shreyashnadage commited on
Commit
ceeb3e9
1 Parent(s): 069da00

Stock Analysis:
OHLC Plot
Chaikin, MACD indicator,
Candlestick Pattern recognition

Intraday Analysis:
Barrier Hit probability
VWAP analysis

Files changed (4) hide show
  1. .idea/vcs.xml +6 -0
  2. PatternRecognition.py +25 -8
  3. TopMovers.py +21 -0
  4. main.py +215 -23
.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
PatternRecognition.py CHANGED
@@ -1,8 +1,9 @@
1
- import talib
2
  import pandas as pd
 
3
 
4
  def GetPatternForData(stock_data_df):
5
- candle_name_list = talib.get_function_groups()['Pattern Recognition']
6
  tech_analysis_df = stock_data_df.iloc[-10:].copy()
7
  op_df = tech_analysis_df.Open
8
  hi_df = tech_analysis_df.High
@@ -10,14 +11,30 @@ def GetPatternForData(stock_data_df):
10
  cl_df = tech_analysis_df.Close
11
 
12
  for candle in candle_name_list:
13
- tech_analysis_df[candle] = getattr(talib, candle)(op_df, hi_df, lo_df, cl_df)
14
 
15
- result = pd.DataFrame(tech_analysis_df[['Date']+candle_name_list].sum(),columns=['Count'])
16
- filtered_results = result[result.Count!=0]
17
 
18
  if filtered_results.empty:
19
- return None,tech_analysis_df
20
  else:
21
- return filtered_results[filtered_results.Count == filtered_results.Count.max()].index[0],tech_analysis_df
22
 
23
- return None,tech_analysis_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import talib as ta
2
  import pandas as pd
3
+ import numpy as np
4
 
5
  def GetPatternForData(stock_data_df):
6
+ candle_name_list = ta.get_function_groups()['Pattern Recognition']
7
  tech_analysis_df = stock_data_df.iloc[-10:].copy()
8
  op_df = tech_analysis_df.Open
9
  hi_df = tech_analysis_df.High
 
11
  cl_df = tech_analysis_df.Close
12
 
13
  for candle in candle_name_list:
14
+ tech_analysis_df[candle] = getattr(ta, candle)(op_df, hi_df, lo_df, cl_df)
15
 
16
+ result = pd.DataFrame(tech_analysis_df[['Date']+candle_name_list].sum(), columns=['Count'])
17
+ filtered_results = result[result.Count != 0]
18
 
19
  if filtered_results.empty:
20
+ return None, tech_analysis_df
21
  else:
22
+ return filtered_results[filtered_results.Count == filtered_results.Count.max()].index[0], tech_analysis_df
23
 
24
+ return None, tech_analysis_df
25
+
26
+ def ComputeChaikinADSignal(stock_data_df):
27
+ ADOSC_data = stock_data_df.copy()
28
+ ADOSC_data['ADOSC'] = ta.ADOSC(ADOSC_data.High, ADOSC_data.Low, ADOSC_data.Close, ADOSC_data.Volume,
29
+ fastperiod=3, slowperiod=10)
30
+ ADOSC_data.dropna(inplace=True)
31
+ ADOSC_data['ADOSC_chg'] = np.log(ADOSC_data['ADOSC']/ADOSC_data['ADOSC'].shift(1))
32
+ ADOSC_data.dropna(inplace=True)
33
+ return ADOSC_data
34
+
35
+ def ComputeMACDSignal(stock_data_df):
36
+ macd_data_df = stock_data_df.copy()
37
+ macd_data_df['macd'], macd_data_df['macdsignal'], macd_data_df['macdhist'] =\
38
+ ta.MACD(macd_data_df.Close, fastperiod=12, slowperiod=26, signalperiod=9)
39
+ macd_data_df.dropna(inplace=True)
40
+ return macd_data_df
TopMovers.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from nsetools import Nse
2
+ import pandas as pd
3
+ from collections import OrderedDict
4
+
5
+ nse = Nse()
6
+
7
+ def GetTopLosers():
8
+ try:
9
+ top5losers = nse.get_top_losers()[:5]
10
+ data = OrderedDict({'Symbol': [i['symbol'] for i in top5losers], '%Change': [str(i['netPrice'])+'%' for i in top5losers]})
11
+ return pd.DataFrame(data).set_index('Symbol')
12
+ except:
13
+ return None
14
+
15
+ def GetTopGainers():
16
+ try:
17
+ top5gainers = nse.get_top_gainers()[:5]
18
+ data = OrderedDict({'Symbol': [i['symbol'] for i in top5gainers], '%Change': [str(i['netPrice'])+'%' for i in top5gainers]})
19
+ return pd.DataFrame(data).set_index('Symbol')
20
+ except:
21
+ return None
main.py CHANGED
@@ -2,10 +2,19 @@ import streamlit as st
2
  from nsetools import Nse
