Portfolio Optimization Using Monte Carlo Simulation

6 min read

By Mohak Pachisia & Mandeep Kaur

In the previous blog of this series, we saw how to compute the mean and the risk (or standard deviation) of a portfolio containing 'n' number of stocks, each stock 'i ' having a weight of 'wi'.

In this blog, we will examine the process of portfolio optimisation through the reallocation of asset weights. Portfolio optimisation, in this context, refers to constructing an asset allocation that aligns with one of several possible investment objectives.

Conditions of Portfolio Optimization

  1. Portfolio optimization typically seeks to identify an allocation of capital across assets that satisfies one of the following conditions:
  2. Maximum Sharpe Ratio Portfolio (Tangency Portfolio): A portfolio that maximizes the return-to-risk ratio, formally defined as the Sharpe ratio, which is the excess return over the risk-free rate per unit of risk.
  3. Minimum Variance Portfolio: A portfolio that achieves the lowest possible risk (as measured by portfolio variance or standard deviation) for a given level of expected return.Maximum Return Portfolio at a Given Risk: A portfolio that delivers the highest expected return for a specified level of risk.

Annual Returns and Standard Deviation

This article utilizes annualised returns and annualised standard deviation, based on one year of stock data (2024). However, in practical applications, annualised returns and annualised standard deviation could also be employed. The conversion from daily to annual figures is performed using the standard formulas, assuming 252 trading days in a calendar year:

Annualised Returns = Mean of daily return* 252

Annualised Standard Deviation = Daily Standard Deviation* sqrt(252)

Let us consider a portfolio consisting of four stocks in banking/financial services sector, namely: Bank of America (BAC), Goldman Sachs (GS), JP Morgan Chase & Co (JPM) and Morgan Stanley (MS).

To start with, we’ll assign random weights to all four stocks, keeping the sum of the weights to be 1. We will compute the return and standard deviation of the portfolio as we did in the previous blog and record it. We will then run Monte Carlo Simulations on our portfolio to get the optimal weights for the stocks. We will use python to demonstrate how portfolio optimization can be achieved. Before moving on to the step-by-step process, let us quickly have a look at Monte Carlo Simulation.

Monte Carlo Simulation

This simulation is extensively used in portfolio optimization. In this simulation, we will assign random weights to the stocks. One important point to keep in mind is that the sum of the weights should always sum up to 1. At every particular combination of these weights, we will compute the return and standard deviation of the portfolio and save it. We’ll then change the weights and assign some random values and repeat the above procedure.

The number of iterations depends on the error that the trader is willing to accept. Higher the number of iterations, higher will be the accuracy of the optimization but at the cost of computation and time. For the purpose of this blog, we will restrict ourselves to 10000 such iterations. Out of these 10000 results for returns and corresponding standard deviation, we can then achieve portfolio optimization by identifying a portfolio that satisfies on any of the 3 conditions discussed above.

Portfolio Optimization Process in Python

Let’s start by importing relevant libraries and fetching the data for the stocks for  the year 2024.

The data looks as shown:

                 B_A_C	          G_S	         J_P_M	         M_S
Date

2024-01-02	32.851429	377.245605	166.179565	89.284668
2024-01-03	32.492874	370.920959	165.455276	87.392487
2024-01-04	32.754520	372.047943	166.553253	87.620689
2024-01-05	33.365032	375.438599	167.388885	88.657104
2024-01-08	33.103386	377.789673	167.145996	88.913834

We will then convert these stock prices into returns and will save this under the name ‘stock_ret’.

Output:

We will now calulate the mean return of all stocks and the covariance matrix.

Output:

B_A_C    0.311970
G_S      0.450367
J_P_M    0.383907
M_S      0.364621
dtype: float64
          B_A_C       G_S     J_P_M       M_S
B_A_C  0.052034  0.043756  0.040258  0.040840
G_S    0.043756  0.066842  0.047369  0.053826
J_P_M  0.040258  0.047369  0.055535  0.040262
M_S    0.040840  0.053826  0.040262  0.068850

Let us define an array to hold the result of each iteration. The array will hold the returns, standard deviation, Sharpe ratio and weights for each step in the iteration. We will define one result array initially containing all zeroes and will save the simulation results in this array. The number of columns in the array is 7 to hold portfolio return, standard deviation, Sharpe Ratio and the weights of all stocks. The number of columns will change with the number of stocks in the portfolio as we have to store the weights for all the stocks. That's why we use the 'len function' while defining the array. The number of rows in the array is equal to the number of iterations.

Let’s now move on to the iterations.

