Kevin Crotty
Strategies so far have been focused on expected returns
We should also think about managing portfolio risk.
We have been equally-weighting portfolios.
Could we reduce portfolio volatility using different weighting schemes?
Today, we’ll focus on GMV.
Mathematically, choose portfolio weights to solve the following constrained optimization problem:
\[ \underset{w_1,w_2,\dots,w_N}{\text{min}} \text{var}[r_{p}] \]
subject to constraints: \(\sum_i w_i=1\)
The function cvxopt.solvers.qp
solves problems of the general form: \[\begin{align}
\underset{w}{\text{min }}& \frac{1}{2} w' Q w + p'w \\
\text{subject to } & Gw \le h \\
& Aw = b \\
\end{align}\]
def gmv(means, cov):
n = len(means)
Q = matrix(cov, tc="d")
p = matrix(np.zeros(n), (n, 1), tc="d")
# Constraint: short-sales allowed
G = matrix(np.zeros((n,n)), tc="d")
h = matrix(np.zeros(n), (n, 1), tc="d")
# Constraint: fully-invested portfolio
A = matrix(np.ones(n), (1, n), tc="d")
b = matrix([1], (1, 1), tc="d")
sol = Solver(Q, p, G, h, A, b)
wgts = np.array(sol["x"]).flatten() if sol["status"] == "optimal" else np.array(n * [np.nan])
return wgts
def gmv_ssc(means, cov):
n = len(mns)
Q = matrix(cov, tc="d")
p = matrix(np.zeros(n), (n, 1), tc="d")
# Constraint: short-sales not allowed
G = matrix(-np.identity(n), tc="d")
h = matrix(np.zeros(n), (n, 1), tc="d")
# Constraint: fully-invested portfolio
A = matrix(np.ones(n), (1, n), tc="d")
b = matrix([1], (1, 1), tc="d")
sol = Solver(Q, p, G, h, A, b)
wgts = np.array(sol["x"]).flatten() if sol["status"] == "optimal" else np.array(n * [np.nan])
return wgts
def constrained_gmv(means, cov, min_wgt, max_wgt):
n = len(means)
Q = matrix(cov, tc="d")
p = matrix(np.zeros(n), (n, 1), tc="d")
# Constraint: minimum and maximum position limits
G = matrix(np.vstack((-np.identity(n), np.identity(n))), tc="d")
h = matrix(np.append(min_wgt*np.ones(n), max_wgt*np.ones(n)), (2*n, 1), tc="d")
# Constraint: fully-invested portfolio
A = matrix(np.ones(n), (1, n), tc="d")
b = matrix([1], (1, 1), tc="d")
sol = Solver(Q, p, G, h, A, b)
wgts = np.array(sol["x"]).flatten() if sol["status"] == "optimal" else np.array(n * [np.nan])
return wgts
Set of expected returns for assets
Set of std deviations (variances) for assets
Set of correlations (covariances) across assets
How good are we at estimating these things?
We’ll use four strategies for input estimation.
Today’s notebooks contain backtests comparing estimation choices and position limit choices for portfolios of