From da8b1a862c242cfbbbe12fcf1f359f21f38d7be9 Mon Sep 17 00:00:00 2001 From: didier Date: Tue, 9 Feb 2021 23:20:52 +0000 Subject: [PATCH] Add new ARIMA model to prediction techniques menu --- prediction_techniques/arima.py | 77 ++++++++++++++++++++++++++++++ prediction_techniques/pred_menu.py | 13 +++-- 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 prediction_techniques/arima.py diff --git a/prediction_techniques/arima.py b/prediction_techniques/arima.py new file mode 100644 index 00000000000..aca8c1e7dff --- /dev/null +++ b/prediction_techniques/arima.py @@ -0,0 +1,77 @@ +import argparse +from helper_funcs import * +import pandas as pd +import matplotlib.pyplot as plt +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() +import pmdarima +from statsmodels.tsa.arima.model import ARIMA + +# -------------------------------------------------- ARIMA -------------------------------------------------- +def arima(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='arima', + description="""In statistics and econometrics, and in particular in time + series analysis, an autoregressive integrated moving average (ARIMA) model + is a generalization of an autoregressive moving average (ARMA) model. Both + of these models are fitted to time series data either to better understand + the data or to predict future points in the series (forecasting). """) + + parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=5, help='prediction days') + parser.add_argument('-i', "--ic", action="store", dest="s_ic", type=str, default='aic', choices=['aic', 'aicc', 'bic', 'hqic', 'oob'], help='information criteria') + parser.add_argument('-s', "--seasonal", action="store_true", default=False, dest="b_seasonal", help='Use the fact that the market data is weekly') + parser.add_argument('-o', "--order", action="store", dest="s_order", type=str, help='arima model order') + parser.add_argument('-r', "--results", action="store_true", dest="b_results", default=False, help='results about ARIMA summary') + + try: + (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) + + if l_unknown_args: + print(f"The following args couldn't be interpreted: {l_unknown_args}\n") + return + + # Machine Learning model + if ns_parser.s_order: + t_order = tuple([int(ord) for ord in list(ns_parser.s_order)]) + model = ARIMA(df_stock['4. close'].values, order=t_order).fit() + l_predictions = model.predict(start=len(df_stock['4. close'])+1, end=len(df_stock['4. close'])+ns_parser.n_days) + else: + if ns_parser.b_seasonal: + model = pmdarima.auto_arima(df_stock['4. close'].values, error_action='ignore', seasonal=True, m=5, information_criteria=ns_parser.s_ic) + else: + model = pmdarima.auto_arima(df_stock['4. close'].values, error_action='ignore', seasonal=False, information_criteria=ns_parser.s_ic) + l_predictions = model.predict(n_periods=ns_parser.n_days) + + # Prediction data + l_pred_days = get_next_stock_market_days(last_stock_day=df_stock['4. close'].index[-1], n_next_days=ns_parser.n_days) + df_pred = pd.Series(l_predictions, index=l_pred_days, name='Price') + + if ns_parser.b_results: + print(model.summary()) + print("") + + # Plotting + plt.plot(df_stock.index, df_stock['4. close'], lw=2) + if ns_parser.s_order: + plt.title(f"ARIMA {str(t_order)} on {s_ticker} - {ns_parser.n_days} days prediction") + else: + plt.title(f"ARIMA {model.order} on {s_ticker} - {ns_parser.n_days} days prediction") + plt.xlim(df_stock.index[0], get_next_stock_market_days(df_pred.index[-1], 1)[-1] ) + plt.xlabel('Time') + plt.ylabel('Share Price ($)') + plt.grid(b=True, which='major', color='#666666', linestyle='-') + plt.minorticks_on() + plt.grid(b=True, which='minor', color='#999999', linestyle='-', alpha=0.2) + plt.plot([df_stock.index[-1], df_pred.index[0]], [df_stock['4. close'].values[-1], df_pred.values[0]], lw=1, c='tab:green', linestyle='--') + plt.plot(df_pred.index, df_pred, lw=2, c='tab:green') + plt.axvspan(df_stock.index[-1], df_pred.index[-1], facecolor='tab:orange', alpha=0.2) + xmin, xmax, ymin, ymax = plt.axis() + plt.vlines(df_stock.index[-1], ymin, ymax, linewidth=1, linestyle='--', color='k') + plt.show() + + # Print prediction data + df_pred = df_pred.apply(lambda x: f"{x:.2f} $") + print(df_pred.to_string()) + print("") + + except: + print("") diff --git a/prediction_techniques/pred_menu.py b/prediction_techniques/pred_menu.py index 3313888ab7f..7ece85701a2 100644 --- a/prediction_techniques/pred_menu.py +++ b/prediction_techniques/pred_menu.py @@ -12,6 +12,7 @@ register_matplotlib_converters() from prediction_techniques import sma from prediction_techniques import knn from prediction_techniques import regression +from prediction_techniques import arima # ----------------------------------------------------------------------------------------------------------------------- def print_prediction(s_ticker, s_start, s_interval): @@ -35,6 +36,7 @@ def print_prediction(s_ticker, s_start, s_interval): print(" quadratic quadratic regression (polynomial 2)") print(" cubic cubic regression (polynomial 3)") print(" regression regression (other polynomial)") + print(" arima autoregressive integrated moving average") #print(" arima") #print(" rnn") #print(" lstm") @@ -49,7 +51,8 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval): pred_parser = argparse.ArgumentParser(prog='technical_analysis', add_help=False) pred_parser.add_argument('cmd', choices=['help', 'q', 'quit', 'sma', 'knn', - 'linear', 'quadratic', 'cubic', 'regression']) + 'linear', 'quadratic', 'cubic', 'regression', + 'arima']) print_prediction(s_ticker, s_start, s_interval) @@ -81,11 +84,11 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval): elif ns_known_args.cmd == 'sma': sma.simple_moving_average(l_args, s_ticker, s_interval, df_stock) - # ------------------------------------------ k NEAREST NEIGHBORS ------------------------------------------ + # ------------------------------------------- k NEAREST NEIGHBORS ------------------------------------------ elif ns_known_args.cmd == 'knn': knn.k_nearest_neighbors(l_args, s_ticker, s_interval, df_stock) - # ------------------------------------------------- REGRESSION ------------------------------------------------- + # ----------------------------------------------- REGRESSION ------------------------------------------------- elif ns_known_args.cmd == 'linear': regression.regression(l_args, s_ticker, s_interval, df_stock, regression.LINEAR) @@ -98,6 +101,10 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval): elif ns_known_args.cmd == 'regression': regression.regression(l_args, s_ticker, s_interval, df_stock, regression.USER_INPUT) + # ------------------------------------------------- ARIMA ------------------------------------------------- + elif ns_known_args.cmd == 'arima': + arima.arima(l_args, s_ticker, s_interval, df_stock) + # ------------------------------------------------------------------------------------------------------------ else: print("Command not recognized!")