In [1]:
# Generate data for long only portfolio optimization.
srand(9);
n = 10;
mu = abs(randn(n, 1));
Sigma = randn(n, n);
Sigma = Sigma' * Sigma;
In [2]:
# Long only portfolio optimization.
using Convex, SCS, ECOS
set_default_solver(SCSSolver(verbose=0));
w = Variable(n);
ret = sum(mu' * w);
risk = sum(quad_form(w, Sigma));

# Compute trade-off curve.
SAMPLES = 100;
risk_data = zeros(SAMPLES);
ret_data = zeros(SAMPLES);
gamma_vals = logspace(-2, 3, SAMPLES);
for i=1:SAMPLES
    gamma = gamma_vals[i];
    problem = maximize(ret - gamma*risk, [sum(w) == 1, w >= 0]);
    solve!(problem);
    risk_data[i] = sqrt(evaluate(risk));
    ret_data[i] = evaluate(ret);
end
In [3]:
using Gadfly
markers_on = [29, 40];
labels = [@sprintf("γ = %0.2f", gamma_vals[marker]) for marker in markers_on];
plot(
layer(x=[sqrt(Sigma[i,i]) for i=1:n], y=mu,
        Geom.point, Theme(default_color=color("red"))),
layer(x=risk_data, y=ret_data,
        Geom.line, Theme(default_color=color("green"))),
layer(x=risk_data[markers_on], y=ret_data[markers_on], label=labels,
        Geom.point, Geom.label, Theme(default_color=color("blue"))),
Guide.XLabel("Risk"), Guide.YLabel("Return")
)
Out[3]:
Risk -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 8.2 8.4 8.6 8.8 9.0 9.2 9.4 9.6 9.8 10.0 -5 0 5 10 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 γ = 0.26 γ = 0.93 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 -2.0 -1.9 -1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 -2 0 2 4 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 Return
In [4]:
# Plot return distributions for two points on the trade-off curve.
using DataFrames, Distributions
xdata = linspace(-2, 5, 1000);
df = DataFrame(x=xdata,
    y=pdf(Normal(ret_data[markers_on[1]], risk_data[markers_on[1]]), xdata),
    label=@sprintf("γ = %0.2f", gamma_vals[markers_on[1]]));
for i=2:length(markers_on)
    m = markers_on[i];
    df = vcat(df, DataFrame(x=xdata,
                    y=pdf(Normal(ret_data[m], risk_data[m]), xdata),
                    label=@sprintf("γ = %0.2f", gamma_vals[m])));
end
plot(df, x="x", y="y", color="label", Geom.line, Guide.XLabel("Return"), Guide.YLabel("Density"))
Out[4]:
Return -12 -10 -8 -6 -4 -2 0 2 4 6 8 10 12 14 16 -10.0 -9.5 -9.0 -8.5 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 -10 0 10 20 -10.0 -9.5 -9.0 -8.5 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 γ = 0.26 γ = 0.93 label -1.25 -1.00 -0.75 -0.50 -0.25 0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00 2.25 -1.00 -0.95 -0.90 -0.85 -0.80 -0.75 -0.70 -0.65 -0.60 -0.55 -0.50 -0.45 -0.40 -0.35 -0.30 -0.25 -0.20 -0.15 -0.10 -0.05 0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 1.25 1.30 1.35 1.40 1.45 1.50 1.55 1.60 1.65 1.70 1.75 1.80 1.85 1.90 1.95 2.00 -1 0 1 2 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 Density
In [ ]:
# Portfolio optimization with leverage limit.
# Compute trade-off curve for each leverage limit.
L_vals = [1, 2, 4];
SAMPLES = 100;
risk_data = zeros(length(L_vals), SAMPLES);
ret_data = zeros(length(L_vals), SAMPLES);
for k=1:length(L_vals)
    for i=1:SAMPLES
        Lmax = L_vals[k];
        gamma = gamma_vals[i];
        problem = maximize(ret - gamma*risk,[sum(w) == 1, norm(w, 1) <= Lmax]);
        solve!(problem);
        risk_data[k, i] = sqrt(evaluate(risk));
        ret_data[k, i] = evaluate(ret);
    end
end
In [6]:
df = DataFrame(x=vec(risk_data[1,:]), y=vec(ret_data[1,:]), label=@sprintf("Lmax = %d", L_vals[1]));
for i=2:length(L_vals)
    df = vcat(df, DataFrame(x=vec(risk_data[i,:]), y=vec(ret_data[i,:]), label=@sprintf("Lmax = %d", L_vals[i])));
end
plot(df, x="x", y="y", color="label", Geom.line, Guide.XLabel("Return"), Guide.YLabel("Standard deviation"))
Out[6]:
Return -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 8.2 8.4 8.6 8.8 9.0 9.2 9.4 9.6 9.8 10.0 -5 0 5 10 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 Lmax = 1 Lmax = 2 Lmax = 4 label -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 -5 0 5 10 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 Standard deviation
In [7]:
# Portfolio optimization with a leverage limit and a bound on risk.
# Compute solution for different leverage limits.
w_vals = zeros(n, length(L_vals));
for i=1:length(L_vals)
    problem = maximize(ret, [sum(w) == 1, norm(w, 1) <= L_vals[i], risk <= 2]);
    solve!(problem);
    w_vals[:, i] = evaluate(w);
end
In [8]:
# Generate data for factor model.
n = 3000;
m = 50;
mu = abs(randn(n, 1));
Sigma_tilde = randn(m, m);
Sigma_tilde = Sigma_tilde' * Sigma_tilde;
D = diagm(0.9 * rand(n));
F = randn(n, m);
In [9]:
# Factor model portfolio optimization.
w = Variable(n);
f = F' * w;
ret = sum(mu' * w); 
risk = quad_form(f, Sigma_tilde) + quad_form(w, D);


# Solve the factor model problem.
Lmax = 2
gamma = 0.1
factor_problem = maximize(ret - gamma*risk, [sum(w) == 1, norm(w, 1) <= Lmax]);
solve!(factor_problem, ECOSSolver())
ECOS 1.0.5 - (c) A. Domahidi, ETH Zurich & embotech 2012-14. Support: [email protected]

It     pcost         dcost      gap     pres    dres     k/t     mu      step     IR
 0   -7.928e-01   -1.279e+01   +2e+04   3e+01   1e+02   1e+00   3e+00    N/A     4 5 -
 1   -1.139e+01   -1.274e+01   +2e+03   4e+00   1e+01   4e-01   4e-01   0.9899   4 3 4
 2   -7.570e+00   -7.792e+00   +4e+02   6e-01   2e+00   2e-02   7e-02   0.8105   3 3 3
 3   -7.340e+00   -7.529e+00   +4e+02   5e-01   2e+00   2e-02   6e-02   0.2022   4 4 4
 4   -6.937e+00   -7.099e+00   +4e+02   4e-01   1e+00   2e-02   6e-02   0.2089   5 4 5
 5   -6.565e+00   -6.694e+00   +3e+02   3e-01   1e+00   2e-02   5e-02   0.2735   4 4 4
 6   -5.876e+00   -5.948e+00   +2e+02   2e-01   7e-01   1e-02   3e-02   0.5625   5 5 5
 7   -5.533e+00   -5.582e+00   +2e+02   1e-01   4e-01   8e-03   3e-02   0.3618   5 5 5
 8   -5.313e+00   -5.348e+00   +1e+02   1e-01   3e-01   5e-03   2e-02   0.4704   5 5 5
 9   -4.961e+00   -4.975e+00   +5e+01   4e-02   1e-01   2e-03   9e-03   0.7557   5 5 5
10   -4.989e+00   -5.003e+00   +5e+01   4e-02   1e-01   2e-03   8e-03   0.2647   5 5 5
11   -4.857e+00   -4.864e+00   +3e+01   2e-02   6e-02   8e-04   4e-03   0.5682   5 5 5
12   -4.819e+00   -4.824e+00   +2e+01   1e-02   4e-02   5e-04   3e-03   0.5266   5 5 5
13   -4.789e+00   -4.791e+00   +8e+00   5e-03   2e-02   2e-04   1e-03   0.8850   5 5 5
14   -4.774e+00   -4.775e+00   +4e+00   2e-03   8e-03   8e-05   6e-04   0.7023   5 5 5
15   -4.768e+00   -4.768e+00   +2e+00   1e-03   4e-03   4e-05   3e-04   0.6936   5 5 5
16   -4.766e+00   -4.766e+00   +1e+00   6e-04   2e-03   2e-05   2e-04   0.7589   5 5 5
17   -4.765e+00   -4.765e+00   +3e-01   2e-04   6e-04   5e-06   4e-05   0.7661   5 5 5
18   -4.764e+00   -4.764e+00   +2e-02   2e-05   5e-05   5e-07   4e-06   0.9461   5 5 5
19   -4.764e+00   -4.764e+00   +9e-04   6e-07   2e-06   2e-08   2e-07   0.9777   5 5 5
20   -4.764e+00   -4.764e+00   +1e-05   1e-08   3e-08   3e-10   2e-09   0.9845   5 5 5
21   -4.764e+00   -4.764e+00   +3e-07   2e-10   7e-10   6e-12   5e-11   0.9791   5 5 5

OPTIMAL (within feastol=6.7e-10, reltol=6.5e-08, abstol=3.1e-07).
Runtime: 1.193969 seconds.

In [10]:
# Standard portfolio optimization with data from factor model.
risk = quad_form(w, F * Sigma_tilde * F' + D);
problem = maximize(ret - gamma*risk,  [sum(w) == 1, norm(w, 1) <= Lmax]);
In [ ]:
# Warning: This takes a long time.
# solve!(problem, ECOSSolver())