In [1]:
import math
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM,Dense,Dropout

import random
import torch
from torch import nn
from torch.autograd import Variable 
pd.options.mode.chained_assignment = None

plt.style.use('fivethirtyeight') # or seaborn
Using TensorFlow backend.

Stock Prediction¶

Get the stock data from yfinance

In [2]:
# Get the stock data
df = yf.download('AMZN', 
                      start='2018-01-01', 
                      end='2022-08-28')
print(df.shape)
df.head()
[*********************100%***********************]  1 of 1 completed
(1172, 6)
Out[2]:
Open High Low Close Adj Close Volume
Date
2018-01-02 58.599998 59.500000 58.525501 59.450500 59.450500 53890000
2018-01-03 59.415001 60.274502 59.415001 60.209999 60.209999 62176000
2018-01-04 60.250000 60.793499 60.233002 60.479500 60.479500 60442000
2018-01-05 60.875500 61.457001 60.500000 61.457001 61.457001 70894000
2018-01-08 61.799999 62.653999 61.601501 62.343498 62.343498 85590000

We plot the dataset!

In [7]:
plt.figure(figsize=(16,8))
plt.plot(df.Close)
plt.ylabel('Closing price', fontsize=18)
plt.xlabel('Date', fontsize=18)
plt.show()
No description has been provided for this image
In [8]:
#plt.style.use('ggplot')
plt.style.use('fivethirtyeight')
df['Volume'].plot(label='CLOSE', title='Amazon')
Out[8]:
<AxesSubplot:title={'center':'Amazon'}, xlabel='Date'>
No description has been provided for this image

Predicting the following day, based on the previous 60 days¶

We first create our dataframe

In [3]:
# Create new dataframe with only close column
data = df.filter(['Close'])

# Save it as a numpy array
dataset = np.array(data)

# Get the number of rows to train the model
train_data_len = math.ceil(len(dataset) * 0.8) # we multiply by 0.8 to get a 80-20 train-test model

print(train_data_len)
938

We then have to normalize the data

In [4]:
# Scale/normalize the data, since neuron takes only values between [0,1]

scaler = MinMaxScaler(feature_range=(0,1))
scaled_data = scaler.fit_transform(dataset)

scaled_data
Out[4]:
array([[0.        ],
       [0.00597466],
       [0.00809471],
       ...,
       [0.58487654],
       [0.61225221],
       [0.56088343]])

Now our implementation with

Keras:¶

We create the training dataset:

In [5]:
# Create the training dataset
train_data = scaled_data[0:train_data_len, :] # Splitting the 80% training data, with all the column 'Close'

# Split the training data into x_train and y_train
x_train = []  
y_train = []

for i in range(60,len(train_data)): # We're using the past 60 days to preditct the stock price
    x_train.append(train_data[i-60:i,0]) 
    y_train.append(train_data[i,0])
    if i <= 62:
        print(x_train) 
        print(y_train)
        print('\n')
x_train, y_train = np.array(x_train), np.array(y_train)
[array([0.        , 0.00597466, 0.00809471, 0.0157843 , 0.02275801,
       0.02505112, 0.02569225, 0.03448316, 0.04570093, 0.04556715,
       0.04168895, 0.04102816, 0.04152373, 0.05439743, 0.0682544 ,
       0.06627599, 0.0743156 , 0.08379485, 0.08994259, 0.09786421,
       0.10300505, 0.07905522, 0.0947687 , 0.07905522, 0.09983872,
       0.08958855, 0.06351873, 0.05923146, 0.07757238, 0.08869574,
       0.10306795, 0.1072805 , 0.10213972, 0.10987259, 0.1156034 ,
       0.11655521, 0.12232143, 0.13095503, 0.1270335 , 0.12721836,
       0.11974513, 0.12241974, 0.1316079 , 0.13712637, 0.14002124,
       0.1427195 , 0.1533512 , 0.1610211 , 0.15700517, 0.15811441,
       0.15470026, 0.15051526, 0.13999369, 0.15634834, 0.15451937,
       0.13998979, 0.12057505, 0.14429279, 0.12116112, 0.09534691])]
