Passive, no benchmark (minimum variance)

Task

Optimize the trade to get the minimum variance portfolio given some simple constraints.

Preparation

  • vector of asset prices
  • variance matrix for the assets
  • current portfolio (if it exists)
  • Portfolio Probe

You need the prices at which assets trade and a variance matrix of the asset returns.

The holdings of the current portfolio need to be in a vector with names that are the asset identifiers.

You also 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

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

require(pprobeData)

Doing it

The inputs we need in order to get our minimum variance portfolio are:

  • vector of prices at which the assets may be traded
  • variance matrix of the asset returns
  • desired value of the new portfolio
  • appropriate constraints
  • current portfolio (optional)

prices

We start by naming the vector of prices that we want to use:

priceVector <- xassetPrices[251,]

These are the prices at the close of the last trading day of 2006.  The first few values are:

> head(priceVector)
 XA101  XA103  XA105  XA107  XA108  XA111 
 33.56  72.25  74.39 192.06   5.91  15.98

The requirement for the prices is that it be a vector of positive numbers with names (that are the asset identifiers).

current portfolio

We create an object to serve as the current portfolio:

curPortfol <- (1:10) * 1000
names(curPortfol) <- colnames(xassetPrices)[1:10]

What is expected is a numeric vector of the number of units of each asset in the portfolio.  The names of the vector are the identifiers of the assets that are used in the price vector and the variance matrix.

> curPortfol
XA101 XA103 XA105 XA107 XA108 XA111 XA113 XA115 
 1000  2000  3000  4000  5000  6000  7000  8000 
XA120 XA126 
 9000 10000

portfolio value

The value of the portfolio that we should specify is the current value of the existing portfolio adjusted by whatever cash flow is desired.  Here we assume we want to add $20,000 to the portfolio:

cashFlow <- 20000
grossVal <- as.numeric(valuation(curPortfol, 
   priceVector, collapse=TRUE)) + cashFlow

We get the value of the current portfolio assuming the prices we are using and then add the cash flow.  (The as.numeric is merely for cosmetic reasons to make the result simpler.)  We end up with:

> grossVal
[1] 3033430

The gross value of the portfolio that we want is slightly more than $3 million.

Optimization

We’re now ready to do an optimization.  The only constraint that we impose besides the gross value and being long-only is that no more than 10 assets may be in the portfolio.

opMinVar <- trade.optimizer(priceVector, variance=xaLWvar06, 
   existing=curPortfol, gross=grossVal, long.only=TRUE, 
   port.size=10, utility="minimum var")

We specify the utility to be minimum variance.  We still would have got the same thing without the specification, but there would have been a warning that it was guessing what utility we wanted.

print result

The resulting object is printed like:

> opMinVar
$new.portfolio
XA105 XA280 XA298 XA643 XA675 XA709 XA731 XA778 
 2659 17920  2906 20192  7182  6485  4166  6840 
XA891 XA966 
 5200  6247 

$trade
 XA101  XA103  XA105  XA107  XA108  XA111  XA113 
 -1000  -2000   -341  -4000  -5000  -6000  -7000 
 XA115  XA120  XA126  XA280  XA298  XA643  XA675 
 -8000  -9000 -10000  17920   2906  20192   7182 
 XA709  XA731  XA778  XA891  XA966 
  6485   4166   6840   5200   6247 

$results
   objective      negutil         cost 
1.654167e-05 1.654167e-05 0.000000e+00 
     penalty 
0.000000e+00 

$converged
[1] TRUE

$objective.utility
[1] "minimum variance"

$alpha.values
[1] NA

$var.values
          V0 
1.654167e-05 

$utility.values
[1] 1.654167e-05

$existing
XA101 XA103 XA105 XA107 XA108 XA111 XA113 XA115 
 1000  2000  3000  4000  5000  6000  7000  8000 
XA120 XA126 
 9000 10000 

$violated
NULL

$timestamp
[1] "Wed Sep 05 19:54:08 2012"
[2] "Wed Sep 05 19:54:11 2012"

$call
trade.optimizer(prices = priceVector, variance = xaLWvar06, existing = curPortfol, 
    gross = grossVal, long.only = TRUE, port.size = 10, utility = "minimum var")

The first two components are the new (optimal) portfolio and the trade to achieve that.  There are some additional components to the object that are not shown.

Explanation

The trade.optimizer function does the optimization.  Its first argument is the asset prices.

It is mandatory that the value of the resulting portfolio be specified.  For long-only portfolios it is sufficient to state the desired gross value.  The actual value of the portfolio will (usually) be slightly less than the specification:

> format(grossVal, nsmall=2, big.mark=",")
[1] "3,033,430.00"
> grossVal - as.numeric(valuation(opMinVar, collapse=TRUE))
[1] 96.69

One component of the output to pay special attention to is ‘violated‘ — this states which constraints, if any, are violated.  You want this to be NULL.

It is probably not important whether ‘converged‘ is TRUE or FALSE.  The optimization is likely to be good enough with or without convergence.

Further Details

You can see more about the optimization with the summary of the object:

> summary(opMinVar)
$results
   objective      negutil         cost 
1.654167e-05 1.654167e-05 0.000000e+00 
     penalty 
0.000000e+00 

$objective.utility
[1] "minimum variance"

$alpha.values
[1] NA

$var.values
          V0 
1.654167e-05 

$number.of.assets
         existing             trade 
               10                19 
              new              open 
               10                 9 
            close    universe.total 
                9               350 
         tradable   select.universe 
              350               350 
positions.notrade 
                0 

$opening.positions
[1] "XA280" "XA298" "XA643" "XA675" "XA709"
[6] "XA731" "XA778" "XA891" "XA966"

$closing.positions
[1] "XA101" "XA103" "XA107" "XA108" "XA111"
[6] "XA113" "XA115" "XA120" "XA126"

$value.limits
        lower   upper
gross 3033127 3033430
net   3033127 3033430
long  3033127 3033430
short       0       0

$valuation.new.portfolio
  gross     net    long   short 
3033333 3033333 3033333       0 

$valuation.trade
     gross        net       long      short 
5651157.29   19903.31 2835530.30 2815626.99 

$valuation.trade.fraction.of.gross
      gross         net        long       short 
1.863018901 0.006561531 0.934790216 0.928228685

This has some pieces that are also in the print method, but new information as well.  We see that virtually all of the current portfolio was sold off — a trade to make the broker happy.

Troubleshooting

  • The variance matrix needs to contain all of the assets that are in the price vector.  It can have additional assets — except for benchmarks, these will be ignored.  The order of the assets in the variance does not matter.
  • All of the prices need to be in the same currency.  You have to check that — the code has no way of knowing.
  • It will still work if the object given as the prices is a one-column or one-row matrix.  But it will complain about other matrices.

See also

Navigate