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
Open | High | Low | Close | Adj Close | Volume | return | |
---|---|---|---|---|---|---|---|
Date | |||||||
2023-03-02 | 31.50 | 31.75 | 31.25 | 31.50 | 31.50 | 60011300 | -0.015625 |
2023-03-03 | 31.50 | 31.75 | 31.50 | 31.50 | 31.50 | 19908100 | 0.000000 |
2023-03-07 | 31.75 | 32.25 | 31.50 | 31.75 | 31.75 | 42108700 | 0.007937 |
2023-03-08 | 31.50 | 31.75 | 31.50 | 31.50 | 31.50 | 24125500 | -0.007874 |
2023-03-09 | 31.50 | 31.50 | 31.00 | 31.00 | 31.00 | 58129951 | -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
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | … | 2990 | 2991 | 2992 | 2993 | 2994 | 2995 | 2996 | 2997 | 2998 | 2999 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | … | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 |
1 | 30.624142 | 30.886822 | 30.302935 | 31.456390 | 29.925924 | 31.015815 | 31.435928 | 31.925185 | 30.396851 | 30.669240 | … | 30.636991 | 31.581546 | 31.486450 | 31.378577 | 30.367192 | 31.199107 | 30.648214 | 30.316717 | 30.779670 | 31.759020 |
2 | 30.929384 | 31.031700 | 30.312928 | 31.359815 | 29.599105 | 30.513139 | 31.719668 | 31.798648 | 29.950444 | 30.016716 | … | 30.515551 | 30.445097 | 31.224797 | 30.695051 | 31.021273 | 30.922282 | 30.735699 | 30.838754 | 31.073997 | 31.752538 |
3 | 31.432269 | 30.924827 | 30.618077 | 31.411319 | 29.448541 | 30.733475 | 32.927928 | 31.196079 | 29.003688 | 30.824073 | … | 30.624688 | 30.578242 | 30.432547 | 30.711158 | 31.947819 | 31.705452 | 31.288379 | 30.700140 | 30.746848 | 32.191944 |
4 | 31.050457 | 30.738314 | 32.226358 | 30.595502 | 29.424568 | 31.352653 | 32.501233 | 31.827013 | 29.487913 | 29.899317 | … | 29.681311 | 30.014667 | 30.063149 | 30.257137 | 32.169975 | 32.349671 | 31.708116 | 31.061389 | 30.595968 | 32.566573 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
247 | 24.759876 | 30.433211 | 39.127756 | 55.786634 | 28.248968 | 47.023977 | 33.844887 | 47.597659 | 52.594149 | 39.475020 | … | 56.008955 | 32.182615 | 27.972079 | 35.580116 | 36.545204 | 28.664260 | 32.469102 | 33.531562 | 30.606520 | 71.623563 |
248 | 25.064196 | 30.766222 | 38.480410 | 58.028936 | 28.420211 | 47.743994 | 34.568648 | 47.539089 | 52.071686 | 39.445285 | … | 57.896471 | 31.922368 | 27.610498 | 36.330963 | 35.407327 | 28.597718 | 31.416826 | 31.828631 | 31.894662 | 73.021210 |
249 | 25.564310 | 31.273236 | 39.401399 | 59.408373 | 28.007279 | 48.815210 | 34.888497 | 46.300626 | 51.667830 | 39.446178 | … | 57.654993 | 32.686240 | 27.270713 | 35.409621 | 35.183759 | 29.260873 | 31.051861 | 31.399108 | 32.099511 | 74.604010 |
250 | 25.594067 | 31.553442 | 39.993304 | 57.174789 | 28.336828 | 49.575587 | 34.561877 | 45.457932 | 51.138486 | 40.330773 | … | 59.288161 | 32.717469 | 27.520846 | 35.453200 | 35.547231 | 29.496658 | 31.528150 | 31.497671 | 31.096110 | 74.683576 |
251 | 25.320299 | 32.109058 | 40.062443 | 56.570170 | 28.647245 | 49.242500 | 34.552955 | 45.781583 | 49.043640 | 40.101241 | … | 57.729747 | 32.023868 | 27.237245 | 36.999185 | 36.010805 | 29.757450 | 31.774517 | 30.646250 | 30.996811 | 74.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()
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()
0 | 1 | 2 | 3 | … | 2997 | 2998 | 2999 | percentile_5 | percentile_95 | |
---|---|---|---|---|---|---|---|---|---|---|
2022-08-26 | 31.000000 | 31.000000 | 31.000000 | 31.000000 | … | 31.000000 | 31.000000 | 31.000000 | 31.000000 | 31.000000 |
2022-08-29 | 30.624142 | 30.886822 | 30.302935 | 31.456390 | … | 30.316717 | 30.779670 | 31.759020 | 29.963142 | 31.988664 |
2022-08-30 | 30.929384 | 31.031700 | 30.312928 | 31.359815 | … | 30.838754 | 31.073997 | 31.752538 | 29.564717 | 32.402370 |
2022-08-31 | 31.432269 | 30.924827 | 30.618077 | 31.411319 | … | 30.700140 | 30.746848 | 32.191944 | 29.289413 | 32.715531 |
2022-09-01 | 31.050457 | 30.738314 | 32.226358 | 30.595502 | … | 31.061389 | 30.595968 | 32.566573 | 29.037760 | 32.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()