All of the examples can be found in Jupyter notebook form here.

Portfolio Optimization

In this problem, we will find the portfolio allocation that minimizes risk while achieving a given expected return $R_\text{target}$.

Suppose that we know the mean returns $\mu \in \mathbf{R}^n$ and the covariance $\Sigma \in \mathbf{R}^{n \times n}$ of the $n$ assets. We would like to find a portfolio allocation $w \in \mathbf{R}^n$, $\sum_i w_i = 1$, minimizing the risk of the portfolio, which we measure as the variance $w^T \Sigma w$ of the portfolio. The requirement that the portfolio allocation achieve the target expected return can be expressed as $w^T \mu >= R_\text{target}$. We suppose further that our portfolio allocation must comply with some lower and upper bounds on the allocation, $w_\text{lower} \leq w \leq w_\text{upper}$.

This problem can be written as

\[\begin{array}{ll} \text{minimize} & w^T \Sigma w \\ \text{subject to} & w^T \mu >= R_\text{target} \\ & \sum_i w_i = 1 \\ & w_\text{lower} \leq w \leq w_\text{upper} \end{array}\]

where $w \in \mathbf{R}^n$ is our optimization variable.

using Convex, SCS

# generate problem data
μ = [11.5; 9.5; 6] / 100          #expected returns
Σ = [
    166 34 58              #covariance matrix
    34 64 4
    58 4 100
] / 100^2

n = length(μ)                   #number of assets

R_target = 0.1
w_lower = 0
w_upper = 0.5;

If you want to try the optimization with more assets, uncomment and run the next cell. It creates a vector or average returns and a variance-covariance matrix that have scales similar to the numbers above.

using Random Random.seed!(123)

n = 15 #number of assets, CHANGE IT?

μ = (6 .+ (11.5-6)*rand(n))/100 #mean A = randn(n,n) Σ = (A * A' + diagm(0=>rand(n)))/500; #covariance matrix

w = Variable(n)
ret = dot(w, μ)
risk = quadform(w, Σ)

p = minimize(risk, ret >= R_target, sum(w) == 1, w_lower <= w, w <= w_upper)

solve!(p, SCS.Optimizer)
------------------------------------------------------------------
	       SCS v3.2.3 - Splitting Conic Solver
	(c) Brendan O'Donoghue, Stanford University, 2012
------------------------------------------------------------------
problem:  variables n: 6, constraints m: 17
cones: 	  z: primal zero / dual free vars: 2
	  l: linear vars: 8
	  q: soc vars: 7, qsize: 2
settings: eps_abs: 1.0e-04, eps_rel: 1.0e-04, eps_infeas: 1.0e-07
	  alpha: 1.50, scale: 1.00e-01, adaptive_scale: 1
	  max_iters: 100000, normalize: 1, rho_x: 1.00e-06
	  acceleration_lookback: 10, acceleration_interval: 10
lin-sys:  sparse-direct-amd-qdldl
	  nnz(A): 27, nnz(P): 0
------------------------------------------------------------------
 iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
------------------------------------------------------------------
     0| 1.71e+01  1.00e+00  1.62e+01 -8.04e+00  1.00e-01  6.27e-05
   100| 8.60e-05  5.21e-05  1.29e-05  6.33e-03  1.00e-01  1.36e-04
------------------------------------------------------------------
status:  solved
timings: total: 1.37e-04s = setup: 4.97e-05s + solve: 8.68e-05s
	 lin-sys: 2.88e-05s, cones: 1.36e-05s, accel: 4.48e-06s
------------------------------------------------------------------
objective = 0.006330
------------------------------------------------------------------

Optimal portfolio weights:

evaluate(w)
3-element Vector{Float64}:
 0.4075330632520431
 0.5000359110432534
 0.09243172401160002
sum(evaluate(w))
1.0000006983068965

This page was generated using Literate.jl.