Monte Carlo Simulation for optimization of portfolio weighting - Ready to use example simulation in Python!
Understand Monte Carlo Simulation on example of portfolio optimization
Today’s article is the first of the series about Monte Carlo Simulation which will be appearing on my blog post every couple of weeks to build upon the range of benefits you may get by knowing how to apply stochastic calculus, financial models and python straight to your trading strategy.
Once choosing fabulous companies that will definitely beat the benchmark to your portfolio have you ever struggled with setting appropriate weights? did you choose them intuitively? Well, MC simulation which we will construct today will tell you which balance is the best for you based on level of risk you want to take as well as previous performance of chosen securities. How MC gets that recommendation, well by simulating different scenarios by THOUSANDS TIMES! Or even more, here your computational power is the only limit!
Building up on Modern Portfolio Theory, based on historical data it is possible to co create the best portfolio weights of given instruments based on historical performance, in terms of daily returns, volatility, skewness and kurtosis in order to achieve the best possible risk-return trade-off composition by simulating number of scenarios with various weights of portfolio, that approach is called Monte Carlo Simulation.
Monte Carlo Simulation Overview
Monte Carlo simulation is a computational technique that uses random sampling to model the probability of different outcomes in a complex system. In finance, it is used to model the behaviour of financial assets and markets, and to estimate the likelihood of different investment outcomes.
The technique is named after the famous Monte Carlo Casino in Monaco, where the method was first used to analyse the odds of winning at roulette. Today, Monte Carlo simulation is used in a wide range of fields, from physics to engineering to finance.
At its core, Monte Carlo simulation works by generating a large number of random simulations, each of which represents a possible scenario for the financial market. These simulations are then used to calculate the expected value, standard deviation, and other statistical measures of the market’s behaviour.
For example, let’s say we want to model the behaviour of a stock over the next year. We might start by gathering historical data on the stock’s price, volume, and other relevant factors. Using this data, we can build a statistical model of the stock’s behaviour.
Other example can be, based on certain set indicator we can set up optimal weights for an investment portfolio in less than 10 minutes. Now is the time to show you how!
Monte Carlo Simulation in Practice
To start off with building our promised simulation we need to set certain indicator that will measure desired performance. Sharpe ratio is great, time-proof, simple and widely used measure to examine level of investment return in its proportion to volatility, often with consideration of risk free rate. Formula for this Sharpe ratio is rather simple:
(Formula)
As a rule of thumb, huge indexes like S7P 500 or FTSE 100 have Sharpe ratio of 1, of course the bigger the share ratio the more profitable the investment in a given amount of risk, which is here measured as Standard Deviation, which is a default for measuring volatility of the stock and therefore its riskiness.
Therefore, the most optimal portfolio would give the biggest possible Sharpe ratio in proportion of risk you are willing to take.
Let’s start a bit backwards today and analyse result of Monte Carlo Simulation outcome to give you taste of what it can do:
(MC Graph)
This simulation displays best Sharpe Ratio for given areas and highlighted field is the target Sharpe Ratio that given weights performed in the past, now please take a look at code of this simulation below with comments along the way:
Also, you can see results on my GitHub page here
#import necessary packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
from datetime import date, timedelta
#Read the stock market data based on tickers of selected companies
MSFT = yf.download("MSFT", start = date.today() - timedelta(days=1095), end = date.today())['Adj Close']
AAPL = yf.download("AAPL", start = date.today() - timedelta(days=1095), end = date.today())['Adj Close']
AMZN = yf.download("AMZN", start = date.today() - timedelta(days=1095), end = date.today())['Adj Close']
NVDA = yf.download("NVDA", start = date.today() - timedelta(days=1095), end = date.today())['Adj Close']
#Create the dataframe
df = pd.concat([MSFT,AAPL,AMZN,NVDA], axis =1)
df.columns = ['MSFT','AAPL','AMZN','NVDA']
#Monte Carlo variables calculations
#Calcuclate logarithmic returns
log_rets = np.log(df/df.shift(1))
# N = number of holdings in the portfolio
N = len(df.columns)
#set of N random numbers (not adding up to 1!)
weights = np.random.random(N)
# sum very close to one but with float error (not affecting anything)
weights = weights/ np.sum(weights)
#Calculate covariance
covariance = log_rets.cov()
#Function to generate random portfolio weights for every simulation
def generate_weights(N):
weights = np.random.random(N)
return weights/np.sum(weights)
#Function to calculate returns for every combination of simulated weights
def calculate_returns(wights, log_rets):
return np.sum(log_r.mean()*weights) * 252
#Function to calculate volitality of every simulation
def calculate_volitality(weights, covariance):
annulaized_cov = np.dot(covariance*252,weights)
vol = np.dot(weights.transpose(),annulaized_cov)
return np.sqrt(vol)
# Monte Carlo Simulation
mc_returns = []
mc_vol = []
mc_weights = []
for sims in range(10000):
weights = generate_weights(N=4)
mc_weights.append(weights)
sim_r = calculate_returns(weights, log_r)
mc_returns.append(sim_r)
sim_vol = calculate_volitality(weights, covariance)
mc_vol.append(sim_vol)
#Share ratio as indicator of simulated performances
sp_ratio = np.array(mc_returns)/np.array(mc_vol)
#Scatter diagram
plt.figure(dpi=200, figsize = (10,5))
plt.scatter(x= mc_vol, y = mc_returns, c= sp_ratio)
plt.colorbar(label = 'Sharpe ratio')
plt.xlabel('Volitality')
plt.ylabel('Return')
plt.title('Monte Carlo performance simulation of different portfolio weights based on historical data')
#Weights with the best performance relative to level of risk
mc_weights[np.argmax(sp_ratio)]
You can modify number of holdings at any time, just change cells (2 and 3) accordingly.
Notice Sharpe ratio for the same period for S&P 500 is equal to 0.60. Therefore, bear in mind that the timeframe set in this simulation is 3 years due to the market abnormal behavior in recent year, however range of appropriate price information needs to be balance well to not be too short to capture all market movements however not to long to maintain relevance. In practice recommended timeframes are between 1 year to 3 years for that type of simulation.
Current market data are perfect example of mismatch of models based on historical data in relation to market predictions. Over the last 3 years due to the major events such as Covid19 pandemic, Russia-Ukraine War, Costs of Living Crisis etc. market has experienced major disruptions. Above model examines market volatility based on that period and assumes that the market will behave relatively similar in the future (historical volatility).
Alternative to that approach is implied volatility. Implied volatility is measure widely used on both Sell-side as well as buy side and it can vastly improve accuracy of the financial models. It is calculated by estimating what market and investors think future volatility will be and there are couple of models how to estimate it. In our case implied volatility implemented in place of historical one would enable us to get more relevant estimation regarding future performance of the portfolio in relation to risk the tare more in pair with the current market environment
Limitations and criticism:
However, this model is likely to be imperfect, as it cannot account for all of the factors that might affect the stock’s performance. To account for these uncertainties, we can use Monte Carlo simulation to generate a large number of possible scenarios for the stock’s behaviour, based on different assumptions about the market.
Each scenario represents a possible path that the stock might take over the next year, given a set of initial conditions. For example, we might simulate a scenario where the stock price increases by 10% over the next year, or a scenario where the stock price decreases by 5%. Monte Carlo Simulation then gives us the portion of scenarios where given condition has been met
By simulating a large number of scenarios, we can calculate the expected value of the stock’s performance, as well as its standard deviation and other statistical measures. This allows us to assess the risk of different investment strategies and make informed decisions about where to invest our money.
Conclusions
Of course, Monte Carlo simulation is not a perfect tool. It relies on a number of assumptions and simplifications, and it can be difficult to accurately model complex financial systems. However, when used correctly, it can provide valuable insights into the behaviour of financial markets and help investors make better decisions.
That being said, I hope you enjyed practical example of using Monte Carlo simulation.
Thank you all for reading and stay tuned for next weeks implied volatility calculation that will undoubtedly enrich our Monte Carlo Simulation.
Stay safe,
Tomasz