[0.10160869078816598]


[array([0.        , 0.00597466, 0.00809471, 0.0157843 , 0.02275801,
       0.02505112, 0.02569225, 0.03448316, 0.04570093, 0.04556715,
       0.04168895, 0.04102816, 0.04152373, 0.05439743, 0.0682544 ,
       0.06627599, 0.0743156 , 0.08379485, 0.08994259, 0.09786421,
       0.10300505, 0.07905522, 0.0947687 , 0.07905522, 0.09983872,
       0.08958855, 0.06351873, 0.05923146, 0.07757238, 0.08869574,
       0.10306795, 0.1072805 , 0.10213972, 0.10987259, 0.1156034 ,
       0.11655521, 0.12232143, 0.13095503, 0.1270335 , 0.12721836,
       0.11974513, 0.12241974, 0.1316079 , 0.13712637, 0.14002124,
       0.1427195 , 0.1533512 , 0.1610211 , 0.15700517, 0.15811441,
       0.15470026, 0.15051526, 0.13999369, 0.15634834, 0.15451937,
       0.13998979, 0.12057505, 0.14429279, 0.12116112, 0.09534691]), array([0.00597466, 0.00809471, 0.0157843 , 0.02275801, 0.02505112,
       0.02569225, 0.03448316, 0.04570093, 0.04556715, 0.04168895,
       0.04102816, 0.04152373, 0.05439743, 0.0682544 , 0.06627599,
       0.0743156 , 0.08379485, 0.08994259, 0.09786421, 0.10300505,
       0.07905522, 0.0947687 , 0.07905522, 0.09983872, 0.08958855,
       0.06351873, 0.05923146, 0.07757238, 0.08869574, 0.10306795,
       0.1072805 , 0.10213972, 0.10987259, 0.1156034 , 0.11655521,
       0.12232143, 0.13095503, 0.1270335 , 0.12721836, 0.11974513,
       0.12241974, 0.1316079 , 0.13712637, 0.14002124, 0.1427195 ,
       0.1533512 , 0.1610211 , 0.15700517, 0.15811441, 0.15470026,
       0.15051526, 0.13999369, 0.15634834, 0.15451937, 0.13998979,
       0.12057505, 0.14429279, 0.12116112, 0.09534691, 0.10160869])]
[0.10160869078816598, 0.07197138472795855]


