Share Price Prediction using RNN and LSTM

RishiRajak
Analytics Vidhya
Published in
8 min readJun 28, 2021

--

If you are interested in building an algorithm that can predict a stock’s price trend this might be the page for you.

This article talks about an approach to stock price prediction using deep learning techniques like Recurrent Neural Network and Long Short Term Memory.

We will go through each step of building a deep learning model using RNN and LSTM and check which is more suitable for predicting trends. Anyone with basic
knowledge of deep neural networks can relate to this article easily.

A Deep Learning Approach on Stock’s Share Price Prediction.

Before proceeding to steps, let’s first understand the concept of RNN and LSTM.

RNN:

Recurrent neural networks (RNN) are a class of neural networks that is powerful for modeling sequence data such as time series or natural language. I have used it in predicting stock prices. The logic behind this is that it will remember the price after a particular sequence and the model will gain experience based on that pattern. Schematically, RNN layer uses a for loop to iterate over the timesteps of a sequence, while maintaining an internal state that encodes information about the timesteps it has seen so far. RNN can retain sequence patterns only for a short time thus, we move to LSTM that can remember patterns in Long and Short Term memory.

LSTM:

LSTM is an artificial recurrent neural network architecture used in the field of deep learning. It is preferred over feedforward neural networks because it can memorize the data points over a longer period and hence the name Long Short Term Memory. LSTM network consists of cell, input gate, output gate and a forget gate.
Cell is like a memory that holds values over arbitrary time and three gates regulate that information in and out of the cell.

To get a detailed view of RNN and LSTM, click on the image below:

Data Collection & Preprocessing:

The first thing that we need to do is install yfinance. If you haven’t already installed it yet.

pip install yfinance

Import the yfinance module for collecting data of a particular stock. For our case, we will use Escorts Ltd.

#importing yfinance
import yfinance as yf
#Collecting data
data = yf.download('ESCORTS.NS',period='5y',interval='1d')

Parameters required for yfinance.download() are ticker which is the symbol for your stock; period: total duration for which you want data to be extracted, and interval: which refers to the consecutive records e.g. for 1 day put ‘1d’. This will extract the stock’s data of 5 years for each day excluding the holidays.

Import the following libraries:

import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline

Now that we have collected the data, we need to select the column which is required. Data contains stock’s historical data on Open, Close, Low, High, Volume, and Adjusted Close. We will be using adjusted close for pattern detection and prediction. Also, split the data into train and test set so that we can evaluate our model later.

data_target = data.iloc[:1182,4]
data_test = data.iloc[1132:,4]
steps = 7
#return numpy representation of data
data = data.loc[:,["Adj Close"]].values
test = data[len(data) - len(data_test) - steps:]
#4 the column is Adj Close

Let’s check the trend by visualizing it.

plot = data_target.plot()
Escorts Ltd on NSE

Before, proceeding further we need to define some functions for Scaling Down data and converting data into a set of patterns followed for a particular price.

For scaling down, we will use MinMaxScaler available under ScikitLearn.

#Scaling Dataset
def scaledata(data_target):
#Import scaler and initialise it
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0,1))
#transform by converting it to array and shape of (-1,1)
data_target_scaled = scaler.fit_transform(np.array(data_target).reshape(-1,1))
#plot the scaled version of data
plot_scaled = pd.DataFrame(data_target_scaled).plot()
print(data_target.shape)
#returns scaled data
return data_target_scaled, scaler

Before proceeding to the next function, let’s understand why is it required. By now, we know that RNN retains the pattern for example if you wear red on Sunday, blue on Monday, and green on Tuesday and then repeats it, RNN can retain that pattern for a short time. It can predict that you will wear blue tomorrow if you wear a red t-shirt today. Thus, data must have a pattern to be recognized.

Now, we will build a function that will convert the data into patterns of prices, and the target price achieved after that pattern follows. This way, our model can learn the response of the price patterns.

#Create pattern and end price set
def createPatternSet(data_target_scaled,steps=7):
x_patern = [] #Independent Variable
y_price = [] #Dependent Variable
for day in range(steps,data_target_scaled.shape[0]):
row = data_target_scaled[day-steps:day,0]
#print(len(row))
x_patern.append(row)
y = data_target_scaled[day,0]
#print(y)
y_price.append(y)

x_patern,y_price = np.array(x_patern),np.array(y_price)
#RNN and LSTM takes 3D inputs, we need to change the shape of array to 3 dimensional.
x_patern = x_patern.reshape(x_patern.shape[0],x_patern.shape[1],1) #returns independent and dependent variable sets
return x_patern,y_price

The above function takes data to be converted and the number of steps as steps. By default, we set steps equal to 7 which means that the 7-day pattern and the Price after that will be recorded as independent and dependent variables respectively.

#Scale Down Target
data_target_scaled = scaledata(data_target)[0]
scaler = scaledata(data_target)[1]
#prepare test data
test = data[len(data) - len(data_test) - steps:]
test = scaler.transform(test)

Train and Test Set:

We will use our function to process and build x_train and y_train.

#Overwrite steps to 50. it doesnt really matter here because we will be doing a lot of iterations with it (Take anyhthing less than 100).
train_pattern = createPatternSet(data_target_scaled,steps=50)
x_train = train_pattern[0]
y_train = train_pattern[1]
#Input Shape needs to be 3D.
x_train.shape
>>> (1132, 50, 1)

We finished building our train set and we will build the test set.

#create pattern and price for test set.
test_pattern = createPatternSet(test,steps=50)
x_test = test_pattern[0]
y_test = test_pattern[1]
#Dont forget to check the shape of x_test (3D reuired).
x_test.shape

Test data will be used for the model’s evaluation. We will predict the values based on the x_test and then compare them to the original y_test value.

