Computing the global minimum-variance portfolio
This tutorial appeared originally on the COMISEF Wiki.
1 The problem
The global minimum-variance (MV) portfolio is the leftmost point of the mean–variance efficient frontier. It is found by choosing portfolio weights that minimise overall variance subject only to the constraint that the sum of the weights \(w\) is one. Formally,
\begin{equation} \min_{w}\ \ w' \Sigma w\\ w'\iota = 1 \end{equation}where \(w\) is the vector of portfolio weights, \(\Sigma\) is the variance-covariance matrix of the assets, and \(\iota\) is an appropriately-sized vector of ones. We do not put any further constraints on the problem; short sales, in particular, are allowed here.
As an example dataset, we create artificial returns with mean zero
(the default with rnorm
) and volatility 5%. (This order of magnitude
would be reasonable for monthly equity returns.) These returns are
stored in a matrix mData
.
nO <- 100L ## number of observations nA <- 10L ## number of assets mData <- array(rnorm(nO * nA, sd = 0.05), dim = c(nO, nA))
2 A quadratic-programming solution
We first use the solve.QP
function of package quadprog
(see the
references below), so we load/attach the package.
library("quadprog")
The aim will be to minimise w %*% cov(mData) %*% w
, subject to the
constraint that sum(w)
equals one.
aMat <- array(1, dim = c(1,nA)) bVec <- 1 zeros <- array(0, dim = c(nA,1)) solQP <- solve.QP(cov(mData), zeros, t(aMat), bVec, meq = 1) solQP$solution
[1] 0.07853404 0.12853164 0.14526751 0.09211099 0.11893845 [6] 0.15176486 0.12447023 0.02945822 0.06584904 0.06507502
The quadprod
package will minimise \(\frac{1}{2} w' \Sigma w\), i.e.
one-half of the portfolio variance (see ?solve.QP
). Hence the
returned minimum-value will be one-half of the portfolio's
variance. Check:
all.equal(drop(var(mData %*% solQP$solution)), ## the solution, evaluated at the data 2*solQP$value) ## the solution's objective fun value times 2
[1] TRUE
This computation is also included as function minvar
in the NMOF
package.
require("NMOF") minvar(cov(mData), wmin = -Inf, wmax = Inf)
[1] 0.07853404 0.12853164 0.14526751 0.09211099 0.11893845 [6] 0.15176486 0.12447023 0.02945822 0.06584904 0.06507502 attr(,"variance") [1] 0.0002269999
Note that NMOF's minvar also returns the portfolio variance.
drop(var(mData %*% solQP$solution))
[1] 0.0002269999
3 A regression solution
The problem can also be solved as a linear regression; see Kempf and Memmel (2006). The authors show that regressing the negative excess returns of \(r_{\mathrm{n_A}} - 1\) assets on the returns of the remaining asset results in coefficients that equal the \(r_{\mathrm{n_A}} - 1\) respective portfolio weights; the remaining asset's weight is determined by the budget constraint. (Excess return here means with respect to the remaining asset.)
We run the regression
\begin{equation} r_{\mathrm{n_A}} = \alpha + w_1 (r_{\mathrm{n_A}} - r_1) + w_2 (r_{\mathrm{n_A}} - r_2) + \cdots + w_{\mathrm{n_A}-1}(r_{\mathrm{n_A}}-r_{\mathrm{n_A}-1}) + \epsilon\,, \end{equation}in which \(r_i\) are the returns of the i-th asset, and \(\epsilon\) are the errors.
From this equation, we directly obtain the weights \(w_1\) to \(w_{\mathrm{n_A}-1}\). Since the weights need to sum to unity, we have
\begin{equation} w_{\mathrm{n_A}} = 1 - \sum_{i=1}^{\mathrm{n_A}-1} w_i\,. \end{equation}Furthermore, the resulting portfolio's mean return will equal \(\alpha\) (the constant in the regression), and the portfolio's variance will equal the variance of the residuals.
## choose 1st asset as regressand y <- mData[ , 1L] ## compute minus excess returns X <- mData[ , 1L] - mData[ , 2:nA] ## run regression solR <- lm(y ~ X)
The results should be the same as the results from quadprog
:
cat("weights from qp\n") as.vector(solQP$solution) cat("\nweights from regression\n") as.vector(c(1 - sum(coef(solR)[-1L]), coef(solR)[-1L])) cat("\ncheck: variance of portfolio same as variance of residuals?\n") all.equal(as.numeric(var(mData %*% solQP$solution)), var(solR$residuals))
weights from qp [1] 0.07853404 0.12853164 0.14526751 0.09211099 0.11893845 [6] 0.15176486 0.12447023 0.02945822 0.06584904 0.06507502 weights from regression [1] 0.07853404 0.12853164 0.14526751 0.09211099 0.11893845 [6] 0.15176486 0.12447023 0.02945822 0.06584904 0.06507502 check: variance of portfolio same as variance of residuals? [1] TRUE
4 Solving a system of linear equations
The weights can also be found by solving a system of linear equations.
x <- solve(cov(mData), numeric(nA) + 1) x <- x / sum(x) ## rescale so that sum(w) is 1 x
[1] 0.07853404 0.12853164 0.14526751 0.09211099 0.11893845 [6] 0.15176486 0.12447023 0.02945822 0.06584904 0.06507502
5 References
- Gilli, M., Maringer, D., Schumann, E. (2011) . Numerical Methods and Optimization in Finance. Elsevier/Academic Press. http://nmof.net
- Kempf, A. and C. Memmel (2006). Estimating the Global Minimum Variance Portfolio. Schmalenbach Business Review 58, 332-348.
- R Development Core Team (2008). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing. http://www.r-project.org.
- Turlach, B.A. [S original] and A. Weingessel [R port] (2007). quadprog: Functions to solve Quadratic Programming Problems. R package version 1.4-11. available from CRAN.