[array([0.        , 0.00597466, 0.00809471, 0.0157843 , 0.02275801,
       0.02505112, 0.02569225, 0.03448316, 0.04570093, 0.04556715,
       0.04168895, 0.04102816, 0.04152373, 0.05439743, 0.0682544 ,
       0.06627599, 0.0743156 , 0.08379485, 0.08994259, 0.09786421,
       0.10300505, 0.07905522, 0.0947687 , 0.07905522, 0.09983872,
       0.08958855, 0.06351873, 0.05923146, 0.07757238, 0.08869574,
       0.10306795, 0.1072805 , 0.10213972, 0.10987259, 0.1156034 ,
       0.11655521, 0.12232143, 0.13095503, 0.1270335 , 0.12721836,
       0.11974513, 0.12241974, 0.1316079 , 0.13712637, 0.14002124,
       0.1427195 , 0.1533512 , 0.1610211 , 0.15700517, 0.15811441,
       0.15470026, 0.15051526, 0.13999369, 0.15634834, 0.15451937,
       0.13998979, 0.12057505, 0.14429279, 0.12116112, 0.09534691]), array([0.00597466, 0.00809471, 0.0157843 , 0.02275801, 0.02505112,
       0.02569225, 0.03448316, 0.04570093, 0.04556715, 0.04168895,
       0.04102816, 0.04152373, 0.05439743, 0.0682544 , 0.06627599,
       0.0743156 , 0.08379485, 0.08994259, 0.09786421, 0.10300505,
       0.07905522, 0.0947687 , 0.07905522, 0.09983872, 0.08958855,
       0.06351873, 0.05923146, 0.07757238, 0.08869574, 0.10306795,
       0.1072805 , 0.10213972, 0.10987259, 0.1156034 , 0.11655521,
       0.12232143, 0.13095503, 0.1270335 , 0.12721836, 0.11974513,
       0.12241974, 0.1316079 , 0.13712637, 0.14002124, 0.1427195 ,
       0.1533512 , 0.1610211 , 0.15700517, 0.15811441, 0.15470026,
       0.15051526, 0.13999369, 0.15634834, 0.15451937, 0.13998979,
       0.12057505, 0.14429279, 0.12116112, 0.09534691, 0.10160869]), array([0.00809471, 0.0157843 , 0.02275801, 0.02505112, 0.02569225,
       0.03448316, 0.04570093, 0.04556715, 0.04168895, 0.04102816,
       0.04152373, 0.05439743, 0.0682544 , 0.06627599, 0.0743156 ,
       0.08379485, 0.08994259, 0.09786421, 0.10300505, 0.07905522,
       0.0947687 , 0.07905522, 0.09983872, 0.08958855, 0.06351873,
       0.05923146, 0.07757238, 0.08869574, 0.10306795, 0.1072805 ,
       0.10213972, 0.10987259, 0.1156034 , 0.11655521, 0.12232143,
       0.13095503, 0.1270335 , 0.12721836, 0.11974513, 0.12241974,
       0.1316079 , 0.13712637, 0.14002124, 0.1427195 , 0.1533512 ,
       0.1610211 , 0.15700517, 0.15811441, 0.15470026, 0.15051526,
       0.13999369, 0.15634834, 0.15451937, 0.13998979, 0.12057505,
       0.14429279, 0.12116112, 0.09534691, 0.10160869, 0.07197138])]
[0.10160869078816598, 0.07197138472795855, 0.07986155457201921]


Data Reshaping

In [6]:
# Reshape the data, since LSTM takes 3 dimensional array
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
x_train.shape
Out[6]:
(878, 60, 1)

We can now build our LSTM Model

In [10]:
# Build the LSTM model

model = Sequential()
model.add(LSTM(50, input_shape=(x_train.shape[1],1), 
                return_sequences=True))
model.add(LSTM(50), return_sequences=True)
#model.add(Dense(25))
model.add(LSTM(50))
model.add(Dense(1))
In [ ]:
# Compile model
model.compile(optimizer='adam', loss='mean_squared_error', metrics=['accuracy'])
model.summary()

Model Training

In [ ]:
# Train the model
model.fit(x_train, y_train, batch_size=64, epochs=10)
In [ ]:
# save the model
model.save('best_model/model')
In [7]:
# load the model
from tensorflow import keras
model = keras.models.load_model('best_model/model')

We now test our Keras model¶

We first create our testing dataset

In [8]:
# Testing dataset --- Create a new arrray containing scaled values from index 1543 to 2003
test_data = scaled_data[train_data_len-60: ,:]
x_test = []
y_test = dataset[train_data_len: ,:]

for i in range(60, len(test_data)):
    x_test.append(test_data[i-60:i, 0])

x_test = np.array(x_test)

Some reshape...¶

In [9]:
# Reshape the data
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))

We then test our model¶

In [10]:
# Get the models predicted values
predictions = model.predict(x_test)
predictions = scaler.inverse_transform(predictions)

...and compute the error

In [11]:
# Get the root mean squared error (RSME)
rmse =  np.sqrt( np.mean( predictions - y_test)**2 )
print(rmse)
0.12970665173652846

We plot our results and predictions of the Keras model

In [12]:
# Plot the data
train = data[:train_data_len]
valid = data[train_data_len:]
valid['Predictions'] = predictions

plt.figure(figsize=(16,8))
plt.title(('AMZN stock prediction, RSME =',rmse),fontsize=18)
plt.ylabel('Closing price', fontsize=18)
plt.xlabel('Date', fontsize=18)
plt.plot(train['Close'])
plt.plot(valid[['Close','Predictions']])
plt.legend(['Train','Validation','Predictions'], loc='upper left')
plt.show()
No description has been provided for this image

