## Task

Generate random portfolios with restrictions on volatility or tracking error.

## Preparation

This presumes that you can do basic random portfolio generation. For example, that you have mastered “Very simple long-only”.

- Portfolio Probe

You need to have the Portfolio Probe package loaded into your R session:

require(PortfolioProbe)

If you don’t have Portfolio Probe, see “Demo or Buy”.

### Doing the example

- The objects:
`priceVector`

,`grossVal`

,`curPortfol`

that are defined in several examples, such as in “Passive, no benchmark (minimum variance)” `xaLWvar06`

variance matrix from “Returns to variance matrix” example`xaLWvar06EqWt`

variance matrix from “Add benchmark to variance matrix” example`pprobeData`

package

You need to have the package loaded into your R session:

require(pprobeData)

## Doing it

We generate random portfolios with the following constraints:

- maximum volatility
- volatility within a range
- maximum tracking error
- tracking error within a range

### maximum volatility

We generate 1000 random portfolios with volatility at most 12%:

rpVolMax <- random.portfolio(1000, priceVector, long.only=TRUE, gross=grossVal, variance=xaLWvar06, existing=curPortfol, var.constraint=.12^2/252)

We need to transform the 12% volatility into the scale of our variance matrix, which is daily.

### volatility within a range

To impose a range on volatility, you need to give a two-column matrix as the `var.constraint`

argument. Here we constrain the volatility to be between 11.9% and 12%:

rpVolRange <- random.portfolio(1000, priceVector, long.only=TRUE, gross=grossVal, variance=xaLWvar06, existing=curPortfol, var.constraint=rbind(c(.119, .12)^2/252))

The value given to `var.constraint`

looks like:

> rbind(c(.119, .12)^2/252) [,1] [,2] [1,] 5.619444e-05 5.714286e-05

You could get the same thing with:

> t(as.matrix(c(.119, .12)^2/252)) [,1] [,2] [1,] 5.619444e-05 5.714286e-05

### maximum tracking error

Tracking error is constrained with the `bench.constraint`

argument. But this argument is on the variance scale — that is, some scaling of the squared tracking error.

The variance we are using is from daily returns. We want 1000 portfolios that have at most 2% (predicted) tracking error.

rpTEmax <- random.portfolio(1000, priceVector, long.only=TRUE, gross=grossVal, variance=xaLWvar06EqWt, existing=curPortfol, bench.constraint=c(EqWt=.02^2/252))

There must be a name on the value given to `bench.constraint`

so that it knows which asset to use as the benchmark.

### tracking error within a range

We generate 1000 random portfolios with predicted tracking error that is between 3.5% and 4%:

rpTErange <- random.portfolio(1000, priceVector, long.only=TRUE, gross=grossVal, variance=xaLWvar06EqWt, existing=curPortfol, bench.constraint=rbind(EqWt=c(.035, .04)^2/252))

The value given to `bench.constraint`

in this case is a matrix with one named row and two columns:

> rbind(EqWt=c(.035, .04)^2/252) [,1] [,2] EqWt 4.861111e-06 6.349206e-06

## Explanation

The `var.constraint`

argument constrains the variance. If it is given one number, then that is taken to be the maximum value allowed. To specify a range, you give a two-column matrix where the first column gives the minimum allowed, and the second column gives the maximum allowed. (A vector of values would be maximums for multiple variances.)

The `bench.constraint`

argument takes values just like `var.constraint`

except that the value or the row needs to be named with the identifier of the benchmark.

## Further details

It is possible to constrain both volatility and tracking error. Here we constrain volatility to be between 11% and 12% and the tracking error to be 3.5% to 4%:

rpVolTErange <- random.portfolio(1000, priceVector, long.only=TRUE, gross=grossVal, variance=xaLWvar06EqWt, existing=curPortfol, bench.constraint=rbind(EqWt=c(.035, .04)^2/252), var.constraint=rbind(c(.11, .12)^2/252))

Remember that since we are using argument names, the order of the arguments doesn’t matter (except in this case the number of portfolios to generate and the prices).

## Checking your work

#### predicted volatility

We can check that the volatility is really being restricted by collecting the ex-ante variances for the portfolios:

volCheck <- sqrt(252 * unlist(randport.eval(rpVolMax, keep='var.values')))

The `volCheck`

object holds the predicted volatility for each portfolio. The `randport.eval`

function gets the answer that the optimizer would have if it arrived at the random portfolio. You then have the option to keep only some components of the answer (or to apply a function to it). In this case we are keeping only the predicted variances.

We can look at the achieved volatilities:

> summary(volCheck) Min. 1st Qu. Median Mean 3rd Qu. Max. 0.08973 0.11150 0.11610 0.11430 0.11880 0.12000 > tail(sort(volCheck)) var.values.V0 var.values.V0 var.values.V0 0.1199847 0.1199902 0.1199902 var.values.V0 var.values.V0 var.values.V0 0.1199926 0.1199931 0.1199993

This exercise would be slightly more complicated for the portfolios that constrain tracking error because in that case there are two values in the `var.values`

component: the portfolio variance and the variance relative to the benchmark.

#### realized volatility

We can use the moves in “Returns and realized volatility” to get the realized volatility for the subsequent year and then plot the distribution.

retVolMax07 <- valuation(rpVolMax, xassetPrices[251:502,], returns="log") volVolMax07 <- apply(retVolMax07, 2, sd) * sqrt(252) * 100 plot(density(volVolMax07)) # essentially Figure 1

Figure 1: Volatility realized in 2007 for the `rpVolMax`

portfolios.

The realized volatility for all of the portfolios is significantly bigger than 12%. However, that need not mean we have done anything wrong because 2007 is when volatility started to heat up. We can look at the realized volatility in the first half of 2007 when volatility was still low.

retVolMax07H1 <- valuation(rpVolMax, xassetPrices[251:376,], returns="log") volVolMax07H1 <- apply(retVolMax07H1, 2, sd) * sqrt(252) * 100

Figure 2: Volatility realized in H1 of 2007 for the `rpVolMax`

portfolios. This is a more reassuring picture.

## Troubleshooting

- Are you giving
`var.constraint`

or`bench.constraint`

a value (or values) that correspond to the variance matrix that you are using? Is the variance for returns or percent returns? What is the time frame of the returns?

- If you are wanting a range for the volatility or tracking error, are you giving a two-column matrix?

## See also

## Navigate

- Back to “Random Portfolio Generation”
- Back to the top level of “Portfolio Probe Cookbook”