So, far we have completed data preprocessing, and now the interesting part.

Model Architecture:

We will define a class with methods that can build the architecture, compile it, and fit it on given data. The class will also have methods to set parameters like the number of neurons, batch_size, and epoch. The reason to build this class is that we can run a for loop with the different parameters passed and analyze the result. This will help the readers in trying other combinations of hyperparameters.

Later on, we can also inherit from this class for LSTM and overwrite the architecture building method. There are other options available for hyper tuning the model but we stick to this for the most basic understanding.

Build the Class for RNN:

By default the model’s architecture contains the following layers:

Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_44 (SimpleRNN) (None, 50, 50) 2600
_________________________________________________________________
dropout_32 (Dropout) (None, 50, 50) 0
_________________________________________________________________
simple_rnn_45 (SimpleRNN) (None, 50, 50) 5050
_________________________________________________________________
dropout_33 (Dropout) (None, 50, 50) 0
_________________________________________________________________
simple_rnn_46 (SimpleRNN) (None, 50, 50) 5050
_________________________________________________________________
dropout_34 (Dropout) (None, 50, 50) 0
_________________________________________________________________
simple_rnn_47 (SimpleRNN) (None, 50) 5050
_________________________________________________________________
dropout_35 (Dropout) (None, 50) 0
_________________________________________________________________
dense_19 (Dense) (None, 1) 51
=================================================================
Total params: 17,801
Trainable params: 17,801
Non-trainable params: 0

For compilation, I have used Adam and for loss function Mean Squared Error.

Build the Class for LSTM:

Inherit the previous class’ attribute and overwrite the architecture.

class LstmModel(StocksPriceRNN):
StocksPriceRNN.model = tf.keras.Sequential()
def __init__(self,x_train,y_train,epoch):
super().__init__(x_train,y_train,epoch)

def buildArchitecture(self,dense=1):
StocksPriceRNN.model = tf.keras.Sequential()
StocksPriceRNN.model.add(tf.keras.layers.LSTM(
StocksPriceRNN.neurons,
input_shape=(None,1)))
#Output
StocksPriceRNN.model.add(tf.keras.layers.Dense(units=1))
return StocksPriceRNN.model.summary()

Visualization:
Next, we build a function to plot the validation curves.

def plotting(org_vals,output):
plt.figure(figsize=(10,5), dpi=80, facecolor='w', edgecolor='k')
plt.plot(org_vals,color="Green",label="Org value")
plt.plot(output,color="Yellow",label="Predicted")
plt.legend()
plt.xlabel("Days")
plt.ylabel("Price")
plt.grid(True)
plt.show()

That was a lot of work but we have built the pieces of our algorithm and the only thing left is to put them together.

Iterations & Evaluations:

First, we will iterate on RNN and then on LSTM. The best output of both will be compared for the evaluation.

Build a For-Loop statement for passing different epochs and batch sizes. Run the model on the data and visualize the output:

for steps in [7,30,90]:
for epoch in [20,30,50]:
#prepare train data
train_pattern = createPatternSet(data_target_scaled,steps=steps)
#prepare test data
test = data[len(data) - len(data_test) - steps:]
test = scaler.transform(test)
test_pattern = createPatternSet(inputs,steps=steps)
x_test = test_pattern[0]
y_test = test_pattern[1]
#Build Model
RNN1 = StocksPriceRNN(x_train,y_train,epoch)
RNN1.buildArchitecture(2,0)
RNN1.compiler()
#fit model
history = RNN1.modelfit()
#Predict Values
pred = RNN1.model.predict(x=x_test)
output = scaler.inverse_transform(pred)
org_vals = scaler.inverse_transform(y_test)
#visualise
print("Plotting for Steps {} and Epoch {}".format(steps,epoch))
plotting(org_vals,output)

This will output in 9 iterations. After comparing the iterations, I found that RNN gives sloppy but comparatively best results on a combination of 90–30 and 90–50 (steps-epoch).

Here is the Output:

RNN: Plotting for Steps 90 and Epoch 50

Not much difference between 30–50 epoch but accuracy can increase on the increase of epochs.

Similarly, we run iterations for LSTM:
Please note that there will be some warnings related to “out of calls” and this is natural as we have split the test data with 100 records only. To avoid this, Make sure that experimental_relax_shapes=True, an option that relaxes argument shapes that can avoid unnecessary retracing (not necessarily required).

# for different epochs, batch size, and neurons/units. 
for epch in [60,100,200]:
for batch in [2,4,6]:
for neurons in [8,10,12]:
LSTM2 = LstmModel(x_train,y_train,epoch=epch)
LSTM2.changeBatchSize(batch)
LSTM2.changeNeurons(neurons)
LSTM2.buildArchitecture()
LSTM2.compiler()
history = LSTM2.modelfit()
pred = LSTM2.model.predict(x_test)
pred = scaler.inverse_transform(pred)
#org = scaler.inverse_transform(y_test)
print("For epch {}, neurons {} and batch {}".format(epch,neurons,batch))
plotting(org,pred)

The output will contain 27 iterations.

Analyzing the output of LSTM, it is clear that LSTM performs better on the dataset than the RNN. LSTM gave better results at batch_size = 2, units = 10 and epoch = 200.

Here is the output:

LSTM

EndNote:
The model that we have built is capable of a lot more iterations. We have only tried a few of them and still managed to get closer to the original price curve. Go ahead! and try other hyperparameters on your own, since we have built a class instance we can do a lot of modifications without writing the whole code or making changes to the same one.

Here’s the complete code:
https://www.kaggle.com/rishirajak/share-price-prediciton-using-lstm-and-rnn

Thank you for reading my work.

--

--