IoannisTr commited on
Commit
6f687ac
1 Parent(s): 1b38d94

Upload functions.py

Browse files
Files changed (1) hide show
  1. functions.py +458 -0
functions.py ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from asyncio.constants import LOG_THRESHOLD_FOR_CONNLOST_WRITES
2
+ import yfinance as yf
3
+ import pandas as pd
4
+ import numpy as np
5
+ import plotly.graph_objs as go
6
+ from stocks import *
7
+ from transformers import AutoModelForSequenceClassification, pipeline, AutoTokenizer
8
+ import os
9
+ from random import random
10
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
11
+ import tensorflow as tf
12
+ import math
13
+ import datetime
14
+ import random
15
+ import time
16
+ #import kaleido
17
+ from sklearn.preprocessing import MinMaxScaler
18
+ import matplotlib.pyplot as plt
19
+ #import warnings
20
+ import tensorflow as tf
21
+ from tensorflow import keras
22
+ from keras.layers import Dropout, Activation
23
+ from keras import layers
24
+ from keras.callbacks import EarlyStopping
25
+ from sklearn.metrics import r2_score
26
+ import plotly.graph_objs as go
27
+ import plotly.io as pio
28
+ pio.templates
29
+
30
+ model = AutoModelForSequenceClassification.from_pretrained("fine_tuned_FinBERT", from_tf=False, config="config.json")
31
+ tokenizer = AutoTokenizer.from_pretrained("fine_tuned_FinBERT/tokenizer/")
32
+
33
+ class Models(object):
34
+ def __init__(self):
35
+ self.stock_data = Stock_Data()
36
+
37
+ def bollinger_bands_20d_2std(self, ticker):
38
+ '''
39
+ This method calculates the Bollinger Bands with a Rolling average of the last 20 days and 2 standard deviations. In a plot,
40
+ this would be represented as 3 lines: a rolling average, an upper bound (rolling average + 2 standard deviations) and a lower
41
+ bound (rolling average - 2 standard deviations). When the price of a stock is between the rolling average and lower bound, it is
42
+ considered as oversold, so it makes sense to buy, if it is between the roll. avg. and the upper bound, it is considered as
43
+ overbought, so it makes sense to sell, if it is equal to the roll.avg. it is neutral and if it is outside the bounds, it is
44
+ considered an Unusual Event. The function returns the outlook of the stock (either "Buy", or "Sell" or "Hold" or "Unusual Event")
45
+ '''
46
+ if self.stock_data.status_getter(ticker) != "Open":
47
+ return "Market Closed"
48
+ else:
49
+ data = self.stock_data.stock_data_getter(ticker)
50
+ low_high_closing_df = pd.DataFrame(data)
51
+ low_high_closing_df = data.iloc[:, 4:5] # Getting only the "Adj Close" column
52
+ low_high_closing_df = low_high_closing_df.tail(40) # Getting the last 40 days
53
+
54
+ low_high_closing_df["rolling_avg_20d"] = low_high_closing_df['Adj Close'].rolling(20, min_periods = 20).mean()
55
+ low_high_closing_df["sd"] = low_high_closing_df["Adj Close"].rolling(20, min_periods = 20).std()
56
+ low_high_closing_df = low_high_closing_df.tail(20) # Keeping the last 20 days only
57
+
58
+ recent_data = low_high_closing_df.iloc[-1, :].to_list() # Creating a Series object with the most recent data (last row only)
59
+
60
+ upper_bound = recent_data[1] + 2*recent_data[2] # Upper Bound
61
+ lower_bound = recent_data[1] - 2*recent_data[2] # Lower Bound
62
+ mean_20d = recent_data[1] # Rolling average of last 20 days
63
+
64
+ if self.stock_data.current_price_getter(ticker) is None:
65
+ return "Market Closed"
66
+ else:
67
+ message = ""
68
+
69
+ if self.stock_data.current_price_getter(ticker) < mean_20d and self.stock_data.current_price_getter(ticker) >= lower_bound:
70
+ message = "Buy"
71
+ elif self.stock_data.current_price_getter(ticker) > mean_20d and self.stock_data.current_price_getter(ticker) <= upper_bound:
72
+ message = "Sell"
73
+ elif self.stock_data.current_price_getter(ticker) == mean_20d:
74
+ message = "Hold"
75
+ elif self.stock_data.current_price_getter(ticker) <= lower_bound or self.stock_data.current_price_getter(ticker) >= upper_bound:
76
+ message = "Unusual Event"
77
+ return message
78
+
79
+ def bollinger_bands_10d_1point5std(self, ticker):
80
+ '''
81
+ This method calculates the Bollinger Bands with a Rolling average of the last 10 days and 1.5 standard deviations. In a plot,
82
+ this would be represented as 3 lines: a rolling average, an upper bound (rolling average + 1.5 standard deviations) and a lower
83
+ bound (rolling average - 1.5 standard deviations). When the price of a stock is between the rolling average and lower bound, it is
84
+ considered as oversold, so it makes sense to buy, if it is between the roll. avg. and the upper bound, it is considered as
85
+ overbought, so it makes sense to sell, if it is equal to the roll.avg. it is neutral and if it is outside the bounds, it is
86
+ considered an Unusual Event. The function returns the outlook of the stock (either "Buy", or "Sell" or "Hold" or "Unusual Event")
87
+ '''
88
+ if self.stock_data.status_getter(ticker) != "Open":
89
+ return "Market Closed"
90
+ else:
91
+ data = self.stock_data.stock_data_getter(ticker)
92
+
93
+ low_high_closing_df = pd.DataFrame(data)
94
+ low_high_closing_df = data.iloc[:, 4:5] # Getting only the "Adj Close" column
95
+ low_high_closing_df = low_high_closing_df.tail(20) # Getting the last 20 days
96
+
97
+ low_high_closing_df["rolling_avg_10d"] = low_high_closing_df['Adj Close'].rolling(10, min_periods = 10).mean()
98
+ low_high_closing_df["sd"] = low_high_closing_df["Adj Close"].rolling(10, min_periods = 10).std()
99
+ low_high_closing_df = low_high_closing_df.tail(10) # Keeping the last 10 days only
100
+
101
+ recent_data = low_high_closing_df.iloc[-1, :].to_list() # Creating a Series object with the most recent data (last row only)
102
+
103
+ upper_bound = recent_data[1] + 1.5*recent_data[2] # Upper Bound
104
+ lower_bound = recent_data[1] - 1.5*recent_data[2] # Lower Bound
105
+ mean_10d = recent_data[1] # Rolling average of last 10 days
106
+
107
+ if self.stock_data.current_price_getter(ticker) is None:
108
+ return "Market Closed"
109
+ else:
110
+ message = ""
111
+
112
+ if self.stock_data.current_price_getter(ticker) < mean_10d and self.stock_data.current_price_getter(ticker) >= lower_bound:
113
+ message = "Buy"
114
+ elif self.stock_data.current_price_getter(ticker) > mean_10d and self.stock_data.current_price_getter(ticker) <= upper_bound:
115
+ message = "Sell"
116
+ elif self.stock_data.current_price_getter(ticker) == mean_10d:
117
+ message = "Hold"
118
+ elif self.stock_data.current_price_getter(ticker) <= lower_bound or self.stock_data.current_price_getter(ticker) >= upper_bound:
119
+ message = "Unusual Event"
120
+ return message
121
+
122
+ def bollinger_bands_50d_3std(self, ticker):
123
+ '''
124
+ This method calculates the Bollinger Bands with a Rolling average of the last 50 days and 3 standard deviations. In a plot,
125
+ this would be represented as 3 lines: a rolling average, an upper bound (rolling average + 3 standard deviations) and a lower
126
+ bound (rolling average - 3 standard deviations). When the price of a stock is between the rolling average and lower bound, it is
127
+ considered as oversold, so it makes sense to buy, if it is between the roll. avg. and the upper bound, it is considered as
128
+ overbought, so it makes sense to sell, if it is equal to the roll.avg. it is neutral and if it is outside the bounds, it is
129
+ considered an Unusual Event. The function returns the outlook of the stock (either "Buy", or "Sell" or "Hold" or "Unusual Event")
130
+ '''
131
+ if self.stock_data.status_getter(ticker) != "Open":
132
+ return "Market Closed"
133
+ else:
134
+ data = self.stock_data.stock_data_getter(ticker)
135
+
136
+ low_high_closing_df = pd.DataFrame(data)
137
+ low_high_closing_df = data.iloc[:, 4:5] # Getting only the "Adj Close" column
138
+ low_high_closing_df = low_high_closing_df.tail(100) # Getting the last 100 days
139
+
140
+ low_high_closing_df["rolling_avg_50d"] = low_high_closing_df['Adj Close'].rolling(50, min_periods = 50).mean()
141
+ low_high_closing_df["sd"] = low_high_closing_df["Adj Close"].rolling(50, min_periods = 50).std()
142
+ low_high_closing_df = low_high_closing_df.tail(50) # Keeping the last 50 days only
143
+
144
+ recent_data = low_high_closing_df.iloc[-1, :].to_list() # Creating a Series object with the most recent data (last row only)
145
+
146
+ upper_bound = recent_data[1] + 3*recent_data[2] # Upper Bound
147
+ lower_bound = recent_data[1] - 3*recent_data[2] # Lower Bound
148
+ mean_50d = recent_data[1] # Rolling average of last 50 days
149
+
150
+ # Finding the outlook dependent on the current price
151
+ if self.stock_data.current_price_getter(ticker) is None:
152
+ return "Market Closed"
153
+ else:
154
+ message = ""
155
+ if self.stock_data.current_price_getter(ticker) < mean_50d and self.stock_data.current_price_getter(ticker) >= lower_bound:
156
+ message = "Buy"
157
+ elif self.stock_data.current_price_getter(ticker) > mean_50d and self.stock_data.current_price_getter(ticker) <= upper_bound:
158
+ message = "Sell"
159
+ elif self.stock_data.current_price_getter(ticker) == mean_50d:
160
+ message = "Hold"
161
+ elif self.stock_data.current_price_getter(ticker) <= lower_bound or self.stock_data.current_price_getter(ticker) >= upper_bound:
162
+ message = "Unusual Event"
163
+ return message
164
+
165
+ def MACD(self, ticker):
166
+ '''
167
+ This method calculates the MACD (Mean Average Convergence Divergence) for a stock. The decision of whether to buy or sell
168
+ a stock when using this method, depends on the difference of two "lines". The 1st one is called "MACD" and is equal to the
169
+ difference between the Exponential Moving Average of the adjusted closing price of the last 12 days, and the Moving Average
170
+ of the adjusted closing price of the last 26 days. The 2nd line is the 9 day moving average of the adj. closing price.
171
+ When MACD > 9 day M.A. it is considered that there is an uptrend, else, an downtrend.
172
+ At last, when MACD line crosses the 9 day M.A. from "above", a "Sell" signal is given,
173
+ while it crosses it from below, a "Buy" signal is given.
174
+ '''
175
+ if self.stock_data.status_getter(ticker) != "Open":
176
+ return "Market Closed"
177
+ else:
178
+ data = self.stock_data.stock_data_getter(ticker)
179
+
180
+ low_high_closing_df = pd.DataFrame(data)
181
+ low_high_closing_df = data.iloc[:, 4:5] # Getting only the "Adj Close" column
182
+ low_high_closing_df = low_high_closing_df.tail(52) # Getting the last 52 days
183
+
184
+
185
+ # Get the 12-day EMA of the closing price
186
+ low_high_closing_df['EMA_12d'] = low_high_closing_df['Adj Close'].ewm(span=12, adjust=False, min_periods=12).mean()
187
+ # Get the 26-day MA of the closing price
188
+ low_high_closing_df['MA_26d'] = low_high_closing_df['Adj Close'].ewm(span=26, adjust=False, min_periods=26).mean()
189
+ # Subtract the 26-day EMA from the 12-Day EMA to get the MACD
190
+ low_high_closing_df['MACD'] = low_high_closing_df['EMA_12d'] - low_high_closing_df['MA_26d']
191
+ # Making the signal line
192
+ low_high_closing_df['MA_9d'] = low_high_closing_df['MACD'].ewm(span=9, adjust=False, min_periods=9).mean()
193
+
194
+ low_high_closing_df['Diff'] = low_high_closing_df['MACD'] - low_high_closing_df['MA_9d']
195
+
196
+ Diff = low_high_closing_df['Diff'].astype(float)
197
+
198
+ if self.stock_data.current_price_getter(ticker) is None:
199
+ return "Market Closed"
200
+ else:
201
+ message = ""
202
+
203
+ if Diff.iloc[-1] < 0:
204
+ if Diff.iloc[-2] >= 0:
205
+ message = "Downtrend and sell signal"
206
+ else:
207
+ message = "Downtrend and no signal"
208
+ else:
209
+ if Diff.iloc[-2] <= 0:
210
+ message = "Uptrend and buy signal"
211
+ else:
212
+ message = "Uptrend and no signal"
213
+ return message
214
+
215
+ def finbert_headlines_sentiment(self, ticker):
216
+ '''
217
+ This method uses a the "weights" and the "tokenizer" of a fine-tuned Fin-BERT model, which is a BERT model that
218
+ was furtherly trained on financial data. The "article_parser()" method scraps www.marketwatch.com and returns the
219
+ last 17 headers of the chosen stock's articles. The, the FinBERT model classifies each one of them as either "Positive"
220
+ or "Negative" or "Neutral", and a score is assigned to each header (+100, -100, and 0) correspondingly. At last, a
221
+ rolling average of window size = 5 is used to "smooth" the sentiment line of the "plotly" plot that is returned.
222
+ '''
223
+
224
+ articles_df = self.stock_data.article_parser(ticker)
225
+ articles_list = articles_df["headline"].tolist()
226
+
227
+ clf = pipeline("text-classification", model=model, tokenizer=tokenizer)
228
+ outputs_list = clf(articles_list)
229
+
230
+ sentiments = []
231
+
232
+ for item in outputs_list:
233
+ sentiments.append(item["label"])
234
+
235
+ sentiments_df = pd.DataFrame(sentiments)
236
+ sentiments_df.rename(columns = {0:'sentiment'}, inplace = True)
237
+
238
+ sentiments_df["sentiment"] = sentiments_df["sentiment"].apply(lambda x: 100 if x == "positive" else -100 if x=="negative" else 0)
239
+ sentiments_df["roll_avg"] = round(sentiments_df["sentiment"].rolling(5, min_periods = 1).mean(), 2)
240
+ sentiments_df = sentiments_df.tail(12).reset_index()
241
+
242
+ pd.options.plotting.backend = "plotly"
243
+
244
+ fig = sentiments_df["roll_avg"].plot(title="Sentiment Analysis of the last 12 www.marketwatch.com articles about " + ticker,
245
+
246
+ template="plotly_dark",
247
+ labels=dict(index="12 most recent article headlines", value="sentiment score (rolling avg. of window size 5)"))
248
+ fig.update_traces(line=dict(color="#3D9140", width=3))
249
+ fig.update_layout(yaxis_range=[-100,100])
250
+ fig.update_layout(xaxis_range=[0,12])
251
+ fig.update_layout(showlegend=False)
252
+ fig.add_hline(y=0, line_width=1.5, line_color="black")
253
+
254
+ current_sentiment = sentiments_df["roll_avg"].tail(1).values[0]
255
+
256
+ return {'fig': fig, 'current_sentiment': current_sentiment}
257
+
258
+ def LSTM_7_days_price_predictor(self, ticker):
259
+ '''
260
+ This method predicts the price of a chosen stock for the next 7 days as of today, by using the daily adjusted closing
261
+ prices for the last 2 years. At first, a 60-day window of historical prices (i-60) is created as our feature data (x_train)
262
+ and the following 60-days window as label data (y_train). For every stock available, we have manually defined different
263
+ parameters so that they fit as good as it gets to the model. Finally we combute the R2 metric and make the predictions. At
264
+ last, we proceed with the predictions. The model looks back in our data (60 days back) and predicta for the following 7 days.
265
+ '''
266
+
267
+ stock_data = self.stock_data.LSTM_stock_data_getter(ticker)
268
+ stock_data=pd.DataFrame(data=stock_data).drop(['Open','High','Low','Close', 'Volume'],axis=1).reset_index()
269
+ stock_data['Date'] = pd.to_datetime(stock_data['Date'])
270
+ stock_data=stock_data.dropna()
271
+
272
+ # Data Preprocessing
273
+ random.seed(1997)
274
+ close_prices = stock_data['Adj Close']
275
+ values = close_prices.values
276
+ training_data_len = math.ceil(len(values)* 0.8)
277
+
278
+ scaler = MinMaxScaler(feature_range=(0,1))
279
+ scaled_data = scaler.fit_transform(values.reshape(-1,1))
280
+ train_data = scaled_data[0: training_data_len, :]
281
+
282
+ x_train = []
283
+ y_train = []
284
+
285
+ for i in range(60, len(train_data)):
286
+ x_train.append(train_data[i-60:i, 0])
287
+ y_train.append(train_data[i, 0])
288
+
289
+ x_train, y_train = np.array(x_train), np.array(y_train)
290
+ x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
291
+
292
+ # Preparation of test set
293
+ test_data = scaled_data[training_data_len-60: , : ]
294
+ x_test = []
295
+ y_test = values[training_data_len:]
296
+
297
+ for i in range(60, len(test_data)):
298
+ x_test.append(test_data[i-60:i, 0])
299
+
300
+ x_test = np.array(x_test)
301
+ x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))
302
+
303
+ ##### Setting Up LSTM Network Architecture and the Training of the LSTM Model
304
+ def LSTM_trainer(seed, DROPOUT, LSTM_units,patience,batch_size, epochs):
305
+
306
+ tf.random.set_seed(seed)
307
+ DROPOUT = DROPOUT
308
+ global model_lstm
309
+ model_lstm = keras.Sequential()
310
+ model_lstm.add(layers.LSTM(LSTM_units, return_sequences=True, input_shape=(x_train.shape[1], 1)))
311
+ model_lstm.add(Dropout(rate=DROPOUT))
312
+ model_lstm.add(layers.LSTM(LSTM_units, return_sequences=False))
313
+ model_lstm.add(Dropout(rate=DROPOUT))
314
+ model_lstm.add(layers.Dense(25))
315
+ model_lstm.add(Dropout(rate=DROPOUT))
316
+ model_lstm.add(layers.Dense(1))
317
+ model_lstm.add(Activation('linear'))
318
+
319
+ print('\n')
320
+ print("Compiling the LSTM Model for the " + str(ticker) + " stock....\n")
321
+ t0 = time.time()
322
+ model_lstm.compile(optimizer='adam', loss='mean_squared_error',metrics=['mae'])
323
+ callback=EarlyStopping(monitor='val_loss',
324
+ min_delta=0,
325
+ patience=patience,
326
+ verbose=1, mode='auto')
327
+ model_lstm.fit(x_train,
328
+ y_train,
329
+ batch_size= batch_size,
330
+ epochs=epochs,
331
+ validation_split=0.1,# ...holding out 10% of the data for validation
332
+ shuffle=True,verbose=0,callbacks=[callback])
333
+ t1 = time.time()
334
+ global ex_time
335
+ ex_time = round(t1-t0, 2)
336
+ print("Compiling took :",ex_time,"seconds")
337
+
338
+ predictions = model_lstm.predict(x_test)
339
+ predictions = scaler.inverse_transform(predictions)
340
+ #rmse = np.sqrt(np.mean(((predictions - y_test) ** 2)))
341
+ global r_squared_score
342
+ r_squared_score = round(r2_score(y_test, predictions),2)
343
+ #print('Rmse Score: ', round(rmse),2)
344
+ print('R2 Score: ', r_squared_score)
345
+
346
+ if ticker == 'AAPL':
347
+ LSTM_trainer(1, 0.2, 100,2, 20, 30)
348
+ elif ticker == 'NVDA':
349
+ LSTM_trainer(2, 0.2, 100,2, 30, 50)
350
+ elif ticker == 'PYPL':
351
+ LSTM_trainer(6, 0.2, 100,10,25, 30)
352
+ elif ticker == 'MSFT':
353
+ LSTM_trainer(4, 0.1, 80, 2,20, 40)
354
+ elif ticker == 'TSLA':
355
+ LSTM_trainer(5, 0.1, 120, 4,20, 25)
356
+ elif ticker == 'AMZN':
357
+ LSTM_trainer(6, 0.1, 120,2, 20, 25)
358
+ elif ticker == 'SPOT':
359
+ LSTM_trainer(9, 0.2, 200,5, 20, 40)
360
+ elif ticker == 'TWTR' :
361
+ LSTM_trainer(15, 0.2, 100,4,20, 40)
362
+ elif ticker == 'UBER':
363
+ LSTM_trainer(15, 0.2, 100,7,20, 40)
364
+ elif ticker == 'ABNB':
365
+ LSTM_trainer(15, 0.2, 120,8,20, 40)
366
+ elif ticker == 'GOOG':
367
+ LSTM_trainer(15, 0.2, 100,3,20, 25)
368
+
369
+ # Unseen Predictions for the next 7 days
370
+ close_data = scaled_data
371
+ look_back = 60
372
+
373
+ def predict(num_prediction, model):
374
+ prediction_list = close_data[-look_back:]
375
+
376
+ for _ in range(num_prediction):
377
+ x = prediction_list[-look_back:]
378
+ x = x.reshape((1, look_back, 1))
379
+
380
+ out = model.predict(x)[0][0]
381
+ prediction_list = np.append(prediction_list, out)
382
+ prediction_list = prediction_list[look_back-1:]
383
+
384
+ return prediction_list
385
+
386
+ def predict_dates(num_prediction):
387
+ last_date = stock_data['Date'].values[-1]
388
+ prediction_dates = pd.date_range(last_date, periods=num_prediction+1).tolist()
389
+ return prediction_dates
390
+
391
+ num_prediction = 7
392
+
393
+ forecast = predict(num_prediction, model_lstm)
394
+ forecast_dates = predict_dates(num_prediction)
395
+
396
+ plt.figure(figsize=(25,10))
397
+ forecast = forecast.reshape(-1, 1)
398
+ forecast_inverse = scaler.inverse_transform(forecast)
399
+
400
+ # Ploting the Actual Prices and the Predictions of them for the next 7 days
401
+ base = stock_data['Date'].iloc[[-1]] # Here we create our base date (the last existing date with actual prices)
402
+ testdata = pd.DataFrame(forecast_inverse)# Here we create a data frame that contains the prediction prices and an empty column for their dates
403
+ testdata['Date'] = ""
404
+ testdata.columns = ["Adj Close","Date"]
405
+ testdata = testdata.iloc[1:,:]
406
+ testdata["Label"] = "" # Let's add a column "Label" that would show if the respective price is a prediction or not
407
+ testdata["Label"] = "Prediction"
408
+ testdata = testdata[["Date", "Adj Close", "Label"]]
409
+
410
+ date_list = [base + datetime.timedelta(days=x+1) for x in range(testdata.shape[0]+1)]
411
+ date_list = pd.DataFrame(date_list)
412
+ date_list.columns = ["Date"]
413
+ date_list.reset_index(inplace = True)
414
+ date_list.drop(["index"], axis = 1, inplace = True)
415
+ date_list.index = date_list.index + 1
416
+ testdata.Date = date_list
417
+
418
+ stock_data["Label"] = ""
419
+ stock_data["Label"] = "Actual price"
420
+ finaldf = pd.concat([stock_data,testdata], axis=0) # Here we concatenate the "testdata" and the original data frame "df" into a final one
421
+ finaldf.reset_index(inplace = True)
422
+ finaldf.drop(["index"], axis = 1, inplace = True)
423
+ finaldf['Date'] = pd.to_datetime(finaldf['Date'])
424
+
425
+ plt.rcParams["figure.figsize"] = (25,10)
426
+ #We create two different data frames, one that contains the actual prices and one that has only the predictions
427
+ finaldfPredictions = finaldf.iloc[-8:]
428
+ finaldfActuals = finaldf.iloc[:-7]
429
+
430
+ plot_1 = go.Scatter(
431
+ x = finaldfActuals['Date'],
432
+ y = finaldfActuals['Adj Close'],
433
+ mode = 'lines',
434
+ name = 'Historical Data (2 years)',
435
+ line=dict(width=1,color='#3D9140'))
436
+ plot_2 = go.Scatter(
437
+ x = finaldfPredictions['Date'],
438
+ y = finaldfPredictions['Adj Close'],
439
+ mode = 'lines',
440
+ name = '7-day Prediction',
441
+ line=dict(width=1,color="#EE3B3B"))
442
+
443
+ layout = go.Layout(
444
+ title = 'Next 7 days stock price prediction of ' + str(ticker),
445
+ xaxis = {'title' : "Date"},
446
+ yaxis = {'title' : "Price ($)"}
447
+ )
448
+ fig = go.Figure(data=[plot_1, plot_2], layout=layout)
449
+ fig.update_layout(template='plotly_dark',autosize=True)
450
+ fig.update_layout(legend=dict(
451
+ orientation="h",
452
+ yanchor="bottom",
453
+ y=1.02,
454
+ xanchor="right",
455
+ x=1
456
+ ))
457
+
458
+ return fig