3

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.

Newskooler
  • 3,973
  • 7
  • 46
  • 84
  • Some remarks (from a non-finance-opt-guy): 1) Non-DCP does not imply non-convexity. DCP is a rule-based constructive approach and is not able to express all convex problems (but a large subset). Sometimes, a different formulation is needed. 2) Another SO-user has a [blog-entry](http://yetanothermathprogrammingconsultant.blogspot.com/2016/08/portfolio-optimization-maximize-sharpe.html) and shows a QP-reformulation (easily expressible with cvxpy). There are assumptions needed (which can be checked against using an LP) . – sascha Dec 22 '19 at 20:10
  • (urls exceeding my char-limit of above comment) -> The mathematical basis of this reformulation is explained [here](http://people.stat.sc.edu/sshen/events/backtesting/reference/maximizing%20the%20sharpe%20ratio.pdf) and [here](https://coral.ie.lehigh.edu/~ted/files/ie447/lectures/Lecture9.pdf) – sascha Dec 22 '19 at 20:11
  • 1
    This always depends on what exactly one is striving for. I don't know how troublesome the assumption and it's check is in practice (probably not the matter; easy pre-solve). In general i would prefer convex QP-solvers (or the convex solvers available in cvxpy like ECOS) over the more general NLP-solvers (less robust; probably slower). The CQP-reformulation allows this. cvxpy is a tool for very algebraic (nice to read) descriptions of (a large class of) convex-problems supporting proofs of convexity. In this case, cvxpy offers you a short model and a wrapped convex-solver (math already given). – sascha Dec 22 '19 at 20:17

0 Answers0