Mean Variance Portfolio

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)