Overview
The solution to the optimal growth portfolio is a straightforward application of Lagrange multipliers. The following derivations are states using Linear Algebra to simplify the calculations.Optimal Portfolio with Target Volatility
We solve the problem of finding the portfolio with the highest growth rate, given a chosen portfolio standard deviation.Maximize
{% \vec{w}^T \vec{\mu} - \vec{w}^T \Sigma \vec{w} %}
subject to
{% \vec{w}^T \vec{1} = 1 %}
{% \vec{w}^T \Sigma \vec{w} = \sigma^2 %}
Solution
Introduce Lagrange multipliers {% \lambda %} and {% \gamma %} the Lagrangian is given by
{% L = \vec{w}^T\vec{\mu} - \vec{w}^T \Sigma \vec{w} - \lambda(\vec{w}^T \vec{1} - 1) - \gamma(\vec{w}^T \Sigma \vec{w} - \sigma^2) %}
then we have first order conditions
{% \vec{\mu} - \Sigma \vec{w} - \lambda \vec{1} - 2 \gamma \Sigma \vec{w} = 0 %}
{% \vec{w} = \frac{1}{1+2\gamma} \Sigma ^{-1} (\vec{\mu} - \lambda \vec{1}) %}
The two Lagrange coefficients are set so that the original constraints are satisfied.
(see Luenberger pg 431)
Optimal Portfolio
If {% \gamma %} is set to zero, then the second constraint is ignored and the resulting portfolio is the growth optimal portfolio.
{% \vec{w} = \Sigma ^{-1} (\vec{\mu} - \lambda \vec{1}) %}
To solve, solve for {% \lambda %} using the constraint on weights, and then plug back in
{% [S^{-1}\vec{\mu} - \lambda S^{-1} \vec{1}]^T \vec{1} = 1 %}
{% [\vec{\mu}^T S^{-T} - \lambda \vec{1}^T S^{-T}] \vec{1} = 1 %}
{% \lambda \vec{1}^T S^{-1} \vec{1} = \vec{\mu}^T S^{-T} \vec{1} - 1 %}
{% \lambda = \frac{1}{\vec{1}^T S^{-T}\vec{1}} (\vec{\mu}^T S^{-T}\vec{1}-1) %}
Implementation
def growth_lambda(r, covariance, inv):
rows = covariance.shape[0]
one = np.array([
[1.0]
for x in range(rows)
])
factor1 = r.T @ inv.T @ one
factor2 = one.T @inv.T @ one
result = (1/factor2[0][0]) * (factor1[0][0]-1)
return result
def optimal_growth(r, covariance):
rows = covariance.shape[0]
sigmaInverse = np.linalg.inv(covariance)
r2 = np.array([
[p] for p in r.tolist()
])
lambda1 = growth_lambda(r2, covariance, sigmaInverse)
lambda2 = np.array([
[-1.0 * lambda1]
for x in range(rows)
])
factor = r2+lambda2
result = sigmaInverse @ factor
return result
import numpy as np
import lib.trading.portfolio as pt
sigma = np.array([[0.2,0.05,0.05],[0.05, 0.12, 0.05],[0.05,0.05, 0.15]])
f = np.array([0.10,0.12, 0.13])
w = pt.optimal_growth(f,sigma)