3
  from nsepy import get_history
4
  from datetime import date, timedelta
5
- from PatternRecognition import GetPatternForData
6
  from VixAnalysis import *
7
-
 
 
 
 
 
8
  import yfinance as yf
 
 
 
 
9
 
10
  today = date.today()
11
  nse = Nse()
@@ -13,19 +22,56 @@ all_stock_codes = nse.get_stock_codes()
13
  all_stock_names = dict(zip(nse.get_stock_codes().values(),nse.get_stock_codes().keys()))
14
  del all_stock_names['NAME OF COMPANY']
15
 
16
- st.set_page_config(page_title='Jarvis', page_icon='N', layout='wide', initial_sidebar_state='auto')
 
17
  st.title('Jarvis')
18
- stock_tab, mf_tab = st.tabs(['Stocks', 'Mutual Funds'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  with stock_tab:
 
21
  stock_selector_col, tenure_selector_start_col, tenure_selector_end_col = st.columns(3)
22
  with stock_selector_col:
23
  selected_stock = st.selectbox('Please select a stock for analysis',
24
- list(all_stock_names.keys()),help='Choose stock to analyze')
 
25
  ticker_yf = all_stock_names[selected_stock]+".NS"
26
 
27
  with tenure_selector_start_col:
28
- start_date = st.date_input("Start Date", today-timedelta(40))
29
 
30
  with tenure_selector_end_col:
31
  end_date = st.date_input("End Date", today)
@@ -34,8 +80,8 @@ with stock_tab:
34
  st.error('Start date should be before End date')
35
 
36
  time_delta = end_date-start_date
37
- if time_delta.days < 35:
38
- st.error('Please extend the range of dates. We need atleast 30 days of data for analysis.')
39
 
40
  with st.spinner(text=f'Please Wait...Loading data for {selected_stock}'):
41
  tk = yf.Ticker(ticker_yf)
@@ -66,34 +112,180 @@ with stock_tab:
66
  close=stock_data_df['Close'])])
67
  st.plotly_chart(fig_main_cs, use_container_width=True)
68
 
 
 
69
  st.subheader('Candlestick Matched pattern:')
70
- pattern_expander_col, cs_gauge_col = st.columns((1,3))
71
 
72
  matched_pattern, tech_df = GetPatternForData(stock_data_df=stock_data_df)
73
  if matched_pattern is not None:
74
  with pattern_expander_col:
75
  with st.expander(matched_pattern):
76
  st.write("Will add description here")
 
 
 
 
 
 
 
 
 
 
 
77
 
 
78
  else:
79
  with pattern_expander_col:
80
  with st.expander("No Pattern Matched"):
81
  st.write("It seems there were no pattern formations for last 10 days.")
82
 
