robertmartin8 / PyPortfolioOpt

Financial portfolio optimisation in python, including classical efficient frontier, Black-Litterman, Hierarchical Risk Parity
https://pyportfolioopt.readthedocs.io/
MIT License
4.26k stars 929 forks source link

.max_sharpe() gives OptimizationError #458

Closed KrabMads closed 1 year ago

KrabMads commented 2 years ago

Hi,

I'm receiving an error message, when using the .max_sharpe() function, but the min_volatility() works fine.

I have the following code:

end = date.today()
end_string = end.strftime("%Y-%m-%d") start = end - timedelta(days=100) start_string = start.strftime("%Y-%m-%d")

assets = ['BTC-USD', 'ETH-USD', 'ADA-USD', 'AAVE-USD','MKR-USD','HBTC-USD'] assets.sort() data = yf.download(assets, start=start_string, end=end_string) data = data.loc[:,('Adj Close', slice(None))]

Y = data.pct_change().dropna()

mu = expected_returns.mean_historical_return(data) S = risk_models.exp_cov(data)

eb = EfficientFrontier(mu, S) weights = eb.max_sharpe()

Error message: OptimizationError Traceback (most recent call last) in () 1 eb = EfficientFrontier(mu, S) ----> 2 weights = eb.max_sharpe()

1 frames /usr/local/lib/python3.7/dist-packages/pypfopt/base_optimizer.py in _solve_cvxpy_opt_problem(self) 299 if self._opt.status not in {"optimal", "optimal_inaccurate"}: 300 raise exceptions.OptimizationError( --> 301 "Solver status: {}".format(self._opt.status) 302 ) 303 self.weights = self._w.value.round(16) + 0.0 # +0.0 removes signed zero

OptimizationError: ('Please check your objectives/constraints or use a different solver.', 'Solver status: infeasible')

Using Google Collab:

robertmartin8 commented 2 years ago

Possibly caused by infinities in your returns data. Or maybe HBTC and BTC are similar enough to blow up the linear algebra?

KrabMads commented 2 years ago

Thank you for the suggestions. Indeed HBTC and BTC are near identical, I have changed it with another independent asset.

I have plotted the returns in the attached image, and the highest value is 0.3 => 30%

image

Link to code: https://colab.research.google.com/drive/1chXzDiiRzPYY-CihJxDuBM23l3haxvtc?usp=sharing

robertmartin8 commented 2 years ago

Thanks for sharing the colab. I've found the problem: all your expected returns are negative!

For max_sharpe to work, at least one of the assets must have a return greater than the risk-free return

I should really add that as a check and raise a warning if max_sharpe is called on such a vector

KrabMads commented 2 years ago

Thank you!

I added an asset with positive expected return, and it works :)

robertmartin8 commented 2 years ago

Glad it worked

I'm gonna leave this open so that I remember to make pypfopt raise a warning in this scenario