I'm trying to solve the classical Markowitz optimal portfolio problem, but adding multiple constraints on the weights allocation:
- Each asset should have a weight on the interval
[0,10%](long-only strategy); - The vector of weights vector should sum
100%; - For the assets whose weight is greater than
5%, the aggregate sum should not be greater than40%.
This problem can be classified as a Mixed-Integer quadratic program. To solve it, I'm using CVXPY library from Python. The code that I have developed is structured as follows:
- Two continuous-variable vectors
wandw_5, which represent the weights vector for assets whose weight isw <= 5%andw_5 > 5%respectively. - Two boolean-variable vector
dandd_5, to indicate if an asset is in thewvector or in thew_5vector. - In addition, the corresponding variables to solve the classic mean-variance optimization problem (this works without problem if I do not introduce constraint #3)
The code looks like this:
# Expected annualized yield
mu = np.mean(df_yield, axis = 0).values
# Annualized covariance matrix
sigma = df_yield.cov().values
# Number of assets
n = sigma.shape[0]
# Efficient Frontier (Mean-Covariance Optimization) - Parameters
w = cp.Variable(n)
w_5 = cp.Variable(n)
d = cp.Variable(n, boolean = True)
d_5 = cp.Variable(n, boolean = True)
gamma = cp.Parameter(nonneg = True)
ret = mu.T @ w
risk = cp.quad_form(w, sigma)
# Markowitz Efficient Frontier (Mean-Covariance Optimization) - Constraints
eps = 10e-10
constraints = [
# Assets with weight <= 5%
w <= 0.05 * d,
w >= 0,
# Assets with weight > 5%
w_5 <= 0.10 * d_5,
w_5 >= (0.05 + eps) * d_5,
# Total sum thresholds
cp.sum(w) + cp.sum(w_5) == 1,
cp.sum(d) + cp.sum(d_5) == n,
cp.sum(w) >= 0.4,
cp.sum(w_5) <= 0.4,]
# Markowitz Efficient Frontier (Mean-Covariance Optimization) - Problem
prob = cp.Problem(cp.Maximize(ret - gamma * risk), constraints)
# Markowitz Efficient Frontier (Mean-Covariance Optimization) - Simulation
risk_data = np.zeros(n_samples)
ret_data = np.zeros(n_samples)
gamma_vals = np.logspace(gamma_low, gamma_high, num = n_samples)
portfolio_weights = []
for i in range(n_samples):
gamma.value = gamma_vals[i]
prob.solve()
risk_data[i] = np.sqrt(risk.value)
ret_data[i] = ret.value
portfolio_weights.append(w.value)
# Maximum Sharpe Ratio
sharpes = ret_data / risk_data
The resulting output is:
SolverError: Either candidate conic solvers (['GLPK_MI']) do not support the cones output by the problem (SOC, NonNeg, Zero), or there are not enough constraints in the problem.
From this I can infer that I'm missing some additional constraint, but not idea how to solve it. Any guess?