We can now show our implementation with PyTorch:¶

We split together train and test data

In [14]:
# Create the training and testing dataset
train_data = scaled_data[0:train_data_len, :] # Splitting the 80% training data, with all the column 'Close'
test_data = scaled_data[train_data_len-60: ,:] # Size = 294. We take the 20% left, including days needed to test the first 60 days, they are also part of train_data. So we get the increase in size, from 234 to 294.


# Split the training data into x_train and y_train
x_train = []
y_train = scaled_data[60:train_data_len,:]

x_test = []
y_test = dataset[train_data_len:, :]  # not scaled, we will inverse-transform the predictions later


for i in range(60,len(train_data)): # We're using the past 60 days to preditct the stock price
    x_train.append(train_data[i-60:i,0])

for i in range(60, len(test_data)):     # We start adding where we left in x_train, so the fisrt 60-sequence-long follows the same trend,
    x_test.append(test_data[i-60:i, 0]) # and almost overlap with the last one in x_train: we start from the next index respect to the one
                                        # we started on the last iteration on x_train. 
                                        # Including the previous 60 days in the creation of test_data allows us to test the predictions on all
                                        # the 234 (y_test size) labels/days in y_test. #see following print
                                        

x_train, y_train = np.array(x_train), np.array(y_train)
x_test = np.array(x_test)

print(f'x_train shape: {x_train.shape}') # == (878, 60): we have 878 sequences (of length 60 days) out of 938 = train_data_length. The first 60 days are not usable since there is not enough days/data to train, hence 878 = 938 - 60.
print(f'y_train shape: {y_train.shape}') # labels
print(f'x_test shape: {x_test.shape}')
print(f'y_test shape: {y_test.shape}')
print(f'We overlap the previous 60 days in test_data: {len(y_test)}(labels) = {len(test_data)}(test_data size) - 60(days added)')
x_train shape: (878, 60)
y_train shape: (878, 1)
x_test shape: (234, 60)
y_test shape: (234, 1)
We overlap the previous 60 days in test_data: 234(labels) = 294(test_data size) - 60(days added)

We can show this overlap of train_data and test_data that permits us to test all the 234 labels.

In [15]:
#a = pd.DataFrame(a); #b = pd.DataFrame(b)
a,b = x_train[-1], x_test[0] # We take the last sequence in train and the first in test
i = random.randint(0,51) # Random generate an index in this range

a = a[i+1:i+10] # To visualize it better we only take a slice of the two sequences
b = b[i:i+9]
print(" Train:", a, "\n\n", "Test:", b, "\n\n", a==b)
 Train: [1.         0.99525251 0.99494186 0.97874056 0.98043977 0.9605845
 0.93794059 0.92848499 0.9377675 ] 

 Test: [1.         0.99525251 0.99494186 0.97874056 0.98043977 0.9605845
 0.93794059 0.92848499 0.9377675 ] 

 [ True  True  True  True  True  True  True  True  True]

We then convert arrays to tensors

In [16]:
X_train_tensors = Variable(torch.Tensor(x_train))
X_test_tensors = Variable(torch.Tensor(x_test))

y_train_tensors = Variable(torch.Tensor(y_train))
y_test_tensors = Variable(torch.Tensor(y_test)) 

We need then to convert the tensors to 3-D shape as LSTM takes sequential data, and so timestamp information.
(We will simply use increasing indexes as timestamp info)

In [17]:
#reshaping to rows, timestamps, features

X_train_tensors_final = torch.reshape(X_train_tensors,   (X_train_tensors.shape[0], 1, X_train_tensors.shape[1]))


X_test_tensors_final = torch.reshape(X_test_tensors,  (X_test_tensors.shape[0], 1, X_test_tensors.shape[1]))

print("Training Shape", X_train_tensors_final.shape, y_train_tensors.shape)
print("Testing Shape", X_test_tensors_final.shape, y_test_tensors.shape) 
Training Shape torch.Size([878, 1, 60]) torch.Size([878, 1])
Testing Shape torch.Size([234, 1, 60]) torch.Size([234, 1])

