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
xaLWvar06
variance matrix from “Returns to variance matrix” example
pprobeData
package
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
- Back to “Optimize Trades”
- Back to the top level of “Portfolio Probe Cookbook”