I am looking to find a way via cvxpy
to optimize a portfolio for Sharpe ratio.
Currently I have the following:
import cvxpy as cvx
import numpy as np
def markowitz_portfolio(means, cov, risk_aversion):
weights = cvx.Variable(len(means))
expected_return = weights.T * means
expected_vol = cvx.quad_form(weights, cov)
utility = expected_return - risk_aversion * expected_vol
objective = cvx.Maximize(utility)
constraints = [
cvx.sum(weights) == 1, # fully-invested
weights >= 0, # long-only
cvx.sum(cvx.abs(weights)) <= 1 # Leverage max.
]
problem = cvx.Problem(objective, constraints)
problem.solve()
return np.array(weights.value.flat).round(4), expected_return.value, expected_vol.value
expected_rets = np.array([0.001, 0.002, -0.003, 0.004, 0.005])
cov = np.array([[0.02, 0. , 0. , 0. , 0. ],
[0. , 0.02, 0. , 0. , 0. ],
[0. , 0. , 0.02, 0. , 0. ],
[0. , 0. , 0. , 0.02, 0.01 ],
[0. , 0. , 0. , 0.01 , 0.07]])
risk_aversion = 0.2
weights, rets, var = markowitz_portfolio(expected_rets, cov, risk_aversion)
This works well, and yields:
Weights: [ 0.1469 0.2719 -0. 0.4625 0.1187]
Expected Return: 0.003134374999055644
Expected Variance: 0.00827343748305239
However if I were to change the utility function to utility = expected_return / expected_vol
I get an error:
DCPError: Problem does not follow DCP rules. Specifically:
The objective is not DCP. Its following subexpressions are not:
var295 * [ 0.001 0.002 -0.003 0.004 0.005] / QuadForm(var295, [[0.02 0. 0. 0. 0. ]
[0. 0.02 0. 0. 0. ]
[0. 0. 0.02 0. 0. ]
[0. 0. 0. 0.02 0.01]
[0. 0. 0. 0.01 0.07]])
I looked this up and understand that my problem is not convex I guess, but I still don't understand why and how to solve it. Any help in direction (if not a solution) would be useful.
I have seen here a Sharpe maximization with from scipy.optimize import minimize
however I struggle to replicate it with cvxpy
.