Fábio Neves
Summary
This article provides a step-by-step guide on how to plot the Markowitz Efficient Frontier using Python, which helps in finding the best portfolio allocation for stocks based on a given level of risk.
Abstract
The article begins by explaining the need to load and normalize data from four companies - Amazon, IBM, Cisco, and Apple. It then proceeds to simulate several different combinations of the four stocks and save their Sharpe ratio. The maximum Sharpe ratio is identified, and the weights in it are used to plot a chart comparing all combinations in terms of volatility (or risk) and return, colored by Sharpe ratio. The red dot in the chart represents the return and volatility for the simulation with the maximum Sharpe ratio. The article then introduces three functions - get_ret_vol_sr, neg_sharpe, and check_sum - which are used to prepare for the minimization process. The minimize function is then used to find the portfolio with the maximum Sharpe ratio. Finally, the article explains how to plot the efficient frontier, which is the set of portfolios that gets us the highest expected return for any given risk level.
Bullet points
- The article begins by loading and normalizing data from four companies - Amazon, IBM, Cisco, and Apple.
- The article then simulates several different combinations of the four stocks and saves their Sharpe ratio.
- The maximum Sharpe ratio is identified, and the weights in it are used to plot a chart comparing all combinations in terms of volatility (or risk) and return, colored by Sharpe ratio.
- The red dot in the chart represents the return and volatility for the simulation with the maximum Sharpe ratio.
- Three functions - get_ret_vol_sr, neg_sharpe, and check_sum - are introduced to prepare for the minimization process.
- The minimize function is used to find the portfolio with the maximum Sharpe ratio.
- The article explains how to plot the efficient frontier, which is the set of portfolios that gets us the highest expected return for any given risk level.
This article is a follow up on the article about calculating the Sharpe Ratio. After knowing how to get the Sharpe ratio, we will simulate over a few thousand possible portfolio allocations, and draw the outcomes in a chart. With this we can easily find out the best allocation for our stocks for any given level of risk we are willing to take.
Like in the previous article, we will need to load our data. I’ll be using four simple files with two columns — a date and closing price. You can use your own data, or find something in Quandl, which is very good for this purpose. We have 4 companies — Amazon, IBM, Cisco, and Apple. Each file is loaded as amzn, ibm, cisco and aapl respectively. The head of aapl is printed below.
We want to merge all prices in a single dataframe called stocks, so here’s a way to do it.
One of the things we need to do with this dataframe is to normalize the data. I’m going to use logarithmic returns, since it’s more convenient and it takes care of the normalization for the rest of the project. Converting everything to logarithmic returns is simple. Think of it as the log of an arithmetic daily return (which is obtained by dividing the price at day n, by the price at day n-1).
Things start to get interesting around this point! We need to prepare a for loop which will simulate several different combinations of the four stocks and save their Sharpe ratio. I’m going to use 6000 portfolios, but feel free to use less if your computer is too slow. The random seed at the top of the code is making sure I get the same random numbers every time for reproducibility.
From here we can get the maximum Sharpe ratio present in the simulation and the row where it occurred, so we can get the weights in it.
So the best portfolio is on index 5451. Let’s check the allocation weights in that index number and save the return and volatility figures to use it in the chart later.
We have everything we need to plot a chart that compares all combinations in terms of volatility (or risk) and return, colored by Sharpe ratio. The red dot is obtained from the previous calculation above and it represents the return and volatility for the simulation with the maximum Sharpe ratio.
We can already see the bullet shape in the chart, which kind of outlines the efficient frontier we will plot later. To get there, we need to define a few more functions. The first function get_ret_vol_sr will return an array with: return, volatility and sharpe ratio from any given set of weights.
The second function neg_sharpe will return the negative Sharpe ratio from some weights (which we will use to minimize later).
The third function check_sum will check the sum of the weights, which has to be 1. It will return 0 (zero) if the sum is 1.
Moving on, we will need to create a variable to include our constraints like the check_sum. We’ll also define an initial guess and specific bounds, to help the minimization be faster and more efficient. Our initial guess will be 25% for each stock (or 0.25), and the bounds will be a tuple (0,1) for each stock, since the weight can range from 0 to 1.
Enter the minimize function. I chose the method ‘SLSQP’ because it’s the method used for most of the generic minimization problems. In case you are wondering, it stands for Sequential Least Squares Programming. Make sure to pass the initial method, the bounds and the constraints with the variables defined above. If we print the variable it will look like this:
We want the key x from the dictionary, which is an array with the weights of the portfolio that has the maximum Sharpe ratio. If we use our function get_ret_vol_sr we get the return, volatility, and sharpe ratio:
So we got a better Sharpe ratio than we got with the simulation we did before (1.0307 as opposed to the previous 1.0287).
We’re now ready to check all optimal portfolios, which is basically our efficient frontier. The efficient frontier is the set of portfolios that gets us the highest expected return for any given risk level. Or from another perspective, the minimum amount of risk for an expected return. To trace this line, we can define a variable frontier_y. Going back to the chart above, we can see the maximum return doesn’t go much higher than 0.3, so frontier_y will be defined from 0 to 0.3.
To finish the plotting of the frontier, we have define one last function that will help us minimize the volatility. It will return the volatility (index 1) of the given weights.
And now the last bit of code to help us get get our x values for the efficient frontier. We use the same code as above with a few changes to the constraints. The for loop is basically going through every possible value in our previously defined frontier_y and obtaining the minimum result (which is the key ‘fun’) of volatility (our x axis in the chart).
Finally, we can plot the actual efficient frontier by passing the variables frontier_x and frontier_y.
These are the steps for a Markowitz portfolio optimization with Python. It gets more interesting when you throw in a few more stocks and go through the results testing for different risk strategies. Of course, this type of analysis is always based in the past, so it cannot be a guarantee of future results. Nonetheless it can give you a good idea of the expected output of a specific strategy.
Feel free to ask any questions or leave a message below! Happy coding!
If you’re into financial analysis with Python, there are two great books that will cover pretty much everything you will need:
- Python for Finance: https://amzn.to/3SE6Mu0
- Financial Theory with Python: https://amzn.to/3SC4Vpq
Disclosure: Some of the links in this article are affiliate links. This means that, at zero cost to you, I will earn an affiliate commission if you finalize your purchase through the link!
Investing
Markowitz
Python
Data Science
Optimization
NTTP
The Volatility of Volatility for Stocks and Crypto, Part 7More run controls, and finally… drift!
7 min read
Luis Fernando PÉREZ ARMAS, Ph.D.
Optimizing Project Schedules: An Expert Approach to the Resource Constrained Project Scheduling…Effective scheduling is a fundamental aspect of project management, significantly impacting the outcome of projects. This article examines…
15 min read
Eryk Lewinson
Portfolio Optimization in Python 101 — PyPortfolioOpt editionLearn how to solve an asset allocation problem in a few lines of code
5 min read
Serdar İlarslan
Value at Risk (VaR) and Its Implementation in PythonValue at Risk (VaR) is a statistical technique used to measure the risk of loss on a specific portfolio of financial assets. This post will…
5 min read