Now we can create our LSTM:

In [18]:
class myLSTM(nn.Module):
    def __init__(self, num_classes, input_size, hidden_size, num_layers, seq_length):
        super(myLSTM, self).__init__()
        self.num_classes = num_classes #number of classes
        self.num_layers = num_layers #number of layers
        self.input_size = input_size #input size
        self.hidden_size = hidden_size #hidden state
        self.seq_length = seq_length #sequence length

        self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size,
                          num_layers=num_layers, batch_first=True) #lstm
        
        # Our dense layer
        self.fc = nn.Linear(hidden_size, num_classes)

        self.relu = nn.ReLU()
    
    def forward(self,x):
        h_0 = Variable(torch.zeros(self.num_layers, x.size(0), self.hidden_size)) #hidden state
        c_0 = Variable(torch.zeros(self.num_layers, x.size(0), self.hidden_size)) #internal state
        
        # Propagate input through LSTM
        output, (hn, cn) = self.lstm(x, (h_0, c_0)) #lstm with input, hidden, and internal state
        
        hn = hn.view(-1, self.hidden_size) #reshaping the data for Dense layer next.    Il -1 in pytorch assume la dimensionalità basandosi su la shape e l'altro moltiplicatore, in questo caso hidden_size
        
        out = self.relu(hn) 
        out = self.fc(out) 
        return out

We define some Global variables...

In [19]:
num_epochs = 1500 #1000 epochs. More than 1500 and it overfits!!!
learning_rate = 0.001 #0.001 lr

input_size = 60 #number of features
hidden_size = 50 #number of features in hidden state
num_layers = 1 #number of stacked lstm layers

num_classes = 1 #number of output classes 

... and instanciate our model

In [20]:
lstm = myLSTM(num_classes, input_size, hidden_size, num_layers, X_train_tensors_final.shape[1]) #our lstm class

We define our loss function and our optimizer

In [21]:
loss_fn = torch.nn.MSELoss()    # mean-squared error for regression
optimizer = torch.optim.Adam(lstm1.parameters(), lr=learning_rate)

We now train our model!

In [22]:
for epoch in range(num_epochs):
  outputs = lstm.forward(X_train_tensors_final) #forward pass
  optimizer.zero_grad() #calculate the gradient, manually setting to 0
  
  # Il modello con keras ha come metrica anche l'accuracy, ho provato a calcolarla anche qua confrontando ouput e labels, ma è un errore. Leggi sotto cosa ho scritto:
  #train_acc = torch.sum(Variable(torch.Tensor(y_train == outputs.detach().numpy()))) # Can't get accuracy in regression models, we just want to see how close the prediction is, useless to know when it predicts the exact value --> overfit!

  # obtain the loss function
  loss = loss_fn(outputs, y_train_tensors)

  loss.backward() #calculates the loss of the loss function

  optimizer.step() #improve from loss, i.e backprop
  
  if epoch % 100 == 0:
    print(f"Epoch: {epoch}, loss: {loss.item()}")
Epoch: 0, loss: 0.3505839705467224
Epoch: 100, loss: 0.003500645514577627
Epoch: 200, loss: 0.002669299952685833
Epoch: 300, loss: 0.0019216921646147966
Epoch: 400, loss: 0.001370133482851088
Epoch: 500, loss: 0.0010127387940883636
Epoch: 600, loss: 0.0007733474485576153
Epoch: 700, loss: 0.0006454678368754685
Epoch: 800, loss: 0.0005669034435413778
Epoch: 900, loss: 0.0005129565251991153
Epoch: 1000, loss: 0.00047219780390150845
Epoch: 1100, loss: 0.00043925177305936813
Epoch: 1200, loss: 0.00042482034768909216
Epoch: 1300, loss: 0.0003953732957597822
Epoch: 1400, loss: 0.0003776254307013005

We now predict

In [23]:
predictions = lstm.forward(X_test_tensors_final)

