Predicting an Oil and Gas company’s stocks using AI (Recurrent Neural Networks): a Keras implementation

Aleem
Analytics Vidhya
Published in
4 min readJan 1, 2020

Stock market is a bridge between a country’s economics and the citizens of the particular country. Condition of stock market is related to the health of a country’s economy but at the same time it allows a common man to take part in this market. Stock market contains shares of the big and small companies that reside in a particular country and the citizens can do business by buying shares at a low price and selling them at a profit when the share price rises. However, here’s the catch: huge losses are incurred when the share prices plummet. Therefore, it might not come as a surprise, that people invested in the stock market carry out dozens of calculations before spending a penny. However, thankfully the rise of AI has led to a solution to this problem as AI performs exceptionally well with less human input. Not only that, AI techniques like Recurrent Neural Networks (RNN) can make predictions by taking in decades of data. To illustrate this, this article uses RNNs to make predictions on Schlumberger’s stock (An Oil and Gas Service Company) from 2010 to 2019.

Disclaimer: This is an intermediate to advanced level AI article. Knowledge about Neural Networks, RNNs and Python language is a must.

What are RNNs?

RNNs are a type of Neural networks which are in turn a subset of machine learning techniques. Unlike simple neural networks, RNNs take into account the past state as well as the current state of a particular neuron. In simpler terms, an RNN not only learns from the current data but also from the past data. If the RNN is bi-directional, the network learns from the present, past as well as the future data. The terms are loosely used here for simplicity. Readers are advised to learn more about RNNs through other sources such as Andrew Ng’s Deep Learning specialization.

There are several types of RNNs. The most famous ones are GRU and LSTM. Although there is no conclusive verdict on which one is better, both of them are used widely today. For our application we’ll use an LSTM.

LSTM unit

Implementation

The first step is to gather the data. I gathered the 10 years stock market data from Nasdaq’s official website. The data is in the csv format and the code to visualize is shown below:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import csv
time_step = []
temps = []
with open('HistoricalQuotes(1).csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
next(reader)
step=0
for row in reader:
val=row[1]
temps.append(float(val[2:]))
time_step.append(step)
step = step + 1
series = np.array(temps)
time = np.array(time_step)
plt.figure(figsize=(10, 6))
plot_series(time, series)

HistoricalQuotes(1).csv contains the stock market data. The reader separates each row wherever there is a comma. The second value (i.e first index) is the closing price of the share. The first character which is a dollar sign is omitted by using val[2:]. The plot_series function is shown below:

def plot_series(time, series, format="-", start=0, end=None):
plt.plot(time[start:end], series[start:end], format)
plt.xlabel("Time")
plt.ylabel("Value")
plt.grid(True)
plt.show()

The data is shown below:

Schlumberger’s stock for the past 10 years

The data is split into training and validation set. The data is split at the 1800th timestep mark.

split_time = 1800
time_train = time[:split_time]
x_train = series[:split_time]
time_valid = time[split_time:]
x_valid = series[split_time:]

The input to the RNN is in the form of windowed series. This is necessary so that the network sees a chunk of the data not just one datapoint.

def windowed_dataset(series, window_size, batch_size, shuffle_buffer):
series = tf.expand_dims(series, axis=-1)
ds = tf.data.Dataset.from_tensor_slices(series)
ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size + 1))
ds = ds.shuffle(shuffle_buffer)
ds = ds.map(lambda w: (w[:-1], w[1:]))
return ds.batch(batch_size).prefetch(1)
def model_forecast(model, series, window_size):
ds = tf.data.Dataset.from_tensor_slices(series)
ds = ds.window(window_size, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size))
ds = ds.batch(32).prefetch(1)
forecast = model.predict(ds)
return forecast
tf.keras.backend.clear_session()
np.random.seed(51)
window_size = 64
batch_size = 256
shuffle_buffer_size=1000
train_set = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size)

Up till now we have prepared the data. The next step is to prepare the model. The model we use has the following sequence:

Conv2d -> LSTM -> LSTM -> Dense -> Dense-> Dense -> Lambda

model = tf.keras.models.Sequential([
tf.keras.layers.Conv1D(filters=60, kernel_size=5,
strides=1, padding="causal",
activation="relu",
input_shape=[None, 1]),
tf.keras.layers.LSTM(60, return_sequences=True),
tf.keras.layers.LSTM(60, return_sequences=True),
tf.keras.layers.Dense(30, activation="relu"),
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(1),
tf.keras.layers.Lambda(lambda x: x * 400)
])

We will use Stochastic Gradient Descent (SGD) with momentum as our optimizer and Huber as our loss function trained at 100 epochs. The metric is Mean Absolute Error (MAE).

optimizer = tf.keras.optimizers.SGD(lr=1e-6, momentum=0.9)
model.compile(loss=tf.keras.losses.Huber(),
optimizer=optimizer,
metrics=["mae"])
history = model.fit(train_set,epochs=100)

The model is trained for 100 epochs and then predictions are made on the validation set. The true values (blue line) and the predicted values (orange line) are shown on the same graph for comparison.

The MAE is as small as 1.49 which is a great result given the sporadic and fickle nature of the oil and gas industry.

This code was inspired by the Tensorflow Specialization by Deeplearning.ai

--

--