Overview
Markowitz's famous paper on portolio optimization hypothesized that investors would seek to maximize the expected return of a portfolio for a given level of portfolio variance.Problem Definition
The following discussion follows that found in Luenberger,The objective of mean variance optimization is to minimize the portfolio return variance
{% \frac{1}{2} \vec{w}^T \Sigma \vec{w} %}
Subject to the portfolio mean return equal to a given target
{% \vec{w}^T \vec{r} = \bar{r} %}
where
{% \sum w_i = 1 %}
- {% \bar{r} %} - is a target return
- {% \vec{w} %} be the vector of portfolio weights
- {% r %} is a vector of forecasted asset returns
- {% \Sigma %} is the asset covariance matrix
Solution
The optimal portfolio weights can be solved with a Langrange multiplier approach, with two Lagrange multipliers {% \lambda %} and {% \mu %}.
{% \Sigma \vec{w} -\lambda \bar{r} - \mu = 0 %}
{% \vec{w}^T \vec{r} = \bar{r} %}
{% \sum w_i = 1 %}
where
- {% \Sigma %} is the covariance matrix
- {% \vec{w} %} is the weights vector
- {% \bar{r} %} is target return
- {% \vec{r} %} is a vector of forecasted returns
Stated in matrix form:
{%
\begin{bmatrix}
\Sigma & \vec{r} & \vec{1} \\
\vec{r}^t & 0 & 0\\
\vec{1}^t & 0 & 0 \\
\end{bmatrix}
\times
\begin{bmatrix}
\vec{w} \\
\lambda \\
\mu \\
\end{bmatrix}
=
\begin{bmatrix}
\vec{0} \\
\bar{r} \\
1 \\
\end{bmatrix}
%}
(see Luenberger)
Topics
- Efficient Frontier - a graph of the portfolios that are efficient in a mean variance sense.
Implementation
The following implements the algorithm given above as a function.
'''
r is a column vector of forecasted returns
covariance is an numpy matrix of covariances
target is the target return
'''
def mean_variance(r, covariance, target):
rows = covariance.shape[0]
covar = covariance.tolist()
r2 = r.tolist()
zeros = [0.0 for x in range(rows)]
v =[
[p]
for p in [*zeros, target, 1]
]
m = []
for index in range(rows):
row = covar[index]
nrow = [*row]
nrow.append(-1*r[index])
nrow.append(-1)
m.append(nrow)
pass
m.append([*r2, 0.0,0.0])
m.append([*[
1 for p in r2
], 0.0,0.0])
inv = np.linalg.inv(m)
result = [p[0] for p in (inv @ v).tolist()]
result.pop()
result.pop()
return np.array([
[p] for p in result
])
Then the function can be used as in the follows:
import numpy as np
import lib.trading.portfolio as pt
f = np.array([0.01,0.012, 0.013])
w = pt.mean_variance(f,sigma, target)