pred = predictions.detach().numpy() # or can be used: predictions.data.numpy()

predictions = scaler.inverse_transform(pred) # inverse tranform on numpy array like converted from tensor

predictions.shape # check the shape!
Out[23]:
(234, 1)

Actually quite high RMSE compared to the Keras model!

In [24]:
# Get the root mean squared error (RSME)
rmse =  np.sqrt(np.mean(predictions - y_test)**2)
print(rmse)
1.4330431294237447

And we show the results of the pytorch implementation...

In [25]:
# Plot the data
train = data[:train_data_len]
valid = data[train_data_len:]
valid['Predictions'] = predictions

plt.figure(figsize=(16,8))
plt.title(('AMZN stock prediction, RSME =',rmse),fontsize=18)
plt.ylabel('Closing price', fontsize=18)
plt.xlabel('Date', fontsize=18)
plt.plot(train['Close'])
plt.plot(valid[['Close','Predictions']])
plt.legend(['Train','Validation','Predictions'], loc='upper left')
plt.show()
No description has been provided for this image


Predicting the next day¶

In [11]:
# Predict the next day
stock_aapl = yf.download('AAPL', 
                        start='2018-01-01', 
                        end='2022-08-28')

# Create new data frame
new_df = stock_aapl.filter(['Close'])

# Get the last 60 days closing price
last_60_days = new_df[-60:].values

# Scale the data
last_60_days_scaled = scaler.transform(last_60_days)

# Append data to a list
new_x_test = []
new_x_test.append(last_60_days_scaled)
new_x_test = np.array(new_x_test)

# Reshape the date
new_x_test = np.reshape(new_x_test,(new_x_test.shape[0],new_x_test.shape[1],1))

# Get the predicted price
price_pred = model.predict(new_x_test)
price_pred = scaler.inverse_transform(price_pred)

print(price_pred)
[*********************100%***********************]  1 of 1 completed
[[54.147667]]

We split the dataset

In [18]:
df_sample = data
df_sample[:train_data_len] = data[:train_data_len]
df_sample[train_data_len:] = predictions

We have choosen to calculate the simple moving averages

In [19]:
#Create the 30 day simple moving average
SMA30 = df_sample.rolling(window=30).mean()
SMA30
Out[19]:
Close
Date
2018-01-02 NaN
2018-01-03 NaN
2018-01-04 NaN
2018-01-05 NaN
2018-01-08 NaN
... ...
2022-08-22 128.366192
2022-08-23 129.115955
2022-08-24 129.956921
2022-08-25 130.779187
2022-08-26 131.690558

1172 rows × 1 columns

In [20]:
#Create the 100 day simple moving average
SMA100 = df_sample.rolling(window=100).mean()
SMA100
Out[20]:
Close
Date
2018-01-02 NaN
2018-01-03 NaN
2018-01-04 NaN
2018-01-05 NaN
2018-01-08 NaN
... ...
2022-08-22 126.798824
2022-08-23 126.452762
2022-08-24 126.140010
2022-08-25 125.855358
2022-08-26 125.589627

1172 rows × 1 columns

In [21]:
# Visually Show The Stock and The Moving Averages

# Create the title 
title = 'Adj. Close Price History Simple Moving Averages   '
  
#Create and plot the graph
plt.figure(figsize=(16,8))
plt.plot( df_sample[-150:],  label='AMZN')#plt.plot( X-Axis , Y-Axis, line_width, alpha_for_blending,  label)
plt.plot( SMA30[-150:],  label='SMA30')
plt.plot( SMA100[-150:],  label='SMA100')
  
plt.title(title)
plt.xlabel('Oct. 02, 2006 - Dec. 30, 2011 ',fontsize=18)
plt.ylabel('Adj. Price USD ($)',fontsize=18)
plt.legend( loc='upper left')
plt.show()
No description has been provided for this image

We then try to automate the process¶

