Format: text/x-python
⬇ Download File (7.8 KB)
   1  # Train ML/DL model to predict stock prices for the next day 
   2  '''
   3  Designed an Stacked GRU and LSTM based model to predict Future price of the stocks
   4  In this implementation I used following TI
   5  Technical Analysis:
   6  Use of Technical Indicators:
   7  1. SMA (OHLC)
   8  2. RSI (Relative Strength Index)
   9  3. Stochastic Oscillator
  10  '''
  11  import os
  12  import math
  13  import numpy as np
  14  import argparse
  15  import pandas as pd
  16  from sklearn.metrics import mean_squared_error
  17  import tensorflow as tf
  18  from tensorflow.keras.models import load_model
  19  import matplotlib.pyplot as plt
  20  import seaborn as sns
  21  from sklearn.preprocessing import MinMaxScaler
  22  from config import DATA_PATH
  23  
  24  sns.set()
  25  parser = argparse.ArgumentParser()
  26  parser.add_argument('--stock_name',type=str, default="AAPL")
  27  parser.add_argument('--load_all',action='store_true', help='For complete dataset (without TA)')
  28  parser.add_argument('--use_ta',action='store_true', help='with technical indicators')
  29  parser.add_argument('--indicator',type=str, default='RSI', help='technical indicators, (RSI, Stochastic)')
  30  parser.add_argument('--epoch',type=int, default=5, help='number of iterations')
  31  parser.add_argument('--not_train',action='store_true', help='load save model')
  32  arg = parser.parse_args()
  33  
  34  test_set_size_percentage = 10
  35  
  36  def create_dataset(dataset, step_size):
  37  	data_X, data_Y = [], []
  38  	for i in range(len(dataset)-step_size-1):
  39  		a = dataset[i:(i+step_size), 0]
  40  		data_X.append(a)
  41  		data_Y.append(dataset[i + step_size, 0])
  42  	return np.array(data_X), np.array(data_Y)
  43  
  44  '''
  45  DATA_PATH: Path to the Dataset (change in config.py accordingly)
  46  stock_name: Stock Name present in Stock List dataframe (AAPL, DIS, MKT, YHOO, etc) 
  47  '''
  48  df = pd.read_csv(DATA_PATH + '/prices-split-adjusted.csv')
  49  if arg.stock_name not in list(df['symbol']):
  50  	raise ValueError(arg.stock_name +" "+ "is not listed in Stock List")
  51  
  52  print('Number of Unique Stocks: ', len(list(set(df.symbol)))) # Total Stocks Name in List (501)
  53  print(list(set(df.symbol))[:10]) # 10 Stock Names
  54  
  55  stock_price = df[df['symbol']== arg.stock_name]
  56  sns.relplot(x='date', y='close',kind='line', legend='full' ,data=stock_price[:100]) # plot for 100 samples
  57  sns.relplot(x='date', y='volume',kind='line', legend='full' ,data=stock_price[:100])
  58  df_stocks = stock_price.reindex(index = stock_price.index[::-1])
  59  obs = np.arange(1, len(df_stocks) + 1, 1)
  60  plt.show()
  61  
  62  # drop columns from dataframe
  63  df_stocks.drop(['symbol'], 1, inplace=True)
  64  df_stocks.drop(['date'], 1, inplace=True)
  65  
  66  # Technical Indicators for Analysis
  67  OHLC_avg = df_stocks[['open', 'high', 'low', 'close']].mean(axis=1) # SMA
  68  HLC_avg = df_stocks[['high', 'low', 'close']].mean(axis=1)
  69  close_val  = df_stocks[['close']]
  70  
  71  if arg.use_ta:
  72  	if arg.indicator == 'RSI':
  73  		diff = close_val.diff(1)
  74  		up = diff.where(diff > 0, 0.0)
  75  		dn = -diff.where(diff < 0, 0.0)
  76  		min_periods = 14	
  77  		emaup = up.ewm(alpha=1/14, min_periods=min_periods, adjust=False).mean()
  78  		emadn = dn.ewm(alpha=1/14, min_periods=min_periods, adjust=False).mean()
  79  		rs = emaup / emadn # (https://www.investopedia.com/terms/r/rsi.asp)
  80  		codn = np.where(emadn == 0, 100, 100-(100/(1+rs)))
  81  		codn = codn.flatten()
  82  		rsi = pd.Series(codn, index=close_val.index)
  83  		rsi = rsi.fillna(40, axis=0)
  84  		rsi = pd.Series(rsi, name='RSI')
  85  
  86  	if arg.indicator == 'Stoch':
  87  		min_periods = 14
  88  		smin = df_stocks['low'].rolling(14, min_periods=min_periods).min()
  89  		smax = df_stocks['high'].rolling(14, min_periods=min_periods).max()
  90  		stoch_k = 100 * (df_stocks['close'] - smin) / (smax - smin) # (https://www.investopedia.com/terms/s/stochasticoscillator.asp)
  91  		stoch_k = stoch_k.fillna(40, axis=0)
  92  		stoch = pd.Series(stoch_k, name='Stochastic')
  93  		stoch_obs = np.arange(1, len(stoch) + 1, 1)
  94  
  95  	if arg.indicator is None:
  96  		raise ValueError("No technical indicator is given, please use correct indicators to proceed")
  97  
  98  # Train and Test Split (With and Without Using Technical Indicators)
  99  if arg.load_all:
 100  	ohlc_avg = np.reshape(OHLC_avg.values, (len(OHLC_avg),1))
 101  	scaler = MinMaxScaler(feature_range=(0,1))
 102  	ohlc_avg_norm = scaler.fit_transform(ohlc_avg)
 103  	
 104  	train_ohlc = int(len(ohlc_avg_norm) * 0.9)
 105  	test_ohlc = len(ohlc_avg_norm) - train_ohlc
 106  	train_ohlc, test_ohlc = ohlc_avg_norm[0:train_ohlc,:], ohlc_avg_norm[train_ohlc:len(OHLC_avg),:]
 107  	x_train, y_train = create_dataset(train_ohlc, 1)
 108  	x_test, y_test = create_dataset(test_ohlc, 1)
 109  
 110  elif arg.indicator == 'RSI':
 111  	RSI_avg = np.reshape(rsi.values, (len(rsi),1))
 112  	scaler = MinMaxScaler(feature_range=(0, 1))
 113  	rsi_avg_norm = scaler.fit_transform(RSI_avg)
 114  
 115  	train_rsi = int(len(rsi_avg_norm) * 0.9)
 116  	test_rsi = len(rsi_avg_norm) - train_rsi
 117  	train_rsi, test_rsi = rsi_avg_norm[0:train_rsi,:], rsi_avg_norm[train_rsi:len(rsi),:]
 118  	x_train, y_train = create_dataset(train_rsi, 1)
 119  	x_test, y_test = create_dataset(test_rsi, 1)
 120  else:
 121  	stoch_avg = np.reshape(stoch.values, (len(stoch),1))
 122  	scaler = MinMaxScaler(feature_range=(0,1))
 123  	stoch_avg_norm = scaler.fit_transform(stoch_avg)
 124  
 125  	train_stoch = int(len(stoch_avg_norm) * 0.9)
 126  	test_stoch = len(stoch_avg_norm) - train_stoch
 127  	train_stoch, test_stoch = stoch_avg_norm[0:train_stoch,:], stoch_avg_norm[train_stoch:len(stoch),:]
 128  	x_train, y_train = create_dataset(train_stoch, 1)
 129  	x_test, y_test = create_dataset(test_stoch, 1)
 130  
 131  # RESHAPING TRAIN AND TEST DATA
 132  x_train = np.reshape(x_train, (x_train.shape[0], 1, x_train.shape[1]))
 133  x_test = np.reshape(x_test, (x_test.shape[0], 1, x_test.shape[1]))
 134  step_size = 1
 135  
 136  # Model
 137  input_shape = (x_train.shape[1], x_train.shape[2])
 138  input_layer = tf.keras.Input(shape=input_shape)
 139  x = tf.keras.layers.GRU(256, input_shape=(1, step_size), return_sequences=True)(input_layer)
 140  x = tf.keras.layers.Dropout(0.4)(x)
 141  x = tf.keras.layers.LSTM(256)(x)
 142  x = tf.keras.layers.Dropout(0.4)(x)
 143  x = tf.keras.layers.Dense(64, activation='relu')(x)
 144  x = tf.keras.layers.Dense(1)(x)
 145  
 146  model = tf.keras.Model(inputs=input_layer, outputs=x)
 147  model.summary()
 148  
 149  # Load saved model or training a new model
 150  if os.path.exists('{}_stock_prices__{}_{}.h5'.format(arg.stock_name, arg.indicator, arg.epoch)):
 151  	history = load_model('{}_stock_prices__{}_{}.h5'.format(arg.stock_name, arg.indicator, arg.epoch))
 152  else:
 153  	model.compile(loss='mse', optimizer='adam', metrics=["mse"])
 154  	history = model.fit(x_train, y_train, epochs=arg.epoch, batch_size=2, verbose=1, validation_data = (x_test,y_test))
 155  	if arg.indicator:
 156  		model.save('{}_stock_prices__{}_{}.h5'.format(arg.stock_name, arg.indicator, arg.epoch)) # save model
 157  	else:
 158  		model.save('{}_stock_prices__{}.h5'.format(arg.stock_name, arg.epoch))
 159  
 160  	plt.plot(history.history['mean_squared_error'])
 161  	plt.plot(history.history['val_mean_squared_error'])
 162  	plt.title('model mean squared error')
 163  	plt.ylabel('accuracy')
 164  	plt.xlabel('epoch')
 165  	plt.legend(['train', 'test'], loc='upper left')
 166  	plt.show()
 167  
 168  	# summarize history for loss
 169  	plt.plot(history.history['loss'])
 170  	plt.plot(history.history['val_loss'])
 171  	plt.title('model loss')
 172  	plt.ylabel('loss')
 173  	plt.xlabel('epoch')
 174  	plt.legend(['train', 'test'], loc='upper left')
 175  	plt.show()
 176  
 177  trainPredict = model.predict(x_train)
 178  testPredict = model.predict(x_test)
 179  
 180  if arg.not_train:
 181  	def model_score(model, x_train, y_train, x_test, y_test):
 182  		trainScore = model.evaluate(x_train, y_train, verbose=0)
 183  		print('Train Score: %.5f MSE (%.2f RMSE)' % (trainScore[0], math.sqrt(trainScore[0])))
 184  		testScore = model.evaluate(x_test, y_test, verbose=0)
 185  		print('Test Score: %.5f MSE (%.2f RMSE)' % (testScore[0], math.sqrt(testScore[0])))
 186  		return trainScore[0], testScore[0]
 187  	model_score(model, x_train, y_train, x_test, y_test)
 188  
 189  # DE-NORMALIZING FOR PLOTTING
 190  trainPredict = scaler.inverse_transform(trainPredict)
 191  y_train = scaler.inverse_transform([y_train])
 192  testPredict = scaler.inverse_transform(testPredict)
 193  y_test = scaler.inverse_transform([y_test])
 194  
 195  # PREDICT FUTURE VALUES
 196  last_val = testPredict[-1]
 197  last_val_scaled = last_val/last_val
 198  next_val = model.predict(np.reshape(last_val_scaled, (1,1,1)))
 199  print("Last Day Value:", np.asscalar(last_val))
 200  print("Next Day Value:", np.asscalar(last_val*next_val))