Add Monte Carlo prediction technique (#846)

* Add monte carlo forecast

* Add hugo

* Update _index.md

* review edits

Co-authored-by: James Maslek <james@macbook-pro.myfiosgateway.com>
This commit is contained in:
jmaslek
2021-10-24 18:54:13 -04:00
committed by GitHub
parent 45d7a60ac6
commit d06d56c0e8
5 changed files with 195 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
"""Monte Carlo Model"""
__docformat__ = "numpy"
from typing import Union
import pandas as pd
import numpy as np
from scipy.stats import norm
def get_mc_brownian(
data: Union[pd.Series, np.array], n_future: int, n_sims: int, use_log=True
) -> np.array:
"""Performs monte carlo forecasting for brownian motion with drift
Parameters
----------
data : Union[pd.Series, np.array]
Input data.
n_future : int
Number of future steps
n_sims : int
Number of simulations to run
use_log : bool, optional
Flag to use log returns, by default True
Returns
-------
np.array
Array of predictions. Has shape (n_future, n_sims)
"""
changes = data.pct_change().dropna()
if use_log:
changes = np.log(1 + changes)
dist_mean = changes.mean()
dist_var = changes.var()
dist_drift = dist_mean - 0.5 * dist_var
dist_std = np.sqrt(dist_var)
random_steps = norm.ppf(np.random.rand(n_future, n_sims))
predicted_change = np.exp(dist_drift + dist_std * random_steps)
possible_paths = np.zeros_like(predicted_change)
possible_paths[0] = data.values[-1]
for t in range(1, n_future):
possible_paths[t] = possible_paths[t - 1] * predicted_change[t]
return possible_paths

View File

@@ -0,0 +1,70 @@
"""Monte Carlo View"""
__docformat__ = "numpy"
from typing import Union
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from gamestonk_terminal.common.prediction_techniques import mc_model
from gamestonk_terminal.helper_funcs import (
plot_autoscale,
get_next_stock_market_days,
export_data,
)
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal import feature_flags as gtff
def display_mc_forecast(
data: Union[pd.Series, np.array],
n_future: int,
n_sims: int,
use_log=True,
export: str = "",
):
"""Display monte carlo forecasting
Parameters
----------
data : Union[pd.Series, np.array]
Data to forecast
n_future : int
Number of days to forecast
n_sims : int
Number of simulations to run
use_log : bool, optional
Flag to use lognormal, by default True
export: str
Format to export data
"""
predicted_values = mc_model.get_mc_brownian(data, n_future, n_sims, use_log)
future_index = get_next_stock_market_days(data.index[-1], n_next_days=n_future)
dateFmt = mdates.DateFormatter("%m/%d/%Y")
fig, ax = plt.subplots(1, 2, figsize=plot_autoscale(), dpi=PLOT_DPI)
ax[0].plot(data)
ax[0].plot(future_index, predicted_values, alpha=0.3)
ax[0].set_title("Data Predictions")
ax[0].xaxis.set_major_formatter(dateFmt)
ax[0].tick_params(axis="x", labelrotation=45)
ax[0].grid("on")
sns.histplot(predicted_values[-1, :], ax=ax[1], kde=True)
ax[1].set_xlabel("Price")
ax[1].set_title(f"Distribution of data after {n_future} days.")
ax[1].set_xlim(np.min(predicted_values[-1, :]), np.max(predicted_values[-1, :]))
ax[1].grid("on")
fig.tight_layout(pad=2)
if gtff.USE_ION:
plt.ion()
plt.show()
export_data(export, os.path.dirname(os.path.abspath(__file__)), "mc")
print("")

View File

@@ -27,6 +27,7 @@ from gamestonk_terminal.common.prediction_techniques import (
neural_networks_view,
regression_view,
pred_helper,
mc_view,
)
from gamestonk_terminal.stocks.stocks_helper import load
@@ -46,6 +47,7 @@ class PredictionTechniquesController:
"rnn",
"lstm",
"conv1d",
"mc",
]
CHOICES += CHOICES_MODELS
@@ -105,6 +107,7 @@ Models:
rnn Recurrent Neural Network
lstm Long-Short Term Memory
conv1d 1D Convolutional Neural Network
mc Monte-Carlo simulations
"""
print(help_string)
@@ -724,6 +727,59 @@ Models:
finally:
pred_helper.restore_env()
def call_mc(self, other_args: List[str]):
"""Process mc command"""
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
add_help=False,
prog="mc",
description="""
Perform Monte Carlo forecasting
""",
)
parser.add_argument(
"-d",
"--days",
help="Days to predict",
dest="n_days",
type=check_positive,
default=30,
)
parser.add_argument(
"-n",
"--num",
help="Number of simulations to perform",
dest="n_sims",
default=100,
)
parser.add_argument(
"--dist",
choices=["normal", "lognormal"],
default="lognormal",
dest="dist",
help="Whether to model returns or log returns",
)
try:
ns_parser = parse_known_args_and_warn(
parser, other_args, export_allowed=EXPORT_ONLY_FIGURES_ALLOWED
)
if not ns_parser:
return
if self.target != "AdjClose":
print("MC Prediction designed for AdjClose prices")
return
mc_view.display_mc_forecast(
data=self.stock[self.target],
n_future=ns_parser.n_days,
n_sims=ns_parser.n_sims,
use_log=ns_parser.dist == "lognormal",
export=ns_parser.export,
)
except Exception as e:
print(e, "\n")
def menu(ticker: str, start: datetime, interval: str, stock: pd.DataFrame):
"""Prediction Techniques Menu"""

View File

@@ -0,0 +1,20 @@
```
usage: mc [-d N_DAYS] [-n N_SIMS] [--dist {normal,lognormal}] [-h] [--export {png,jpg,pdf,svg}]
```
Perform Monte Carlo forecasting
```
optional arguments:
-d N_DAYS, --days N_DAYS
Days to predict (default: 30)
-n N_SIMS, --num N_SIMS
Number of simulations to perform (default: 100)
--dist {normal,lognormal}
Whether to model returns or log returns (default: lognormal)
-h, --help show this help message (default: False)
--export {png,jpg,pdf,svg}
Export figure into png, jpg, pdf, svg (default: )
```
![MC_fig](https://user-images.githubusercontent.com/18151143/138540365-55a253f4-e02f-406d-9398-984d988888d7.png)

View File

@@ -508,6 +508,8 @@ main:
ref: "/stocks/prediction_techniques/lstm"
- name: conv1d
ref: "/stocks/prediction_techniques/conv1d"
- name: mc
ref: "/stocks/prediction_techniques/mc"
- name: report
ref: "/stocks/report"
- name: forex