83
- with st.sidebar:
84
- vix_container = st.container()
85
- with vix_container:
86
- st.subheader("VIX Analysis")
87
- with st.spinner(text='Loading VIX Analysis...'):
88
- vix_df = get_history(symbol="India VIX", start=today-timedelta(30), end=today, index=True)
89
- vix_analysis_df = ProcessVixData(vix_df)
90
- value = vix_analysis_df.Norm_Class[-30:].mean()
91
- st.metric("Current Market Mood", GetMood(value), '{:.2f}'.format(value))
92
- mood_dict = {'Greed': 'Markets are in bullish state. Good time to book profits.',
93
- 'Holding Steady': 'Markets are indecisive. its good to hold onto existing portfolio.',
94
- 'Fear': "Markets are in bearish state. Good time to pick good stocks for cheap prices."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- with st.expander(GetMood(value)):
97
- st.write(mood_dict[GetMood(value)])
 
 
 
98
 
 
99
 
 
 
 
2
  from nsetools import Nse
3
  from nsepy import get_history
4
  from datetime import date, timedelta
5
+ from PatternRecognition import *
6
  from VixAnalysis import *
7
+ from TopMovers import *
8
+ import time
9
+ from scipy.stats import norm
10
+ from math import exp, log, sqrt
11
+ import numpy as np
12
+ import pandas as pd
13
  import yfinance as yf
14
+ from plotly.subplots import make_subplots
15
+ from random import randrange
16
+
17
+ buy_sell_color_dict = {"Buy":"green", "Sell":"red", "Hold":"yellow"}
18
 
19
  today = date.today()
20
  nse = Nse()
 
22
  all_stock_names = dict(zip(nse.get_stock_codes().values(),nse.get_stock_codes().keys()))
23
  del all_stock_names['NAME OF COMPANY']
24
 
25
+ st.set_page_config(page_title='Jarvis', page_icon=':money_with_wings:', layout='wide', initial_sidebar_state='auto')
26
+ pd.options.plotting.backend = "plotly"
27
  st.title('Jarvis')
28
+ stock_tab, mf_tab, intraday_tab = st.tabs(['Stocks', 'Mutual Funds', 'Intraday'])
29
+
30
+ main_sidebar = st.sidebar
31
+ with main_sidebar:
32
+
33
+ vix_container = st.container()
34
+ with vix_container:
35
+
36
+ with st.spinner(text='Loading VIX Analysis...'):
37
+ try:
38
+ st.subheader("VIX Analysis")
39
+ vix_df = get_history(symbol="India VIX", start=today-timedelta(30), end=today, index=True)
40
+ vix_analysis_df = ProcessVixData(vix_df)
41
+ value = vix_analysis_df.Norm_Class[-30:].mean()
42
+ st.metric("Current Market Mood", GetMood(value), '{:.2f}'.format(value))
43
+ mood_dict = {'Greed': 'Markets are in bullish state. Good time to book profits.',
44
+ 'Holding Steady': 'Markets are indecisive. its good to hold onto existing portfolio.',
45
+ 'Fear': "Markets are in bearish state. Good time to pick good stocks for cheap prices."}
46
+
47
+ with st.expander(GetMood(value)):
48
+ st.write(mood_dict[GetMood(value)])
49
+ except:
50
+ st.error("Issues fetching VIX Data!")
51
+
52
+ top_losers = st.container()
53
+ with top_losers:
54
+ if GetTopLosers() is not None:
55
+ st.subheader('Top Losers')
56
+ st.table(GetTopLosers())
57
+
58
+ top_gainers = st.container()
59
+ with top_gainers:
60
+ if GetTopGainers() is not None:
61
+ st.subheader('Top Gainers')
62
+ st.table(GetTopGainers())
63
 
64
  with stock_tab:
65
+ min_days = 60
66
  stock_selector_col, tenure_selector_start_col, tenure_selector_end_col = st.columns(3)
67
  with stock_selector_col:
68
  selected_stock = st.selectbox('Please select a stock for analysis',
69
+ list(all_stock_names.keys()),
70
+ help='Choose stock to analyze')
71
  ticker_yf = all_stock_names[selected_stock]+".NS"
72
 
73
  with tenure_selector_start_col:
74
+ start_date = st.date_input("Start Date", today-timedelta(min_days))
75
 
76
  with tenure_selector_end_col:
77
  end_date = st.date_input("End Date", today)
 
80
  st.error('Start date should be before End date')
81
 
82
  time_delta = end_date-start_date
83
+ if time_delta.days < min_days:
84
+ st.error(f'Please extend the range of dates. We need atleast {min_days} days of data for analysis.')
85
 
86
  with st.spinner(text=f'Please Wait...Loading data for {selected_stock}'):
87
  tk = yf.Ticker(ticker_yf)
 
112
  close=stock_data_df['Close'])])
113
  st.plotly_chart(fig_main_cs, use_container_width=True)
114
 
115
+ st.markdown("***")
116
+
117
  st.subheader('Candlestick Matched pattern:')
118
+ pattern_expander_col, cs_gauge_col = st.columns((1, 1))
119
 
120
  matched_pattern, tech_df = GetPatternForData(stock_data_df=stock_data_df)
121
  if matched_pattern is not None:
122
  with pattern_expander_col:
123
  with st.expander(matched_pattern):
124
  st.write("Will add description here")
125
+ with cs_gauge_col:
126
+ score_cs_pattern = tech_df[[matched_pattern]].astype(float).sum()[0]
127
+ if score_cs_pattern < 0:
128
+ value = "Bearish Outlook"
129
+ delta = -1
130
+ elif score_cs_pattern == 0:
131
+ value = "Indecisive Outlook"
132
+ delta = 0
133
+ else:
134
+ value = "Bullish Outlook"
135
+ delta = 1
136
 
137
+ st.metric(label='Pattern Verdict', value=value, delta=delta, help="Outlook from detected CandleStick pattern")
138
  else:
139
  with pattern_expander_col:
140
  with st.expander("No Pattern Matched"):
141
  st.write("It seems there were no pattern formations for last 10 days.")
142
 
