Monte Carlo Simulations on Stock Portfolios in Python

Rahul Mohan
4 min readOct 17, 2023

While learning about different forecasting methods available in Python, I came across the Monte Carlo Simulation. To practise this I will pull stock data from the Yahoo Finance API and use it to create a stock portfolio to run Monte Carlo simulations on.

Importing relevant modules

I am using pretty common Python modules such as Pandas, NumPy and Matplotlib.

Yahoo Finance (yfinance) is used here to pull data on stocks.

#importing relevant modules

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
import yfinance as yf

Creating a function to pull data

This function is used to pull the necessary stock data to create our Monte Carlo simulation, the Mean Returns and Covariance.

It first looks up which stocks are being searched for, along with start and end dates.

Next it pulls the close prices for those dates, calculates the mean returns, and lastly calculates the covariance.

#function for importing data
def get_data(stocks, start, end):
stockData = yf.download(stocks, start, end)
stockData = stockData['Close']
returns = stockData.pct_change()
meanReturns = returns.mean()
covMatrix = returns.cov()
return meanReturns, covMatrix

Creating our portfolio

This section is where we define which stocks will be in our portfolio, and which date ranges to use.

For this portfolio I have chosen the largest Blue Chip Tech Stocks: Apple, Microsoft, Alphabet/Google, Amazon, Nvidia and Meta/Facebook. We can add or reduce stocks by adjusting the tickers selected in the code, we can even include indexes like the S&P 500 or FTSE 100.

For simplicity, the date range we are using is the past 300 days from the day the model is run.

For the portfolio, each stock is weighed evenly.

#selecting stocks and date ranges
stockList = ['AAPL','MSFT','GOOG','AMZN','NVDA','META']
stocks = [stock for stock in stockList]
endDate = dt.datetime.now()
startDate = endDate - dt.timedelta(days=300)

#running function to pull data on selected stocks
meanReturns, covMatrix = get_data(stocks, startDate, endDate)

#evenly weighing each stock in portfolio
weights = [1/(len(stockList))] * len(stockList)

Creating the Monte Carlo Simulation

This model will predict 100 days into the future, and will run 400 simulations.

We create a blank table for the model to fill with it’s predicted values for each simulation.

The model uses a normal distribution and the cholesky decomposition on the covariance matrix. It sums the daily returns to return a cumulative product, showing how the portfolio will grow/fall over our time period.

# monte carlo simulation

mc_sims = 400 # number of simulations
T = 100 #timeframe in days


meanM = np.full(shape=(T, len(weights)), fill_value=meanReturns)
meanM = meanM.T
portfolio_sims = np.full(shape=(T, mc_sims), fill_value=0.0)
initialPortfolio = 10000
for m in range(0, mc_sims):
Z = np.random.normal(size=(T, len(weights)))#uncorrelated RV's
L = np.linalg.cholesky(covMatrix) #cholesky decomposition
dailyReturns = meanM + np.inner(L, Z) #correlated daily returns for individual stocks
portfolio_sims[:,m] = np.cumprod(np.inner(weights, dailyReturns.T)+1)*initialPortfolio

Results of the simulation

Here are how the plots of the Monte Carlo look with different numbers of simulations. I find it helpful to show the simulation in stages as a single image with 400 lines can be difficult to comprehend.

#plotting the simulation
plt.plot(portfolio_sims)
plt.ylabel('Predicted Portfolio Value ($)')
plt.xlabel('Days')
plt.title('Monte Carlo Simulation of Stock Portfolio')
plt.show()

This is how the model looks with 1 simulation:

This is how the model looks with 10 simulations:

This is how the model looks with 50 simulations:

This is how the model looks with 400 simulations:

As we add more simulations we see a wider and denser scope of possibilities. On average we should expect a moderate upward trend where portfolio value steadily increases as days pass. There are some more fringe cases which show a sharper upward trend in portfolio value, and cases where the portfolio decreases over time.

This was an interesting exercise for me, I can see how this would be useful to predict and show the range of possibilities of an expected outcome. It can be applied to areas beyond stock portfolios such as sales forecasting, energy usage etc.

Thank you for reading

This project was a great way for me to explore what I’m capable of doing in Python. I hope to carry on learning and being able to do even more as a data analyst as I continue to develop my knowledge of tools like Python, SQL and PowerBI.

--

--