In [2]:
import numpy as np
from scipy.optimize import minimize
In [3]:
C = np.array([[8, -2, 4], [-2, 2, -2],[4,-2,8]])/1000 # C is the covariance array (analogous to V)
R = np.array([.06, .02, .04]) # R is a return array (analogous to muvec)
W = np.ones([len(R)])/len(R) # W is the weight array (analogous to X): starts with equal weighting
rf = .01
In [4]:
def mu_port(W, R): # Calculates the portfolio return
return np.dot(R, W)
def var_port(W, C): # Calculates the portfolio variance (not the SD)
return np.dot(W, np.dot(C, W))
In [5]:
Mu = mu_port(W, R)
Var = var_port(W, C)
print("Equal weights are: {}".format(W))
print("Return with Equal weights is: {:.2%} with volatility of: {:.2%}".format(Mu, np.sqrt(Var)))
In [6]:
def min_var_optimize(W, C, rf): # takes W and C (doesn't use rf) and returns a new
def mvp(W, C, rf): # vector of optimum weights
return var_port(W, C)
W = np.ones([len(R)])/len(R)
b_ = [(0., 1.) for i in range(len(R))] # weights between 0 and 100%, no shorts
c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) # weights must add to 100%
res = minimize(mvp, W, (C, rf), method='SLSQP', constraints=c_, bounds=b_) # the magic scipy function! (look it up for more info)
if not res.success:
raise BaseException(res.message)
return res.x
In [7]:
minvar_W = min_var_optimize(W, C, rf)
print("Min Var weights are: {} (sum: {:.2f})".format(minvar_W, minvar_W.sum()))
print("Min Var Portfolio return is: {:.2%} with a volatility of: {:.2%}".format(mu_port(minvar_W, R), np.sqrt(var_port(minvar_W, C))))
In [8]:
def tangent_optimize(W, C, rf):
def Sharpe(W, C, rf):
mean, var = mu_port(W, R), var_port(W, C)
util = (mean - rf) / np.sqrt(var) # calculates the Sharpe Ratio
return 1/util # maximize utility, minimize the function so we can use the minimize function
W = np.ones([len(R)])/len(R) # start with equal weights if not already set (not necessary)
b_ = [(0., 1.) for i in range(len(R))] # weights between 0 and 100%, no shorts
c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) # weights must add to 100%
res = minimize(Sharpe, W, (C, rf), method='SLSQP', constraints=c_, bounds=b_) # the magic scipy function! (look it up for more info)
if not res.success:
raise BaseException(res.message)
return res.x
In [9]:
Sharpe_W = tangent_optimize(W, C, rf)
print("Sharpe Optimal weights are: {} (sum: {:.2f})".format(Sharpe_W, Sharpe_W.sum())) # close to empirical solution but not exact
print("Sharpe Optimal Portfolio return is: {:.2%} with a volatility of: {:.2%}".format(mu_port(Sharpe_W, R), np.sqrt(var_port(Sharpe_W, C))))
In [10]:
Sharpe_ratio = (mu_port(Sharpe_W, R) - rf) / np.sqrt(var_port(Sharpe_W, C))
print("Sharpe ratio is: {:.2}".format(Sharpe_ratio))
In [11]:
Q7_return = rf + Sharpe_ratio*.05
print("Expected return for a volatility of 5% is: {:.2%}".format(Q7_return))
In [ ]: