Stock Price Forecasting with Monte Carlo Simulation

Apr 9, 2023

3 min read


programmer-with-chrome

What is the concept of Stock Monte Carlo?


Stock Monte Carlo is a concept that uses random sampling and statistical modeling to estimate the potential future behavior of a stock. The Stock Monte Carlo Chart illustrates simulated returns based on historical data.


In this tutorial, you have successfully imported the necessary libraries, fetched stock data from Yahoo Finance, and calculated the mean and standard deviation of the stock’s returns. You have then applied the Monte Carlo simulation function to create a price matrix, which estimates the stock’s future price based on historical performance. By plotting the results, you have visualized the range of possible future stock prices.


First, import the necessary libraries and dataset:


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import yfinance as yf
import pandas_ta as ta
import plotly.graph_objects as go
import plotly.express as px
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

plt.rcParams['figure.figsize'] = [15, 9]
plt.style.use('ggplot')
sns.set_style("whitegrid")

Create a ticker list and download the maximum data with a 1-day interval from Yahoo Finance:


df = yf.download(tickers='PTT.BK',period= 'max', interval = '1d')
df['return'] = df.Close.pct_change()
df.tail()

[*********************100%***********************]  1 of 1 completed

OpenHighLowCloseAdj CloseVolumereturn
Date
2023-03-0231.5031.7531.2531.5031.5060011300-0.015625
2023-03-0331.5031.7531.5031.5031.50199081000.000000
2023-03-0731.7532.2531.5031.7531.75421087000.007937
2023-03-0831.5031.7531.5031.5031.5024125500-0.007874
2023-03-0931.5031.5031.0031.0031.0058129951-0.015873

monte carlo simulation function:


def monte_carlo(mean = 0, std = 0, startprice = 1, ndays = 252, n = 3000):
    
    simulation = np.random.normal(loc=mean, scale=std, size=(ndays,n))
    simulation = pd.DataFrame(simulation)
    simulation.iloc[0,:] = 0 
    price_matrix = startprice * ((simulation+1).cumprod())

    return price_matrix

apply montecarlo function:


mean_return = df['return'].mean() # Calculate mean of return
std_return = df['return'].std() # Calculate std of return
stock_lastprice = df.Close.iloc[-1]
price_matrix = monte_carlo(mean = mean_return, std = std_return, startprice = stock_lastprice, ndays = 252, n = 3000)
price_matrix

01234567892990299129922993299429952996299729982999
031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.000000
130.62414230.88682230.30293531.45639029.92592431.01581531.43592831.92518530.39685130.66924030.63699131.58154631.48645031.37857730.36719231.19910730.64821430.31671730.77967031.759020
230.92938431.03170030.31292831.35981529.59910530.51313931.71966831.79864829.95044430.01671630.51555130.44509731.22479730.69505131.02127330.92228230.73569930.83875431.07399731.752538
331.43226930.92482730.61807731.41131929.44854130.73347532.92792831.19607929.00368830.82407330.62468830.57824230.43254730.71115831.94781931.70545231.28837930.70014030.74684832.191944
431.05045730.73831432.22635830.59550229.42456831.35265332.50123331.82701329.48791329.89931729.68131130.01466730.06314930.25713732.16997532.34967131.70811631.06138930.59596832.566573
24724.75987630.43321139.12775655.78663428.24896847.02397733.84488747.59765952.59414939.47502056.00895532.18261527.97207935.58011636.54520428.66426032.46910233.53156230.60652071.623563
24825.06419630.76622238.48041058.02893628.42021147.74399434.56864847.53908952.07168639.44528557.89647131.92236827.61049836.33096335.40732728.59771831.41682631.82863131.89466273.021210
24925.56431031.27323639.40139959.40837328.00727948.81521034.88849746.30062651.66783039.44617857.65499332.68624027.27071335.40962135.18375929.26087331.05186131.39910832.09951174.604010
25025.59406731.55344239.99330457.17478928.33682849.57558734.56187745.45793251.13848640.33077359.28816132.71746927.52084635.45320035.54723129.49665831.52815031.49767131.09611074.683576
25125.32029932.10905840.06244356.57017028.64724549.24250034.55295545.78158349.04364040.10124157.72974732.02386827.23724536.99918536.01080529.75745031.77451730.64625030.99681174.668853

252 rows × 3000 columns


Plot monte carlo between 5-95 percentile :


price_matrix['percentile_5'] = np.percentile(price_matrix, 5, axis=1)
price_matrix['percentile_95'] = np.percentile(price_matrix, 95, axis=1)
plt.fill_between(price_matrix.index, price_matrix['percentile_5'], price_matrix['percentile_95'],color='blue')
plt.plot(price_matrix, lw=1, color='skyblue', alpha=0.1)
plt.title('PTT Projection Price Simulation 252 days', size=15, fontstyle='italic')
plt.xlabel('Day', size=15)
plt.ylabel('Price', size=15)
plt.show()

png


Create a function to generate future day simulations:


import datetime
 
#create future day
start = datetime.datetime.strptime("26-08-2022", "%d-%m-%Y")
end = datetime.datetime.strptime("15-08-2023", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end - start).days)]
date_generated =  pd.DataFrame(date_generated)
date_generated['day_name'] = date_generated.iloc[:,0].dt.day_name()
date_generated = date_generated[(date_generated['day_name'] != 'Saturday')&(date_generated['day_name'] != 'Sunday')]
price_matrix.index = date_generated.iloc[:,0].values
price_matrix.head()

0123299729982999percentile_5percentile_95
2022-08-2631.00000031.00000031.00000031.00000031.00000031.00000031.00000031.00000031.000000
2022-08-2930.62414230.88682230.30293531.45639030.31671730.77967031.75902029.96314231.988664
2022-08-3030.92938431.03170030.31292831.35981530.83875431.07399731.75253829.56471732.402370
2022-08-3131.43226930.92482730.61807731.41131930.70014030.74684832.19194429.28941332.715531
2022-09-0131.05045730.73831432.22635830.59550231.06138930.59596832.56657329.03776032.980414

5 rows × 3002 columns


visulization section


plt.plot(price_matrix)
plt.title('PTT Future Price Simulation 252 days', size=15, fontstyle='italic')
plt.xlabel('Day', size=15)
plt.ylabel('Price', size=15)
plt.show()

png


Conclusion


In conclusion, the Monte Carlo Simulation is a valuable method for estimating the range of possible future stock prices by simulating random future scenarios based on historical data. It helps investors better understand the potential risks and opportunities associated with a particular stock, and can be a useful tool in making informed investment decisions.