How to imrove Stock Prediction using BilSTM/Prophet Output

Viewed 46

I have written and tried to implement a python code for stock market prediction. The aim of the code is to run a couple of different ML methods and compare errors and outputs of each.

The data is stock closing price since 2005, split between training and testing(testing is last 3 months of data)

A loop run through the below ML definitions and outputs the error and prediction for each.

However even using high epochs upto 50 or 100 the methods are not performing very well, with prediction not being close to actual stock performance. I'm most suprised by the prophet result i think but i'm not sure what could be changed to improve this either as not based on epochs.

I would appreciate any help in tuning these models as i have tried a range of different "improvements" with little or no luck. I could go higher epoch but my colad times out whenever i try this and i'm not sure the actual benefit.

Any suggestions welcome please, or please reach out for any more info i've exlduded?

Data:

Date Google Microsoft Apple Amazon Nivdia
01/03/2005 5.072823 18.913977 0.964983 2.226 1.804381
01/04/2005 4.867367 18.984707 0.974893 2.107 1.719442

Prophet Definition:


def prophet(train_dataset, test_dataset, verbose = 0):
    r2 = 0;
    mse = 0;
    rmse = 0;
    mae = 0;
    try:
        if (verbose == 1):
            print("starting prophet")
            print(train_dataset.head)
            print(test_dataset.head)
        prophet_basic = Prophet(daily_seasonality=True)
        #prophet_basic = Prophet(weekly_seasonality=False)
        #prophet_basic.add_seasonality(name='monthly', period=30.5, fourier_order=5)
        if (verbose == 1):
            print("fitting")
        prophet_basic.fit(train_dataset)
        future= prophet_basic.make_future_dataframe(periods=len(test_dataset), freq='D')
        if (verbose == 1):
            print("predicting")
        forecast=prophet_basic.predict(future)
        if (verbose == 1):
            print("predicted")
            print(forecast.yhat.head)
        '''
        metric_df = forecast.set_index('ds')[['yhat']].join(train_dataset.set_index('ds').y).reset_index()
        metric_df.dropna(inplace=True)
        if (verbose == 1):
            print("metric_df", metric_df.shape)
        r2 = r2_score(metric_df.y, metric_df.yhat)
        mse = mean_squared_error(metric_df.y, metric_df.yhat)
        mae = mean_absolute_error(metric_df.y, metric_df.yhat)
        rmse = math.sqrt(mse)
        '''
        l1 = len(forecast)
        l2 = len(train_dataset)
        l3 = len(test_dataset)
        result2 = pd.DataFrame()
        result2 ["forecasted"] = forecast.yhat[l2:]
        result2["real"] = [x for x in test_dataset["y"]]
        r2 = r2_score(result2.forecasted, result2.real)
        mse = mean_squared_error(result2.real, result2.forecasted)
        mae = mean_absolute_error(result2.real, result2.forecasted)
        rmse = math.sqrt(mse)
        if (verbose == 1):
            print("r2:", r2, "mse:", mse, "rmse:", rmse, "mae:", mae)
    except Exception as e:
        print(e)
        pass
    #return prophet_basic, forecast, r2, mae, mse, rmse
    return forecast, r2, mae, mse, rmse

Decomposed BiLSTM


