diff --git a/prediction_techniques/neural_networks.py b/prediction_techniques/neural_networks.py new file mode 100644 index 00000000000..02c8e373628 --- /dev/null +++ b/prediction_techniques/neural_networks.py @@ -0,0 +1,166 @@ +import argparse +from helper_funcs import * +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +from pandas.plotting import register_matplotlib_converters +register_matplotlib_converters() + +from TimeSeriesCrossValidation import splitTrain + +from sklearn.preprocessing import MinMaxScaler, StandardScaler +from tensorflow.keras.layers import Dense, Activation, Dropout +from tensorflow.keras.layers import LSTM, SimpleRNN +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import RepeatVector, TimeDistributed + +import os +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' + +from warnings import simplefilter +simplefilter(action='ignore', category=FutureWarning) + + +# ---------------------------------------------------------------------------------------------------- +def build_neural_network_model(Recurrent_Neural_Network, n_inputs, n_days): + model = Sequential() + + for idx_layer, d_layer in enumerate(Recurrent_Neural_Network): + # Recurrent Neural Network + if str(*d_layer) is 'SimpleRNN': + # Is this the input layer? If so, define input_shape + if idx_layer == 0: + model.add(SimpleRNN(**d_layer['SimpleRNN'], input_shape=(n_inputs, 1))) + # Is this the last output layer? If so, set units to prediction days + elif idx_layer == (len(Recurrent_Neural_Network)-1): + model.add(SimpleRNN(**d_layer['SimpleRNN'], units=n_days)) + else: + model.add(SimpleRNN(**d_layer['SimpleRNN'])) + + # Long-Short Term-Memory + elif str(*d_layer) is 'LSTM': + # Is this the input layer? If so, define input_shape + if idx_layer == 0: + model.add(LSTM(**d_layer['LSTM'], input_shape=(n_inputs, 1))) + # Is this the last output layer? If so, set units to prediction days + elif idx_layer == (len(Recurrent_Neural_Network)-1): + model.add(LSTM(**d_layer['LSTM'], units=n_days)) + else: + model.add(LSTM(**d_layer['LSTM'])) + + # Dense (Simple Neuron) + elif str(*d_layer) is 'Dense': + # Is this the input layer? If so, define input_shape + if idx_layer == 0: + model.add(Dense(**d_layer['Dense'], input_dim=n_inputs)) + # Is this the last output layer? If so, set units to prediction days + elif idx_layer == (len(Recurrent_Neural_Network)-1): + model.add(Dense(**d_layer['Dense'], units=n_days)) + else: + model.add(Dense(**d_layer['Dense'])) + + # Dropout (Regularization) + elif str(*d_layer) is 'Dropout': + model.add(Dropout(**d_layer['Dropout'])) + + else: + print(f"Incorrect neuron type: {str(*d_layer)}") + + return model + + +# -------------------------------------------------- MLP -------------------------------------------------- +def mlp(l_args, s_ticker, s_interval, df_stock): + parser = argparse.ArgumentParser(prog='mlp', + description="""Multilayer Perceptron. """) + + parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=5, help='prediction days') + parser.add_argument('-i', "--input", action="store", dest="n_inputs", type=check_positive, default=40, help='number of days to use for prediction') + parser.add_argument('-e', "--epochs", action="store", dest="n_epochs", type=check_positive, default=200, help='number of training epochs') + parser.add_argument('-f', "--freq", action="store", dest="n_jumps", type=check_positive, default=1, help='how') + parser.add_argument('-p', "--pp", action="store", dest="s_preprocessing", default='normalization', choices=['normalization', 'standardization', 'none'], help='Pre Processing data') + parser.add_argument('-o', "--optimizer", action="store", dest="s_optimizer", default='adam', help='Optimizer technique', + choices=['adam', 'adagrad', 'adadelta', 'adamax', 'ftrl', 'nadam', 'optimizer', 'rmsprop', 'sgd']) + parser.add_argument('-l', "--loss", action="store", dest="s_loss", default='mae', + choices=['mae', 'mape', 'mse', 'msle'], help='Loss function') + + 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 + + # Pre-process data + if ns_parser.s_preprocessing == 'standardization': + scaler = StandardScaler() + stock_train_data = scaler.fit_transform(np.array(df_stock['5. adjusted close'].values.reshape(-1, 1))) + elif ns_parser.s_preprocessing == 'normalization': + scaler = MinMaxScaler() + stock_train_data = scaler.fit_transform(np.array(df_stock['5. adjusted close'].values.reshape(-1, 1))) + else: # No pre-processing + stock_train_data = np.array(df_stock['5. adjusted close'].values.reshape(-1, 1)) + + # Split training data for the neural network + stock_x, stock_y = splitTrain.split_train(stock_train_data, ns_parser.n_inputs, ns_parser.n_days, numJumps=ns_parser.n_jumps) + stock_x = np.array(stock_x) + stock_x = np.reshape(stock_x, (stock_x.shape[0], stock_x.shape[1])) + stock_y = np.array(stock_y) + stock_y = np.reshape(stock_y, (stock_y.shape[0], stock_y.shape[1])) + + # Build Neural Network model + MultiLayer_Perceptron \ + = [ {'Dense': + {'units':50, 'activation':'relu'} }, + {'Dense': + {'units':100, 'activation':'relu'} }, + {'Dense': + {'units':80, 'activation':'relu'} }, + {'Dense': + {'units':30, 'activation':'relu'} }, + {'Dense': + {'activation':'linear'} }] + + model = build_neural_network_model(MultiLayer_Perceptron, ns_parser.n_inputs, ns_parser.n_days) + model.compile(optimizer=ns_parser.s_optimizer, loss=ns_parser.s_loss) + print(model.summary()) + print("") + + # Train our model + model.fit(stock_x, stock_y, epochs=ns_parser.n_epochs, verbose=0); + + # Prediction + yhat = model.predict(stock_train_data[-ns_parser.n_inputs:].reshape(1, ns_parser.n_inputs), verbose=0) + + # Re-scale the data back + if (ns_parser.s_preprocessing == 'standardization') or (ns_parser.s_preprocessing == 'normalization'): + y_pred_test_t = scaler.inverse_transform(yhat.tolist()) + else: + y_pred_test_t = yhat + + l_pred_days = get_next_stock_market_days(last_stock_day=df_stock['5. adjusted close'].index[-1], n_next_days=ns_parser.n_days) + df_pred = pd.Series(y_pred_test_t[0].tolist(), index=l_pred_days, name='Price') + + # Plotting + plt.plot(df_stock.index, df_stock['5. adjusted close'], lw=3) + plt.title(f"MLP 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['5. adjusted 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, colors='k', linewidth=3, 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 bbbc52ed99f..79874826e49 100644 --- a/prediction_techniques/pred_menu.py +++ b/prediction_techniques/pred_menu.py @@ -14,6 +14,7 @@ from prediction_techniques import knn from prediction_techniques import regression from prediction_techniques import arima from prediction_techniques import fbprophet +from prediction_techniques import neural_networks # ----------------------------------------------------------------------------------------------------------------------- def print_prediction(s_ticker, s_start, s_interval): @@ -39,10 +40,7 @@ def print_prediction(s_ticker, s_start, s_interval): print(" regression regression (other polynomial)") print(" arima autoregressive integrated moving average") print(" prophet Facebook's prophet prediction") - #print(" arima") - #print(" rnn") - #print(" lstm") - #print(" prophet") + print(" mlp MultiLayer Perceptron") print("") @@ -54,7 +52,7 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval): pred_parser.add_argument('cmd', choices=['help', 'q', 'quit', 'sma', 'knn', 'linear', 'quadratic', 'cubic', 'regression', - 'arima', 'prophet']) + 'arima', 'prophet', 'mlp']) print_prediction(s_ticker, s_start, s_interval) @@ -111,6 +109,10 @@ def pred_menu(df_stock, s_ticker, s_start, s_interval): elif ns_known_args.cmd == 'prophet': fbprophet.fbprophet(l_args, s_ticker, s_interval, df_stock) + # ------------------------------------------------ FBPROPHET ------------------------------------------------ + elif ns_known_args.cmd == 'mlp': + neural_networks.mlp(l_args, s_ticker, s_interval, df_stock) + # ------------------------------------------------------------------------------------------------------------ else: print("Command not recognized!")