143
+ with cs_gauge_col:
144
+ st.metric(label='Pattern Verdict', value="Indecisive Outlook", delta=0,
145
+ help="Outlook from detected CandleStick pattern")
146
+
147
+ st.markdown("***")
148
+ st.subheader('Volume Analysis Pattern:')
149
+ chaikin_curr_trend_col, MACD_curr_trend_col = st.columns(2)
150
+ with chaikin_curr_trend_col:
151
+ st.subheader("Chaikin Indicator")
152
+ chaikin_osc_df = ComputeChaikinADSignal(stock_data_df)
153
+ chaikin_osc_trend = chaikin_osc_df.ADOSC.iloc[-10:].mean()
154
+ chaikin_osc_trend_chg = chaikin_osc_df.ADOSC_chg.iloc[-10:].mean()
155
+
156
+ if chaikin_osc_trend >= 0:
157
+ chaikin_trend = "Bullish"
158
+ else:
159
+ chaikin_trend = "Bearish"
160
+
161
+ st.metric(label="Chaikin Current Trend", value=chaikin_trend,
162
+ delta="{:.2f}%".format(chaikin_osc_trend_chg*100),
163
+ help="Chaikin Oscillator is an indicator of buy/sell pressure in the market for give stock.")
164
+ with MACD_curr_trend_col:
165
+ st.subheader("MACD Indicator")
166
+ macd_df = ComputeMACDSignal(stock_data_df.set_index('Date'))
167
+ macd_bull_bear_signal = "Bullish" if macd_df.macd.iloc[-1] >= macd_df.macdsignal.iloc[-1] else "Bearish"
168
+ st.metric(label="MACD Signal", value=macd_bull_bear_signal, delta="{:.2f}".format(macd_df.macdhist.iloc[-1]),
169
+ help="Helpful in analyzing momentum of price.")
170
+
171
+ momentum_plot_column = st.container()
172
+ st.subheader("MACD Chart")
173
+ with momentum_plot_column:
174
+ fig_macd = go.Figure()
175
+ fig_macd = make_subplots(rows=3, cols=1, shared_xaxes=True,
176
+ vertical_spacing=0.01, row_heights=[0.5, 0.3, 0.3])
177
+ fig_macd.add_trace(go.Candlestick(x=macd_df.index,
178
+ open=macd_df['Open'],
179
+ high=macd_df['High'],
180
+ low=macd_df['Low'],
181
+ close=macd_df['Close'], name=f"OHLC Chart : {ticker_yf}"), row=1, col=1)
182
+
183
+ colors = ['green' if row['Open'] - row['Close'] >= 0
184
+ else 'red' for index, row in macd_df.iterrows()]
185
+ fig_macd.add_trace(go.Bar(x=macd_df.index, y=macd_df['Volume'], marker_color=colors, name="Volume"),
186
+ row=2, col=1)
187
+ colors = ['green' if val >= 0
188
+ else 'red' for val in macd_df.macdhist]
189
+ fig_macd.add_trace(go.Bar(x=macd_df.index, y=macd_df.macdhist, marker_color=colors, name="MACD Histogram"), row=3, col=1)
190
+ fig_macd.add_trace(go.Scatter(x=macd_df.index, y=macd_df.macd, line=dict(color='black', width=2), name="MACD"),
191
+ row=3, col=1)
192
+ fig_macd.add_trace(go.Scatter(x=macd_df.index, y=macd_df.macdsignal,
193
+ line=dict(color='blue', width=1), name="MACD Signal"), row=3, col=1)
194
+ fig_macd.update_yaxes(title_text="Price", row=1, col=1)
195
+ fig_macd.update_yaxes(title_text="Volume", row=2, col=1)
196
+ fig_macd.update_yaxes(title_text="MACD", showgrid=False, row=3, col=1)
197
+ st.plotly_chart(fig_macd, use_container_width=True)
198
+
199
+
200
+
201
+ with intraday_tab:
202
+
203
+ stock_selector_container_intraday = st.container()
204
+ stock_selector_container_intraday_placeholder = st.empty()
205
+ with stock_selector_container_intraday:
206
+ selected_stock_intraday_col, _, barrier_probability_calc_input_col, barrier_probability_calc_button_col \
207
+ = st.columns((1, 1, 1, 1))
208
+ with selected_stock_intraday_col:
209
+ selected_stock_intraday = st.selectbox(label='Select stock for intraday analysis',
210
+ options=list(all_stock_names.keys()),
211
+ help='Choose stock to analyze')
212
+ intraday_selected_ticker = all_stock_names[selected_stock_intraday]
213
+ stock_quote_intraday = nse.get_quote(intraday_selected_ticker)
214
+
215
+ with barrier_probability_calc_input_col:
216
+ barrier = st.number_input("Enter strike to calculate hit probability", min_value=1.0,
217
+ value=100.00, step=0.01, max_value=999999999.99,
218
+ help="Use this tool to estimate strike price of options strategy.")
219
+ if barrier < 0:
220
+ st.error("Please enter strike > 0.")
221
+ with barrier_probability_calc_button_col:
222
+ r = 0.073
223
+ tk = yf.Ticker(intraday_selected_ticker + ".NS")
224
+ v = np.log((tk.history(period='365d', interval="1d")['Close'] /
225
+ tk.history(period='365d', interval="1d")['Close'].shift(1)).dropna()).std()
226
+ live_stock_price_intraday = nse.get_quote(intraday_selected_ticker)['lastPrice']
227
+ barrier_flag = 1 if barrier > live_stock_price_intraday else -1
228
+ T = 1
229
+ d2 = barrier_flag * ((log(live_stock_price_intraday / barrier) + (r - 0.5 * v ** 2)*T) / v*sqrt(T))
230
+ hit_prob = exp(-r) * norm.cdf(d2)
231
+ st.metric(label="Barrier hit probability", value='{:.0f}'.format(hit_prob*100) + '%',
232
+ help="It gives probability that stock price will hit"
233
+ " the strike price you entered")
234
+
235
+ while True:
236
+ with stock_selector_container_intraday_placeholder.container():
237
+ quote_dict = nse.get_quote(intraday_selected_ticker)
238
+ nifty_quote_dict = nse.get_index_quote('Nifty 50')
239
+ live_stock_col, live_nifty_col = st.columns(2)
240
+ with live_stock_col:
241
+ live_stock_price_intraday = quote_dict['lastPrice']
242
+ st.metric(label=all_stock_names[selected_stock_intraday], value=live_stock_price_intraday,
243
+ delta=quote_dict['pChange'])
244
+ with live_nifty_col:
245
+ live_nifty_price = nifty_quote_dict['lastPrice']
246
+ st.metric(label="Nifty 50", value=live_nifty_price,
247
+ delta=nifty_quote_dict['pChange'])
248
+
249
+ st.markdown("***")
250
+
251
+ tk = yf.Ticker(intraday_selected_ticker+'.NS')
252
+ df_intraday_realtime = tk.history(period='1d', interval='1m')
253
+ df_intraday_realtime['VWAP'] = (((df_intraday_realtime.High + df_intraday_realtime.Low
254
+ + df_intraday_realtime.Close) / 3)
255
+ * df_intraday_realtime.Volume).cumsum() /\
256
+ df_intraday_realtime.Volume.cumsum()
257
+ df_intraday_realtime.dropna(inplace=True)
258
+ fig = go.Figure()
259
+ fig.add_trace(go.Scatter(x=df_intraday_realtime.index, y=df_intraday_realtime.Close,
260
+ mode='lines',
261
+ name='Price'))
262
+ fig.add_trace(go.Scatter(x=df_intraday_realtime.index, y=df_intraday_realtime.VWAP,
263
+ mode='lines',
264
+ name='VWAP'))
265
+ fig.update_layout(title=intraday_selected_ticker, xaxis_title="Time",
266
+ yaxis_title=intraday_selected_ticker+" Price")
267
+ st.plotly_chart(fig, use_container_width=True)
268
+
269
+ if df_intraday_realtime.Close.values[-1] < df_intraday_realtime.VWAP.values[-1]:
270
+ VWAP_signal = "Buy"
271
+ vwap_icon = ':thumbsup:'
272
+ vwap_explain = "Currently the market price is less than the VWAP price. Its good time to enter into trade."
273
+ elif df_intraday_realtime.Close.values[-1] == df_intraday_realtime.VWAP.values[-1]:
274
+ VWAP_signal = "Hold"
275
+ vwap_icon = ':open_hands:'
276
+ vwap_explain = "Currently the market price is equal to the VWAP price. Wait for buy or sell signal"
277
+ else:
278
+ VWAP_signal = "Sell"
279
+ vwap_icon = ':thumbsdown:'
280
+ vwap_explain = "Currently the market price is greater than the VWAP price. Its good time to exit the trade."
281
 
282
+ vwap_expander_col, _ = st.columns((1, 3))
283
+ with vwap_expander_col:
284
+ with st.expander(f"VWAP Buy/Sell Indicator : {VWAP_signal}"):
285
+ st.markdown(vwap_explain)
286
+ st.header(vwap_icon)
287
 
288
+ time.sleep(5)
289
 
290
+ with mf_tab:
291
+ st.write("Coming soon...")