def de_BiLSTM(train_dataset, test_dataset, n_input = 3, n_features = 1, u = 32, epochs = 100, batch = 1, verbose = 0):
    try:
        if (verbose == 1):
            print("starting BiLSTM")
        train=pd.DataFrame(data=train_dataset["y"],columns=["y"])
        if (verbose == 1):
            print("starting BiLSTM2")
        start = train_dataset.ds[0]
        if (verbose == 1):
            print("start value:", start)
        dti = pd.date_range(start, periods=len(train_dataset), freq='D')
        train["time"]=dti
        train_days=pd.DataFrame()
        train_days["time"]=dti
        train.set_index('time', inplace=True)
        if (verbose == 1):
            print("starting testdataset")
        test=pd.DataFrame(data=test_dataset["y"],columns=["y"])
        if (verbose == 1):
            print("starting testdataset2", test_dataset.head(1))
        #start2 = test_dataset.ds[0]
        start2 = test_dataset['ds'].iloc[0]
        if (verbose == 1):
            print("start value:", start2)
        dti2 = pd.date_range(start2, periods=len(test_dataset), freq='D')
        test["time"]=dti2
        if (verbose == 1):
            print("test_days")
        test_days=pd.DataFrame()
        test_days["time"]=dti2
        test.set_index('time', inplace=True)

        if (verbose == 1):
            print("starting decomposition")
        res = sm.tsa.seasonal_decompose(x=train["y"], extrapolate_trend='freq')
        lstm_train = pd.DataFrame()
        lstm_train["y"]=res.trend+res.resid

        res_test = sm.tsa.seasonal_decompose(x=test["y"], extrapolate_trend='freq')
        lstm_test = pd.DataFrame()
        lstm_test["y"]=res_test.trend+res_test.resid
        
        if (verbose == 1):
            print("starting scaler")
        scaler = MinMaxScaler()
        scaler.fit(lstm_train)
        scaled_train_data = scaler.transform(lstm_train)
        scaled_test_data = scaler.transform(lstm_test)
        
        if (verbose == 1):
            print("starting generator")
        generator = TimeseriesGenerator(scaled_train_data, scaled_train_data, length=n_input, batch_size=batch)
        lstm_model = models.Sequential()
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u, return_sequences = True, activation='relu', input_shape=(n_input, n_features))))
        lstm_model.add(layers.Dropout(0.005))
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u, return_sequences = True)))
        lstm_model.add(layers.Dropout(0.005))
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u, return_sequences = True)))
        lstm_model.add(layers.Dropout(0.005))
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u)))
        lstm_model.add(layers.Dropout(0.005))
        lstm_model.add(layers.Dense(1))
        lstm_model.compile(optimizer='adam', loss='mse')
        if (verbose == 1):
            print("starting fitting")
        lstm_model.fit(generator,epochs=epochs, verbose=verbose)
        batch = scaled_train_data[-n_input:]
        current_batch = batch.reshape((1, n_input, n_features))
        lstm_predictions_scaled = list()

        for i in range(len(lstm_test)):   
            lstm_pred = lstm_model.predict(current_batch)[0]
            lstm_predictions_scaled.append(lstm_pred) 
            current_batch = np.append(current_batch[:,1:,:],[[lstm_pred]],axis=1)

        lstm_predictions = scaler.inverse_transform(lstm_predictions_scaled)
        lstm_result = pd.DataFrame()
        lstm_result['y'] = test_dataset['y']
        lstm_result['LSTM_Predictions'] = lstm_predictions
        
        
        l_r2 = r2_score(lstm_result.y, lstm_result.LSTM_Predictions)
        l_mse = mean_squared_error(lstm_result.y, lstm_result.LSTM_Predictions)
        l_mae = mean_absolute_error(lstm_result.y, lstm_result.LSTM_Predictions)
        l_rmse = math.sqrt(l_mse)
        if (verbose==1):
            print("r2:", l_r2, "mse:", l_mse, "rmse:", l_rmse, "mae:", l_mae)
        
        
        seasonal_lstm = pd.DataFrame()
        seasonal_lstm["y"] = lstm_train["y"] + res.seasonal

        seasonal_lstm_test = pd.DataFrame()
        seasonal_lstm_test["y"] = lstm_test["y"] + res_test.seasonal

        seasonal_lstm_pred = pd.DataFrame()
        #seasonal_lstm_pred["y"] = lstm_result['LSTM_Predictions'] + res_test.seasonal
        seasonal_lstm_pred["s"] = res_test.seasonal  
        seasonal_lstm_pred["p"] = [x for x in lstm_result['LSTM_Predictions']]
        seasonal_lstm_pred["y"] = seasonal_lstm_pred[['s', 'p']].sum(axis=1)
        seasonal_lstm_pred.drop('s', inplace=True, axis=1)
        seasonal_lstm_pred.drop('p', inplace=True, axis=1)

        #seasonal_lstm_pred["y"] = seasonal_lstm_pred["y"] + lstm_result['LSTM_Predictions']
        return lstm_result,seasonal_lstm, seasonal_lstm_test, seasonal_lstm_pred, l_r2, l_mae, l_mse, l_rmse
        #return lstm_model, lstm_train, lstm_test, lstm_result, train_days, test_days, current_batch, scaler
    except Exception as e:
        print("exception:", e)
        
   

