CVXBOOK extra exercise 13.3

Simple portfolio optimization. Solution by Chris Dembia.


In [1]:
from cvxpy import *
from simple_portfolio_data import *
one = np.matrix(np.ones((n, 1)))

Part a


In [2]:
r_min = pbar.T * x_unif
risk_unif = quad_form(x_unif, S).value
print('Minimum return: {}'.format(r_min))


Minimum return: [[ 0.08399391]]

In [3]:
x = Variable(n)
objective_a = Minimize( quad_form(x, S) )

No (additional) constraints


In [4]:
constraints_i = [pbar.T * x == r_min, sum(x) == 1]
problem_ai = Problem(objective_a, constraints_i)
risk_ai = problem_ai.solve()

Long-only


In [5]:
constraints_ii = [pbar.T * x == r_min, sum(x) == 1, x >= 0]
problem_aii = Problem(objective_a, constraints_ii)
risk_aii = problem_aii.solve()

Total short


In [6]:
constraints_iii = [pbar.T * x == r_min, sum(x) == 1,
                   one.T * max(-x, 0) <= 0.5]
problem_aiii = Problem(objective_a, constraints_iii)
risk_aiii = problem_aiii.solve()

In [7]:
print('Uniform portfolio risk: {}'.format(risk_unif))
print('No additional constraints risk: {}'.format(risk_ai))
print('Long-only risk: {}'.format(risk_aii))
print('Total short: {}'.format(risk_aiii))


Uniform portfolio risk: 0.00500978688334
No additional constraints risk: 6.56715701762e-05
Long-only risk: 0.00101937807592
Total short: 6.56717792366e-05

Part b


In [8]:
N = 20
mus = np.logspace(0, 5, N)
mean_longonly = np.zeros(N)
std_longonly = np.zeros(N)
mean_totalshort = np.zeros(N)
std_totalshort = np.zeros(N)
constraints_longonly = [sum(x) == 1, x >= 0]
constraints_totalshort = [sum(x) == 1, one.T * max(-x, 0) <= 0.5]
for i, mu in enumerate(mus):
    print('mu = {}'.format(mu))
    
    ret = pbar.T * x
    risk = quad_form(x, S)
    
    objective = Minimize( -ret + mu * risk )
    
    # Long-only.
    Problem(objective, constraints_longonly).solve()
    mean_longonly[i] = ret.value
    std_longonly[i] = np.sqrt(risk.value)
    
    # Total short.
    Problem(objective, constraints_totalshort).solve()
    mean_totalshort[i] = ret.value
    std_totalshort[i] = np.sqrt(risk.value)


mu = 1.0
mu = 1.83298071083
mu = 3.35981828628
mu = 6.15848211066
mu = 11.2883789168
mu = 20.6913808111
mu = 37.9269019073
mu = 69.5192796178
mu = 127.42749857
mu = 233.572146909
mu = 428.133239872
mu = 784.759970351
mu = 1438.44988829
mu = 2636.65089873
mu = 4832.93023857
mu = 8858.6679041
mu = 16237.7673919
mu = 29763.5144163
mu = 54555.9478117
mu = 100000.0

In [9]:
pl.plot(std_longonly, mean_longonly, label='long-only')
pl.plot(std_totalshort, mean_totalshort, label='total short')
pl.xlabel('standard deviation of return')
pl.ylabel('mean return')
pl.legend(loc='lower right', frameon=False);