cvxopt
library, as shown in the quantopian blog on portfolio optimizations <br></br> Then, we find the efficient frontier function by using spline interpolation, and finding the tangent line that passes throw rf, as shown in the tutorial about market line from Python for Finance book <br></br>¶import numpy as np
import pandas as pd
import pytz
from datetime import datetime
import matplotlib.pyplot as plt
start = datetime(2011, 1, 1, 0, 0, 0, 0, pytz.utc)
end = datetime(2013, 1, 1, 0, 0, 0, 0, pytz.utc)
data = get_pricing(['IBM', 'GLD', 'XOM', 'AAPL',
'MSFT', 'TLT', 'SHY', 'AA'],
start, end)
data.price.plot(figsize=(8,5))
plt.ylabel('price in $')
prices = data.price
returnsOfStocks = prices.pct_change().dropna()
print(returnsOfStocks);
import cvxopt as opt
from cvxopt import blas, solvers
import scipy.optimize as sco
# Turn off progress printing
solvers.options['show_progress'] = False
return_vec = returnsOfStocks.values.T
print(return_vec);
def rand_weights(n):
''' Produces n random weights that sum to 1 '''
k = np.random.rand(n)
return k / sum(k)
def random_portfolio(returns):
'''
Returns the mean and standard deviation of returns for a random portfolio
'''
p = np.asmatrix(np.mean(returns, axis=1)) * 252
w = np.asmatrix(rand_weights(returns.shape[0]))
C = np.asmatrix(np.cov(returns)) * 252
mu = w * p.T
sigma = np.sqrt(w * C * w.T)
# This recursion reduces outliers to keep plots pretty
if sigma > 2:
return random_portfolio(returns)
return mu, sigma
n_portfolios = 3000
means, stds = np.column_stack([
random_portfolio(return_vec)
for _ in range(n_portfolios)
])
plt.plot(stds, means, 'o', markersize=5)
plt.xlabel('std')
plt.ylabel('mean')
plt.title('Mean and standard deviation of returns of randomly generated portfolios');
plt.show();
def optimal_portfolio(returns):
n = len(returns)
returns = np.asmatrix(returns)
N = 100
mus = [10**(5.0 * t/N - 1.0) for t in range(N)]
# Convert to cvxopt matrices
S = opt.matrix(np.cov(returns)*252)
pbar = opt.matrix(np.mean(returns, axis=1)*252)
# Create constraint matrices
G = -opt.matrix(np.eye(n)) # negative n x n identity matrix
h = opt.matrix(0.0, (n ,1))
A = opt.matrix(1.0, (1, n))
b = opt.matrix(1.0)
# Calculate efficient frontier weights using quadratic programming
portfolios = [solvers.qp(mu*S, -pbar, G, h, A, b)['x']
for mu in mus]
## CALCULATE RISKS AND RETURNS FOR FRONTIER
returns = [blas.dot(pbar, x) for x in portfolios]
risks = [np.sqrt(blas.dot(x, S*x)) for x in portfolios]
return returns, risks
returns, risks = optimal_portfolio(return_vec)
plt.plot(stds, means, 'o')
plt.ylabel('mean')
plt.xlabel('std')
plt.plot(risks, returns, 'y-o');
import scipy.interpolate as sci
def getListOfUniqueWithinPrecision(sortedArray):
ind = 0
currentVal = 0
diffToIgnore = 0.00000001
listOfIndices = [];
for i in range(sortedArray.size):
if(sortedArray[i] - diffToIgnore > currentVal):
listOfIndices.append(i);
currentVal = sortedArray[i];
return listOfIndices;
twoRowsArrayForSorting = np.vstack([returns, risks]).T;
rowsAfterSorting = twoRowsArrayForSorting[twoRowsArrayForSorting[:,0].argsort()].T
returnsSorted = rowsAfterSorting[0,:];
risksSorted = rowsAfterSorting[1,:];
listOfInd = getListOfUniqueWithinPrecision(risksSorted);
print(listOfInd)
risksSorted = risksSorted[listOfInd];
returnsSorted = returnsSorted[listOfInd];
ind = np.argmin(risksSorted)
evols = risksSorted[ind:]
erets = returnsSorted[ind:]
tck = sci.splrep(evols, erets)
def f(x):
''' Efficient frontier function (splines approximation). '''
return sci.splev(x, tck, der=0)
def df(x):
''' First derivative of efficient frontier function. '''
return sci.splev(x, tck, der=1)
def equations(p, rf=0.06):
eq1 = rf - p[0]
eq2 = rf + p[1] * p[2] - f(p[2])
eq3 = p[1] - df(p[2])
return eq1, eq2, eq3
opt = sco.fsolve(equations, [0.06, 0.5, 0.15])
opt
np.round(equations(opt), 5)
plt.figure(figsize=(8, 4))
plt.plot(stds, means, 'o')
# random portfolio composition
plt.plot(evols, erets, 'y', lw=2.0)
# efficient frontier
cx = np.linspace(0.0, 0.2)
plt.plot(cx, opt[0] + opt[1] * cx, lw=1.0)
# capital market line
plt.plot(opt[2], f(opt[2]), 'r*', markersize=11.0)
plt.grid(True)
plt.axhline(0, color='k', ls='--', lw=2.0)
plt.axvline(0, color='k', ls='--', lw=2.0)
plt.xlabel('expected volatility')
plt.ylabel('expected return')