The tangency portfolio is the portfolio that maximises the Sharpe ratio, ie, it is obtained from(1)
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. The vector $\mu$ holds the assets' means, $$r_f$$ is the riskfree rate (assumed to be a constant). There are no further constraints on the problem, in particular, short sales are allowed here.
The optimisation makes sense only if there exists at least ones portfolio for which $\mu'w$ is larger than $r_f$; otherwise, excess return is negative and no one would want to hold risky assets.
Using a QP solver
We use the quadprog package for R (see the references below).
require(quadprog) # create artifical data nO <- 100 # number of observations nA <- 10 # number of assets mData <- array(rnorm(nO * nA, mean = 0.001, sd = 0.01), dim = c(nO, nA)) rf <- 0.0001 # riskfree rate (2.5% pa) mu <- apply(mData, 2, mean) # means mu2 <- mu - rf # excess means # qp aMat <- as.matrix(mu2) bVec <- 1 zeros <- array(0, dim = c(nA,1)) solQP <- solve.QP(cov(mData), zeros, aMat, bVec, meq = 1) # rescale variables to obtain weights w <- as.matrix(solQP$solution/sum(solQP$solution)) # compute sharpe ratio SR <- t(w) %*% mu2 / sqrt(t(w) %*% cov(mData) %*% w)
A regression representation
Britten-Jones  showed that the same results can be obtained by running the following regression(2)
Here $1$ is a vector of ones, $X$ holds in its columns the excess returns of the assets (each row is one observation), and $\varepsilon$ holds the remaining errors.
The obtained regression weights need to be rescaled, ie,(3)
# (...continued) ## # regression # compute excess returns X <- mData - rf ones <- array(1, dim = c(100,1)) # run regression solR <- lm(ones~-1 + X) # rescale w2 <- coef(solR) w2 <- w2/sum(w2)
Solving a system of linear equations
The weights can also be found by solving a system of linear equations.
# (...continued) # solve w3 <- solve(cov(mData),mu2) # rescale w3 <- w3/sum(w3)
All three methods should give the same results:
# (...continued) #qp as.vector(w) # regression as.vector(w2) # linear equations as.vector(w3) # check all.equal(as.vector(w),as.vector(w2)) all.equal(as.vector(w),as.vector(w3)) all.equal(as.vector(w2),as.vector(w3))
|How to compute the global minimum-variance portfolio|
1. Britten-Jones, M. (1999). The Sampling Error in Estimates of Mean-Variance Efficient Portfolio Weights. Journal of Finance 64, 655-671.
2. Gilli, M., D. Maringer and E. Schumann. (2011). Numerical Methods and Optimization in Finance. Elsevier.
3. R Development Core Team (2008). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing. http://www.R-project.org.
4. 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.