robertmartin8 / PyPortfolioOpt

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

Feature request: Using efficient frontier on multiple expected returns #159

Closed linda390 closed 4 years ago

linda390 commented 4 years ago

Is your feature request related to a problem? Please describe.

Describe the solution you'd like For the same portfolio, I have computed expected returns using two different methods. I would like to be able to receive portfolio weights where the risk-adjusted return is maximized when using the expected returns from the first method, and then add a constraint so that these weights also result in the risk-adjusted returned from the second method being above a lower bound.

Example:

For a portfolio, I computed expected returns of X using exponentially-weighted means method.

For the same portfolio, I computed expected returns of Y using an alternative method.

I can maximize the return for X given a target volatility using:

ef = EfficientFrontier(X, S)
ef.efficient_risk(target_volatility=0.15)

When I apply these weights, I want to make sure that the risk-adjusted return for the portfolio using Y would be above 10%.

Describe alternatives you've considered The only way I can think of doing this is via Excel where the constraint options in the Solver are flexible, and works perfectly.

Cell A1: I compute the Risk-adjusted return using expected returns X as: =SUMPRODUCT([Portfolio weights],[expected returns X]) + [risk-free rate]*[risk-free weight]

Cell A2: I calculate the Risk-adjusted return using expected returns Y through the same formula as above, just replacing X with Y for the expected returns.

I then set the objective in the Solver tool as A1 and then add a constraint so that Cell A2 is >= 10%.

Was wondering if there would be a way to do this via pyportfolioopt.

Additional context This can be very helpful in cases where you are also trying to protect your downside risk. i.e. consider a case where the alternative method you used to compute the expected returns is the worst observed annual return over the last 3 years. While you want to maximize your risk-adjusted return using your regular expected returns method (ema, james-stein, etc.), you also want to ensure that the weights returned will also maximize the minimum expected returns.

robertmartin8 commented 4 years ago

Hi @linda390,

Thanks for reaching out! I think what you are describing is very possible except for one key thing: if you want to use the convex optimiser (which is more robust), you cannot constrain the risk-adjusted return, only the return.

In this example, we maximise the Sharpe ratio for a portfolio with expected returns mu, subject to a constraint where the expected returns using mu_other is greater than 10%.

ef = EfficientFrontier(mu, S)
ef.add_constraint(lambda w: w @ mu_other >= 0.1)
ef.max_sharpe()

If risk-adjusted returns is a must, then it is possible to do this with PyPortfolioOpt's nonconvex_objective functionality.

Hope that helps! Robert

linda390 commented 4 years ago

This worked out great!

Thank you for the excellent work you have done on this module.