'''

BiLSTM

def BiLSTM(train_dataset, test_dataset, n_input = 3, n_features = 1, u = 32, epochs = 100, batch = 1, verbose = 0):
    try:
        if (verbose == 1):
            print("starting BiLSTM")
        train=pd.DataFrame(data=train_dataset["y"],columns=["y"])
        if (verbose == 1):
            print("starting BiLSTM2")
        start = train_dataset.ds[0]
        if (verbose == 1):
            print("start value:", start)
        dti = pd.date_range(start, periods=len(train_dataset), freq='D')
        train["time"]=dti
        train_days=pd.DataFrame()
        train_days["time"]=dti
        train.set_index('time', inplace=True)
        if (verbose == 1):
            print("starting testdataset")
        test=pd.DataFrame(data=test_dataset["y"],columns=["y"])
        if (verbose == 1):
            print("starting testdataset2", test_dataset.head(1))
        #start2 = test_dataset.ds[0]
        start2 = test_dataset['ds'].iloc[0]
        if (verbose == 1):
            print("start value:", start2)
        dti2 = pd.date_range(start2, periods=len(test_dataset), freq='D')
        test["time"]=dti2
        if (verbose == 1):
            print("test_days")
        test_days=pd.DataFrame()
        test_days["time"]=dti2
        test.set_index('time', inplace=True)

        
        scaler = MinMaxScaler()
        scaler.fit(train)
        scaled_train_data = scaler.transform(train)
        scaled_test_data = scaler.transform(test)
        
        if (verbose == 1):
            print("starting generator")
        generator = TimeseriesGenerator(scaled_train_data, scaled_train_data, length=n_input, batch_size=batch)
        lstm_model = models.Sequential()
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u, return_sequences = True, activation='relu', input_shape=(n_input, n_features))))
        lstm_model.add(layers.Dropout(0.2))
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u, return_sequences = True)))
        lstm_model.add(layers.Dropout(0.2))
        lstm_model.add(layers.Bidirectional(layers.LSTM(units=u)))
        lstm_model.add(layers.Dropout(0.2))
        lstm_model.add(layers.Dense(1))
        lstm_model.compile(optimizer='adam', loss='mse')
        if (verbose == 1):
            print("starting fitting")
        lstm_model.fit(generator,epochs=epochs, verbose=verbose)
        batch = scaled_train_data[-n_input:]
        current_batch = batch.reshape((1, n_input, n_features))
        lstm_predictions_scaled = list()

        for i in range(len(test)):   
            lstm_pred = lstm_model.predict(current_batch)[0]
            lstm_predictions_scaled.append(lstm_pred) 
            current_batch = np.append(current_batch[:,1:,:],[[lstm_pred]],axis=1)

        lstm_predictions = scaler.inverse_transform(lstm_predictions_scaled)
        lstm_result = pd.DataFrame()
        lstm_result['y'] = test_dataset['y']
        lstm_result['LSTM_Predictions'] = lstm_predictions
        
        
        l_r2 = r2_score(lstm_result.y, lstm_result.LSTM_Predictions)
        l_mse = mean_squared_error(lstm_result.y, lstm_result.LSTM_Predictions)
        l_mae = mean_absolute_error(lstm_result.y, lstm_result.LSTM_Predictions)
        l_rmse = math.sqrt(l_mse)
        if (verbose==1):
            print("r2:", l_r2, "mse:", l_mse, "rmse:", l_rmse, "mae:", l_mae)
        
        return lstm_result, l_r2, l_mae, l_mse, l_rmse
        #return lstm_model, lstm_train, lstm_test, lstm_result, train_days, test_days, current_batch, scaler
    except Exception as e:
        print("exception:", e)

Loop

params = {'googl': {'name':'Google', 'n_features': 1, 'n_input': 24, 'u': 8, 'epochs' : 1, 'train':googl_train_dataset, 'test':googl_test_dataset},
          #'msft': {'name':'Microsoft', 'n_features': 1, 'n_input': 14, 'u': 4, 'epochs' : 2, 'train':msft_train_dataset, 'test':msft_test_dataset},
          #'aapl': {'name':'Apple', 'n_features': 1, 'n_input': 24, 'u': 4, 'epochs' : 2, 'train':aapl_train_dataset, 'test':aapl_test_dataset},
          #'amzn': {'name':'Amazon', 'n_features': 1, 'n_input': 20, 'u': 4, 'epochs' : 5, 'train':amzn_train_dataset, 'test':amzn_test_dataset},
          #'nvda': {'name':'Nivdia', 'n_features': 1, 'n_input': 14, 'u': 4, 'epochs' : 5, 'train':nvda_train_dataset, 'test':nvda_test_dataset},
         }
for p in params:
    print("-----------------------------------------")
    print("starting ",params[p]['name'])
    train_dataset = params[p]['train']
    test_dataset = params[p]['test']
    n_input = params[p]['n_input']
    n_features = params[p]['n_features']
    u = params[p]['u']
    epochs = params[p]['epochs']
    l = len(train_dataset)
    
    delstm_result,seasonal_lstm, seasonal_lstm_test, seasonal_lstm_pred , dl_r2, dl_mae, dl_mse, dl_rmse = de_BiLSTM(train_dataset, test_dataset, n_input, n_features, u , epochs,  1, 0)
    lstm_result, l_r2, l_mae, l_mse, l_rmse = BiLSTM(train_dataset, test_dataset, n_input, n_features, u , epochs,  1, 0)
    forecast,p_r2, p_mae, p_mse, p_rmse = prophet(train_dataset, test_dataset, 0)
    
    result = pd.DataFrame()
    result ["Prophet"] = forecast.yhat[l:]
    result["deBiLSTM"] = [x for x in seasonal_lstm_pred["y"]]
    result['avg'] = result.mean(axis=1)
    result["real"] = [x for x in seasonal_lstm_test["y"]]
    result["days"]  = [x for x in test_dataset["ds"]]
    result["BiLSTM"] = [x for x in lstm_result["LSTM_Predictions"]]
    result["hdeBiLSTM"] = [x for x in hseasonal_lstm_pred["y"]]
    
    r2 = r2_score(result.real, result.avg)
    mse = mean_squared_error(result.real, result.avg)
    mae = mean_absolute_error(result.real, result.avg)
    rmse = math.sqrt(mse)
    print("hybrid:", "r2:", r2, "mse:", mse, "rmse:", rmse, "mae:", mae)
    print("prophet:", "r2:", p_r2, "mse:", p_mse, "rmse:", p_rmse, "mae:", p_mae)
    print("deBiLSTM:", "r2:", dl_r2, "mse:", dl_mse, "rmse:", dl_rmse, "mae:", dl_mae)
    print("BiLSTM:", "r2:", l_r2, "mse:", l_mse, "rmse:", l_rmse, "mae:", l_mae)
    plot_graph(result, params[p]['name'], show = 0)

Sample Prediction

sample prediction

0 Answers
Related