We then save the output in a ‘pandas data frame’ for easy analysis and plotting of data.

sim_frame = pd.DataFrame(simulation_res.T,columns=['ret','stdev','sharpe',stock[0],stock[1],stock[2],stock[3]])
print (sim_frame.head())
print (sim_frame.tail())

Output:

        ret     stdev    sharpe       BAC        GS       JPM        MS
0  0.372583  0.217626  1.712036  0.306097  0.213561  0.299019  0.181323
1  0.363463  0.216364  1.679873  0.394337  0.130685  0.435499  0.039480
2  0.389084  0.222811  1.746252  0.133718  0.290982  0.339756  0.235544
3  0.387731  0.227346  1.705464  0.193391  0.360197  0.124769  0.321643
4  0.403024  0.230934  1.745187  0.147800  0.508287  0.134870  0.209043
           ret     stdev    sharpe       BAC        GS       JPM        MS
9995  0.393074  0.226539  1.735132  0.086871  0.322538  0.278485  0.312106
9996  0.380222  0.220915  1.721121  0.251156  0.283732  0.233118  0.231994
9997  0.378073  0.225809  1.674303  0.274834  0.308734  0.075159  0.341274
9998  0.361877  0.221326  1.635042  0.315757  0.127436  0.153136  0.403672
9999  0.386932  0.231995  1.667842  0.193662  0.371691  0.032976  0.401671

The above output shows the rows and columns of the simulation results. We can now select the portfolio with respect to the conditions we discussed earlier.

  1. Maximum Sharpe Ratio Portfolio (Tangency Portfolio) : By locating the portfolio with the highest Sharpe Ratio
  2. Minimum Variance Portfolio: By locating the portfolio with the lowest standard deviation
  3. Maximum Return Portfolio at a Given Risk: By locating the portfolio with a specific standard deviation. Here take our target portfolio to have a standard deviation closest to 23%. Because our simulated portfolios may not have a portfolio that has an exact s.d of 23%, we take a threshold range of 0.05% and spot the portfolio closest to our target portfolio.
The portfolio for max Sharpe Ratio:
 ret       0.422893
stdev     0.235598
sharpe    1.794974
BAC       0.007436
GS        0.600565
JPM       0.371630
MS        0.020369
Name: 9591, dtype: float64
The portfolio for min risk:
 ret       0.347404
stdev     0.213900
sharpe    1.624142
BAC       0.458589
GS        0.000216
JPM       0.358250
MS        0.182945
Name: 1505, dtype: float64
The portfolio with standard deviation closest to 23%:
 ret       0.419614
stdev     0.234454
sharpe    1.789751
BAC       0.045694
GS        0.601202
JPM       0.303228
MS        0.049876
Name: 7443, dtype: float64

The output can be plotted using the matplotlib library as the relevant points can be highlighted as shown:

In the output, the red star shows the portfolio with the maximum Sharpe ratio, the blue star depicts the point with the minimum standard deviation, and the green star depicts the portfolio with the maximum return at chosen level of risk.

Sharpe ratio and Standard Deviation

From the above curve, we can get the composition for the required optimal portfolio based on any of the three conditions as discussed above. We can select the portfolio with maximum return for a given risk or a portfolio with minimum risk for a given return or we can simply select the portfolio with maximum Sharpe ratio.


Summary

Just to summarize our complete analysis, we first downloaded the stock price data for one month and computed the mean return of all the stocks and the covariance matrix (which is used in computing the standard deviation of the portfolio). We then ran a Monte Carlo Simulation to compute the risk and return of the portfolio by randomly selecting the weights of the portfolio. We then identify the optimal portfolio based on the Sharpe ratio or other conditions.

Next Step

Our next blog covers various aspects of the portfolio performance evaluation and portfolio performance measurement. It starts with why evaluation and measurement are necessary. Then explains how to compute and analyse the returns generated by the portfolio after a particular time period.

Update

We have noticed that some users are facing challenges while downloading the market data from Yahoo and Google Finance platforms. In case you are looking for an alternative source for market data, you can use Quandl for the same.

Download Python Code

  • Portfolio Optimization Using Monte Carlo Simulation - Python Code

Note: The original post has been revamped on 13th May 2025 for recentness, and accuracy.

Disclaimer: All investments and trading in the stock market involve risk. Any decision to place trades in the financial markets, including trading in stock or options or other financial instruments, is a personal decision that should only be made after thorough research, including a personal risk and financial assessment and the engagement of professional assistance to the extent you believe necessary. The trading strategies or related information mentioned in this article is for informational purposes only.

Webinar on Building Quant Portfolio