In [22]:
#Create a function to signal when to buy and sell an asset
def buy_sell(signal):
  sigPriceBuy = []
  sigPriceSell = []
  flag = -1
  for i in range(0,len(signal)):
    #if sma30 > sma100  then buy else sell
      if signal['SMA30'][i] > signal['SMA100'][i]:
        if flag != 1:
          sigPriceBuy.append(signal['Close'][i])
          sigPriceSell.append(np.nan)
          flag = 1
        else:
          sigPriceBuy.append(np.nan)
          sigPriceSell.append(np.nan)
        #print('Buy')
      elif signal['SMA30'][i] < signal['SMA100'][i]:
        if flag != 0:
          sigPriceSell.append(signal['Close'][i])
          sigPriceBuy.append(np.nan)
          flag = 0
        else:
          sigPriceBuy.append(np.nan)
          sigPriceSell.append(np.nan)
        #print('sell')
      else: #Handling nan values
        sigPriceBuy.append(np.nan)
        sigPriceSell.append(np.nan)
  
  return (sigPriceBuy, sigPriceSell)  
In [23]:
#Create a new dataframe
signal = pd.DataFrame(index=df_sample['Close'].index)
signal['Close'] = df_sample['Close']
signal['SMA30'] = SMA30['Close']
signal['SMA100'] = SMA100['Close']
In [24]:
signal
Out[24]:
Close SMA30 SMA100
Date
2018-01-02 59.450500 NaN NaN
2018-01-03 60.209999 NaN NaN
2018-01-04 60.479500 NaN NaN
2018-01-05 61.457001 NaN NaN
2018-01-08 62.343498 NaN NaN
... ... ... ...
2022-08-22 138.406097 128.366192 126.798824
2022-08-23 133.884415 129.115955 126.452762
2022-08-24 134.242996 129.956921 126.140010
2022-08-25 134.358337 130.779187 125.855358
2022-08-26 137.381302 131.690558 125.589627

1172 rows × 3 columns

In [25]:
x = buy_sell(signal)
signal['Buy_Signal_Price'] = x[0]
signal['Sell_Signal_Price'] = x[1]
In [26]:
signal
Out[26]:
Close SMA30 SMA100 Buy_Signal_Price Sell_Signal_Price
Date
2018-01-02 59.450500 NaN NaN NaN NaN
2018-01-03 60.209999 NaN NaN NaN NaN
2018-01-04 60.479500 NaN NaN NaN NaN
2018-01-05 61.457001 NaN NaN NaN NaN
2018-01-08 62.343498 NaN NaN NaN NaN
... ... ... ... ... ...
2022-08-22 138.406097 128.366192 126.798824 NaN NaN
2022-08-23 133.884415 129.115955 126.452762 NaN NaN
2022-08-24 134.242996 129.956921 126.140010 NaN NaN
2022-08-25 134.358337 130.779187 125.855358 NaN NaN
2022-08-26 137.381302 131.690558 125.589627 NaN NaN

1172 rows × 5 columns

In [27]:
# Visually Show The Stock buy and sell signals
# Create the title 
title = 'Adj. Close Price History Buy / Sell Signals   '
#Get the stocks
my_stocks = signal
ticker = 'Close'
  
#Create and plot the graph
plt.figure(figsize=(16,8)) #width = 12.2in, height = 4.5
plt.scatter(my_stocks.index, my_stocks['Buy_Signal_Price'], color = 'green', label='Buy Signal', marker = '^', alpha = 1)
plt.scatter(my_stocks.index, my_stocks['Sell_Signal_Price'], color = 'red', label='Sell Signal', marker = 'v', alpha = 1)
plt.plot( my_stocks[ticker],  label=ticker, alpha = 0.35)#plt.plot( X-Axis , Y-Axis, line_width, alpha_for_blending,  label)
plt.plot( my_stocks['SMA30'],  label='SMA30', alpha = 0.35)
plt.plot( my_stocks['SMA100'],  label='SMA100', alpha = 0.35)
plt.title(title)
plt.xlabel('Date',fontsize=18)
plt.ylabel('Close Price USD ($)',fontsize=18)
plt.legend( loc='upper left')
plt.show()
No description has been provided for this image