robertmartin8 / PyPortfolioOpt

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

Complex Plot Example Code Not Working #305

Closed NDH0014 closed 3 years ago

NDH0014 commented 3 years ago

Describe the bug I was able to successfully run through all of the "Mean-Variance Optimization" cookbook code except for the last portion relating to complex plots, specifically being able to successfully run the code that creates the Efficient Frontier with Random Portfolios plot. I was able to optimize my asset weights based on my preferred constraints however for some reason the complex plots just don't work for me.

I read the documentation and instantiated the efficient frontier (prior to executing the optimization of max Sharpe) so really not sure what is going on. I ran the code exactly as given within the cookbook adjusted for my variables and I get one completely blank ax plot with no simulated portfolios and one ax plot with just the blue efficient frontier line and no simulated portfolios ever being added which is very frustrating. I am so close to getting what I want, but I just can't get this last little piece to work. PLEASE HELP!!!!!!!!!!!

Expected behavior I would expect the code to run as shown in the cookbook as I have not adjusted anything except for variables. Everything run is the same as the cookbook and all other portions of the code ran for me throughout the cookbook. Even the simple efficient frontier CLA plot ran just fine. Just can't get the complex plot to work.

Code sample

#Plotting constrained complex efficient frontier
S = risk_models.exp_cov(prices)
mu = expected_returns.capm_return(prices)
ef = EfficientFrontier(mu, S)  # weight_bounds automatically set to (0, 1)
ef.add_sector_constraints(style_mapper, style_lower, style_upper)

ax = plotting.plot_efficient_frontier(ef, ef_param="risk", 
                                      ef_param_range=np.linspace(0.12, 0.4, 50), 
                                      showfig=False);

#Create 10K simulated portfolios with random weights 
n_samples = 10000
w = np.random.dirichlet(np.ones(len(mu)), n_samples)
rets = w.dot(mu)
stds = np.sqrt(np.diag(w @ S @ w.T))
sharpes = rets / stds

print("Sample portfolio returns:", rets)
print("Sample portfolio volatilities:", stds)

# Plot efficient frontier with Monte Carlo sim
ef = EfficientFrontier(mu, S)
fig, ax = plt.subplots()
plotting.plot_efficient_frontier(ef, ax=ax, show_assets=False)

# Find and plot the tangency portfolio
ef.max_sharpe()
ret_tangent, std_tangent, _ = ef.portfolio_performance()
ax.scatter(std_tangent, ret_tangent, marker="*", s=100, c="r", label="Max Sharpe")

# Plot random portfolios
ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")

# Format
ax.set_title("Efficient Frontier with random portfolios")
ax.legend()
plt.tight_layout()
plt.show()

Operating system, python version, PyPortfolioOpt version Windows 10, python 3.7.9, PyPortfolioOpt 1.3.1

Additional context The above code provided only provides a blank plot and then a second plot with just the efficient frontier and no simulated assets and a label that says efficient frontier.

robertmartin8 commented 3 years ago

@NDH0014 thanks for the detailed bug report.

Are you running the script within a Jupyter notebook, or as a standalone python script.

Also, when you run the script does it print the sample returns/volatilities?

The code works for me (you can verify it by running the Binder notebook "2-Mean-Variance-Optimisation.ipynb".

Best, Robert

NDH0014 commented 3 years ago

Thanks for your quick reply Robert. I am running all of my script in an Spyder IDE environment (4.1.5). I have not had any issues with any other portion of the code (outside of the complex plots). My code does print the sample returns and vols that are all different for the 10K simulated portfolios. I have included the outputs from the charts in the 1st block of code and the 2nd block of code. Also, I added a pic of the output of the sample returns & vols. Really hoping you guys can help me get this working!! 2nd Code Block - 2nd Chart Produced with Efficient Frontier Line Only 2nd Code Block - 1st Blank Chart Produced 2nd Code Block - Printed Random Portfolio Returns   Vols 1st Code Block - 2nd Chart Produced 1st Code Block - 1st Blank Chart Produced

robertmartin8 commented 3 years ago

@NDH0014 can you try executing the entire script in one go (i.e not split over separate inputs).

Screenshot 2021-02-24 at 10 54 49
NDH0014 commented 3 years ago

Hi Robert, I ran the whole script through in one go again (tried this before) and it produces 3 separate plots (see attached). 1 is blank, 1 has just the efficient frontier line and one has the efficient frontier line with the assets as well. Not sure what is going on at all. I wonder if there could be issues with Matplotlib or some other feeder into what produces these plots. Seems like the complex plots are not able to build on top of the earlier ax plots in the upper portion of the code. Any thoughts on something like that?

I absolutely have to get this working so would be up for some type of a quick Zoom call if that would be possible so you might spot something when I walk you through everything or any other ideas that you or other collaborators might have. Thanks so much for all of you efforts on this so far! 1st Code Block - 2nd Chart Produced 2nd Code Block - 1st Blank Chart Produced 2nd Code Block - 2nd Chart Produced with Efficient Frontier Line Only

robertmartin8 commented 3 years ago

Can you try downloading the cookbook recipe and running the jupyter notebook locally?

Also, what happens if you replace the plt.show() with plt.savefig("img.png") and run the script via python script.py (instead of interactively)

robertmartin8 commented 3 years ago

Closing due to inactivity. I don't believe this is a problem with PyPortfolioOpt, more likely to be some weird mix of matplotlib figures, axes, shows etc (and their interaction with ipython).