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 | 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
