-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathStockVisualizations.py
More file actions
284 lines (250 loc) · 10.2 KB
/
StockVisualizations.py
File metadata and controls
284 lines (250 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 11 23:37:01 2019
@author: adityakalia
"""
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as matdates
from scipy.stats import norm
import numpy as np
def user_input():
"""
This function takes the user's input of what stocks they would like to
anayze and stores .
"""
while True:
try:
stocks = input("Please enter the stocks you would " +
"like to analyze seperated by commas : ")
if len(stocks) > 0:
break
except ValueError:
pass
print("Incorrect input please enter your stocks")
return stocks
def parseStocks(val):
"""
This function parses the user's input and ensures there are no whitespaces.
"""
val = [x.strip(' ') for x in val]
return val
def historicalData(stocks):
"""
This function uses the Yfinance API and collects the historical data
of the user inputted and places the data in a dataframe (DF).
"""
stocks_df = pd.DataFrame()
for x in stocks:
try:
stock = yf.Ticker(x)
tempdf = stock.history(period='3mo')
tempdf.loc[:, 'StockName'] = x
stocks_df = stocks_df.append(tempdf, sort='False')
stocks_df.loc[:, 'ROI'] = stocks_df['Close'].pct_change()
except ValueError:
print("Incorrect stock entered " + x)
pass
return stocks_df
def stockForecastingMovingAverage(stocks_df):
"""
This function calculates the stocks Simple Moving Average and Exponential
Moving Average using the rolling function and the ewm function. It
calculates for a window of 5,10, and 15 days. Returns a large DataFrame
that has all moving averages for all stocks entered
"""
uniqueStocks = stocks_df.StockName.unique()
MovingAverageDF = stocks_df
for stock in uniqueStocks:
df1 = stocks_df.loc[stocks_df.StockName == stock]
df1.reset_index(inplace=True)
data = df1[['Date', 'Close']]
for i in (5, 10, 15):
simple_moving_average = data.set_index(
'Date').rolling(window=i).mean()
df1.loc[:, 'SMA ' + str(stock) + ' ' + str(
i)] = simple_moving_average.values
for i in (5, 10, 15):
exponential_moving_average = data.set_index(
'Date').ewm(span=i, adjust=False).mean()
df1.loc[:, 'EMA ' + str(stock) + ' ' + str(
i)] = exponential_moving_average.values
df1 = df1.set_index('Date')
smaPlotdf = df1.filter(regex='\ASMA')
smaPlotdf.loc[:, 'Close'] = df1.Close
ax1 = smaPlotdf.plot(legend=True, grid=True,
title='Simple Moving Average Plot of ' + stock)
ax1.set_ylabel('Stock Price')
ax1.set_xlabel('Date')
plt.savefig('Screenshots/Simple_Moving_Average_' + stock +'.png',
dpi=72,
bbox_inches='tight')
plt.show()
emaPlotdf = df1.filter(regex='\AEMA')
emaPlotdf.loc[:, 'Close'] = df1.Close
ax2 = emaPlotdf.plot(legend=True, grid=True,
title='Exponential Moving Average Plot of ' + stock)
ax2.set_ylabel('Stock Price')
ax2.set_xlabel('Date')
plt.savefig('Screenshots/Exponential_Moving_Average_' + stock +'.png', dpi=72,
bbox_inches='tight')
plt.show()
MovingAverageDF = pd.concat([df1, MovingAverageDF])
return MovingAverageDF
def stockBollingerBands(stocks_df):
"""
This function calculates the upper/middle/lower bound for the bollinger
bands using a window of 20 days to calculate the STD
(multiplying by 2 after). Ater calculating the bounds, it plots the data
using matplotlib.
"""
uniqueStocks = stocks_df.StockName.unique()
for stock in uniqueStocks:
df = stocks_df.loc[stocks_df.StockName == stock]
df.loc[:, 'Middle Bound'] = df['Close'].rolling(window=20).mean()
df.loc[:, '20std'] = df['Close'].rolling(window=20).std()
df.loc[:, 'Upper Bound'] = df['Middle Bound'] + (df['20std'] * 2)
df.loc[:, 'Lower Bound'] = df['Middle Bound'] - (df['20std'] * 2)
fig = plt.figure()
ax = fig.add_subplot(111)
# https://stackoverflow.com/a/37219987 reference of the code
majorFmt = matdates.DateFormatter('%Y-%m-%d %H:%M')
Daylocator2 = matdates.DayLocator(interval=1)
ax.xaxis.set_minor_locator(Daylocator2)
ax.xaxis.set_major_formatter(majorFmt)
plt.setp(ax.xaxis.get_majorticklabels(), rotation=45)
x_axis = df.index.get_level_values('Date')
ax.fill_between(x_axis, df['Upper Bound'], df['Lower Bound'],
color='orange')
ax.plot(x_axis, df['Close'], color='blue', lw=2)
ax.plot(x_axis, df['Upper Bound'], color='Black', lw=1)
ax.plot(x_axis, df['Lower Bound'], color='Black', lw=1)
ax.plot(x_axis, df['Middle Bound'], color='Green', lw=1)
ax.set_title('Bollinger Bands ' + stock)
ax.set_xlabel('Date (Year/Month Hour/Minute)')
ax.set_ylabel('Price')
ax.legend()
plt.savefig('Screenshots/Bollinger_Bands_' + stock +'.png', dpi=72,
bbox_inches='tight')
plt.show()
def CovarianceCorrelation(stocks_df):
"""
Covariance measures how related the stocks are to each other, value
of 0 meaning no relation, and a positive number indicating a positive
relation in the same direction.
Correlation measures a standarized value of the direction and strength
between the stocks, it is measured between -1 to +1.
"""
returns = stocks_df[['ROI', 'StockName']]
returns = returns.pivot(columns='StockName', values='ROI')
cov = returns.cov()
print("The Covariance matrix is ")
print(cov.rename_axis(None))
corr = returns.corr()
print("\n The Correlation matrix is ")
print(corr.rename_axis(None))
return cov, corr
def MarketComparison(stocks_df):
"""
This function takes the users stocks and caculates the normalized returns,
with the normalized returns, it maps it on the same plot as the noramlized
returns on the market to provide a comparison on returns
against the market.
"""
norm = stocks_df.loc[:, ['StockName', 'Close']]
norm = norm.pivot(index=norm.index, columns='StockName')
norm = norm/norm.iloc[0]
norm.columns = norm.columns.droplevel()
marketVal = yf.Ticker('SPY')
df1 = marketVal.history(period='3mo')
marketDF = df1.loc[:, ['Close']]
marketDF = marketDF.rename(columns={'Close': 'SPY Market'})
marketDF = marketDF/marketDF.iloc[0]
norm['SPY Market'] = marketDF
ax = norm.plot(legend=True, grid=True,
title='3 Month Normalized Stock Performance VS. Market(SPY)')
ax.set_ylabel('Normalized Price')
ax.set_xlabel('Date')
plt.savefig('Screenshots/MarketComparision.png', dpi=72,
bbox_inches='tight')
plt.show()
def StandardDev(stocks_df):
"""
This function takes input of the stocks dataframe and calculates the
standard deviation of each stock for its 30 day closing price period
using this standard deviation value the script creates a plot of the
stock's closing price with an error bar equivalent to the standard
deviation showing the closing price's possible voltaility.
"""
for stock in stocks_df.StockName.unique():
df = stocks_df['Close'][(stocks_df.StockName == stock)][-30:]
std_Val = df.std()
fig = plt.figure()
ax = fig.add_subplot(111)
majorFmt = matdates.DateFormatter('%Y-%m-%d')
Daylocator2 = matdates.DayLocator(interval=1)
ax.xaxis.set_minor_locator(Daylocator2)
ax.xaxis.set_major_formatter(majorFmt)
plt.setp(ax.xaxis.get_majorticklabels(), rotation=90)
ax.set_xlabel('Date')
ax.set_ylabel('Price')
ax.set_title(stock + ' CLose Price With Error Bar ')
xaxis = df.index.get_level_values('Date')
ax.errorbar(xaxis, df.values, yerr=std_Val, label=stock)
ax.grid(color='lightgrey', linestyle='-')
ax.set_facecolor('w')
plt.savefig('Screenshots/Error_Bar_Plot_' + stock +'.png',
dpi=72, bbox_inches='tight')
plt.show()
def zValue(series):
"""
This function takes a series as input and calculates the standard
deviation, mean, and uses the series last stock price as the x value
using these values it calculates the z value
"""
meanVal = series.mean()
stdVal = series.std()
mu = series[-1]
z1 = (mu - meanVal) / stdVal
return z1
def NormalGaussianCurve(stocks_df):
"""
This function plots the normal gaussian curve for the stocks closing price
times series data by calculating the z value using zValue function and
created a normal distrubutioon plot with the area of the z value shaded in
"""
for stock in stocks_df.StockName.unique():
series = stocks_df['Close'][(stocks_df.StockName == stock)][-30:]
z1 = zValue(series)
x = np.arange(-4, z1, 0.01)
y = norm.pdf(x, 0, 1)
x_all = np.arange(-10, 10, 0.001)
y2 = norm.pdf(x_all, 0, 1)
# build the plot
fig, ax = plt.subplots(figsize=(9, 6))
plt.style.use('fivethirtyeight')
ax.plot(x_all, y2)
ax.fill_between(x, y, -1, alpha=0.3, color='b')
ax.fill_between(x_all, y2, 0, alpha=0.1)
ax.set_xlim([-4, 4])
ax.set_ylim(0)
ax.set_xlabel('# of Standard Deviations Outside the Mean')
ax.set_yticklabels([])
ax.set_title('Normal Gaussian Curve of ' + stock)
plt.savefig('Screenshots/normal_curve_' + stock +'.png', dpi=72,
bbox_inches='tight')
plt.show()
def main():
stocks = user_input().split(',')
stocks = parseStocks(stocks)
stocks_df = historicalData(stocks)
stockForecastingMovingAverage(stocks_df)
stockBollingerBands(stocks_df)
CovarianceCorrelation(stocks_df)
MarketComparison(stocks_df)
StandardDev(stocks_df)
NormalGaussianCurve(stocks_df)
if __name__ == '__main__':
main()