JayLacoma commited on
Commit
b5991b5
·
verified ·
1 Parent(s): b8fa85a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +330 -0
app.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%
2
+ # %%
3
+ import gradio as gr
4
+ import pandas as pd
5
+ import yfinance as yf
6
+ from datetime import datetime
7
+ import plotly.graph_objects as go
8
+ import numpy as np
9
+
10
+ # Functions for calculating indicators (SMA, RSI, etc.) and generating trading signals
11
+
12
+ def calculate_sma(df, window):
13
+ return df['Close'].rolling(window=window).mean()
14
+
15
+ def calculate_ema(df, window):
16
+ return df['Close'].ewm(span=window, adjust=False).mean()
17
+
18
+
19
+ def calculate_macd(df):
20
+ short_ema = df['Close'].ewm(span=12, adjust=False).mean()
21
+ long_ema = df['Close'].ewm(span=26, adjust=False).mean()
22
+ macd = short_ema - long_ema
23
+ signal = macd.ewm(span=9, adjust=False).mean()
24
+ return macd, signal
25
+
26
+
27
+ def calculate_rsi(df):
28
+ delta = df['Close'].diff()
29
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
30
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
31
+ rs = gain / loss
32
+ rsi = 100 - (100 / (1 + rs))
33
+ return rsi
34
+
35
+ def calculate_bollinger_bands(df):
36
+ middle_bb = df['Close'].rolling(window=20).mean()
37
+ upper_bb = middle_bb + 2 * df['Close'].rolling(window=20).std()
38
+ lower_bb = middle_bb - 2 * df['Close'].rolling(window=20).std()
39
+ return middle_bb, upper_bb, lower_bb
40
+
41
+ def calculate_stochastic_oscillator(df):
42
+ lowest_low = df['Low'].rolling(window=14).min()
43
+ highest_high = df['High'].rolling(window=14).max()
44
+ slowk = ((df['Close'] - lowest_low) / (highest_high - lowest_low)) * 100
45
+ slowd = slowk.rolling(window=3).mean()
46
+ return slowk, slowd
47
+
48
+ def calculate_atr(df, window=14):
49
+ high_low = df['High'] - df['Low']
50
+ high_close = np.abs(df['High'] - df['Close'].shift())
51
+ low_close = np.abs(df['Low'] - df['Close'].shift())
52
+ tr = high_low.combine(high_close, max).combine(low_close, max)
53
+ atr = tr.rolling(window=window).mean()
54
+ return atr
55
+
56
+ def calculate_cmf(df, window=20):
57
+ mfv = ((df['Close'] - df['Low']) - (df['High'] - df['Close'])) / (df['High'] - df['Low']) * df['Volume']
58
+ cmf = mfv.rolling(window=window).sum() / df['Volume'].rolling(window=window).sum()
59
+ return cmf
60
+
61
+ def calculate_cci(df, window=20):
62
+ """Calculate Commodity Channel Index (CCI)."""
63
+ typical_price = (df['High'] + df['Low'] + df['Close']) / 3
64
+ sma = typical_price.rolling(window=window).mean()
65
+ mean_deviation = (typical_price - sma).abs().rolling(window=window).mean()
66
+ cci = (typical_price - sma) / (0.015 * mean_deviation)
67
+ return cci
68
+
69
+ def calculate_atr_signal(df, atr_column='ATR', close_column='Close', atr_window=20, ma_window=50, volatility_days=3, atr_threshold=1.2):
70
+
71
+ # Calculate the 20-day ATR rolling mean and high volatility threshold
72
+ df['ATR_20'] = df[atr_column].rolling(window=atr_window).mean()
73
+ df['High_Volatility'] = np.where(df[atr_column] > atr_threshold * df['ATR_20'], 1, 0)
74
+
75
+ # Calculate the 50-day moving average of the close prices for trend direction
76
+ df['MA_50'] = df[close_column].rolling(window=ma_window).mean()
77
+
78
+ # Generate the ATR signal based on high volatility and trend direction
79
+ df['ATR_Signal'] = np.where(
80
+ (df['High_Volatility'].rolling(window=volatility_days).sum() >= volatility_days) & (df[close_column] > df['MA_50']),
81
+ 1, # Buy Signal
82
+ np.where(
83
+ (df['High_Volatility'].rolling(window=volatility_days).sum() >= volatility_days) & (df[close_column] < df['MA_50']),
84
+ -1, # Sell Signal
85
+ 0 # No Signal
86
+ )
87
+ )
88
+
89
+ # Return only the ATR_Signal column as output
90
+ return df['ATR_Signal']
91
+
92
+
93
+
94
+ def generate_trading_signals(df):
95
+ # Calculate various indicators
96
+ df['SMA_30'] = calculate_sma(df, 30)
97
+ df['SMA_100'] = calculate_sma(df, 100)
98
+ df['EMA_12'] = calculate_ema(df, 12)
99
+ df['EMA_26'] = calculate_ema(df, 26)
100
+ df['RSI'] = calculate_rsi(df)
101
+ df['MiddleBB'], df['UpperBB'], df['LowerBB'] = calculate_bollinger_bands(df)
102
+ df['SlowK'], df['SlowD'] = calculate_stochastic_oscillator(df)
103
+ df['ATR'] = calculate_atr(df)
104
+ df['CMF'] = calculate_cmf(df)
105
+ df['CCI'] = calculate_cci(df)
106
+
107
+
108
+
109
+ # Generate trading signals
110
+ df['SMA_Signal'] = np.where(df['SMA_30'] > df['SMA_100'], 1, 0)
111
+
112
+ macd, signal = calculate_macd(df)
113
+ df['MACD_Signal'] = np.select([(macd > signal) & (macd.shift(1) <= signal.shift(1)),
114
+ (macd < signal) & (macd.shift(1) >= signal.shift(1))],[1, -1], default=0)
115
+
116
+
117
+
118
+ df['RSI_Signal'] = np.where(df['RSI'] < 20, 1, 0)
119
+ df['RSI_Signal'] = np.where(df['RSI'] > 90, -1, df['RSI_Signal'])
120
+
121
+ df['BB_Signal'] = np.where(df['Close'] < df['LowerBB'], 0, 0)
122
+ df['BB_Signal'] = np.where(df['Close'] > df['UpperBB'], -1, df['BB_Signal'])
123
+
124
+ df['Stochastic_Signal'] = np.where((df['SlowK'] < 10) & (df['SlowD'] < 15), 1, 0)
125
+ df['Stochastic_Signal'] = np.where((df['SlowK'] > 90) & (df['SlowD'] > 85), -1, df['Stochastic_Signal'])
126
+
127
+ df['ATR_Signal'] = calculate_atr_signal(df)
128
+
129
+ df['CMF_Signal'] = np.where(df['CMF'] > 0.3, -1, np.where(df['CMF'] < -0.3, 1, 0))
130
+
131
+
132
+ df['CCI_Signal'] = np.where(df['CCI'] < -180, 1, 0)
133
+ df['CCI_Signal'] = np.where(df['CCI'] > 150, -1, df['CCI_Signal'])
134
+
135
+
136
+
137
+ # Combined signal for stronger buy/sell points
138
+ df['Combined_Signal'] = df[['RSI_Signal', 'BB_Signal',
139
+ 'Stochastic_Signal', 'CMF_Signal',
140
+ 'CCI_Signal']].sum(axis=1)
141
+
142
+ return df
143
+
144
+
145
+ # %%
146
+ def plot_combined_signals(df, ticker):
147
+ # Create a figure
148
+ fig = go.Figure()
149
+
150
+ # Add closing price trace
151
+ fig.add_trace(go.Scatter(
152
+ x=df.index, y=df['Close'],
153
+ mode='lines',
154
+ name='Closing Price',
155
+ line=dict(color='lightcoral', width=2)
156
+ ))
157
+
158
+ # Add buy signals
159
+ buy_signals = df[df['Combined_Signal'] >= 3]
160
+ fig.add_trace(go.Scatter(
161
+ x=buy_signals.index, y=buy_signals['Close'],
162
+ mode='markers',
163
+ marker=dict(symbol='triangle-up', size=10, color='lightgreen'),
164
+ name='Buy Signal'
165
+ ))
166
+
167
+ # Add sell signals
168
+ sell_signals = df[df['Combined_Signal'] <= -3]
169
+ fig.add_trace(go.Scatter(
170
+ x=sell_signals.index, y=sell_signals['Close'],
171
+ mode='markers',
172
+ marker=dict(symbol='triangle-down', size=10, color='lightsalmon'),
173
+ name='Sell Signal'
174
+ ))
175
+
176
+ # Combined signal trace
177
+ fig.add_trace(go.Scatter(
178
+ x=df.index, y=df['Combined_Signal'],
179
+ mode='lines',
180
+ name='Combined Signal',
181
+ line=dict(color='deepskyblue', width=2),
182
+ yaxis='y2'
183
+ ))
184
+
185
+ # Update layout
186
+ fig.update_layout(
187
+ title=f'{ticker}: Stock Price and Combined Trading Signal (Last 60 Days)',
188
+ xaxis=dict(title='Date'),
189
+ yaxis=dict(title='Price', side='left'),
190
+ yaxis2=dict(title='Combined Signal', overlaying='y', side='right', showgrid=False),
191
+ plot_bgcolor='black',
192
+ paper_bgcolor='black',
193
+ font=dict(color='white')
194
+ )
195
+
196
+ return fig
197
+
198
+ # %%
199
+ def stock_analysis(ticker, start_date, end_date):
200
+ # Download stock data from Yahoo Finance
201
+ df = yf.download(ticker, start=start_date, end=end_date)
202
+
203
+ # Generate signals
204
+ generate_trading_signals(df)
205
+
206
+ # Last 60 days
207
+ df_last_60 = df.tail(60)
208
+
209
+ # Plot signals
210
+ fig_signals = plot_combined_signals(df_last_60, ticker)
211
+
212
+ return fig_signals
213
+
214
+
215
+
216
+
217
+ # %%
218
+ def plot_individual_signals(df, ticker):
219
+ # Create a figure
220
+ fig = go.Figure()
221
+ fig.add_trace(go.Scatter(
222
+ x=df.index, y=df['Close'],
223
+ mode='lines',
224
+ name='Closing Price',
225
+ line=dict(color='lightcoral', width=2)
226
+ ))
227
+
228
+ # Add buy/sell signals for each indicator
229
+ signal_names = ['RSI_Signal', 'BB_Signal',
230
+ 'Stochastic_Signal', 'CMF_Signal',
231
+ 'CCI_Signal']
232
+
233
+ for signal in signal_names:
234
+ buy_signals = df[df[signal] == 1]
235
+ sell_signals = df[df[signal] == -1]
236
+
237
+ fig.add_trace(go.Scatter(
238
+ x=buy_signals.index, y=buy_signals['Close'],
239
+ mode='markers',
240
+ marker=dict(symbol='triangle-up', size=10, color='lightgreen'),
241
+ name=f'{signal} Buy Signal'
242
+ ))
243
+
244
+ fig.add_trace(go.Scatter(
245
+ x=sell_signals.index, y=sell_signals['Close'],
246
+ mode='markers',
247
+ marker=dict(symbol='triangle-down', size=10, color='lightsalmon'),
248
+ name=f'{signal} Sell Signal'
249
+ ))
250
+
251
+ fig.update_layout(
252
+ title=f'{ticker}: Individual Trading Signals',
253
+ xaxis=dict(title='Date'),
254
+ yaxis=dict(title='Price', side='left'),
255
+ plot_bgcolor='black',
256
+ paper_bgcolor='black',
257
+ font=dict(color='white')
258
+ )
259
+
260
+ return fig
261
+
262
+
263
+ def display_signals(df):
264
+ # Create a signals DataFrame
265
+ signals_df = df[['Close', 'SMA_Signal', 'MACD_Signal', 'RSI_Signal',
266
+ 'BB_Signal', 'Stochastic_Signal', 'ATR_Signal',
267
+ 'CMF_Signal', 'CCI_Signal']].copy()
268
+
269
+ # The Date is the index, so we don't need to add it as a column
270
+ signals_df.index.name = 'Date' # Name the index for better readability
271
+
272
+ # Replace signal values with 'Buy', 'Sell', or 'Hold'
273
+ for column in signals_df.columns:
274
+ signals_df[column] = signals_df[column].replace(
275
+ {1: 'Buy', -1: 'Sell', 0: 'Hold'}
276
+ )
277
+
278
+ return signals_df
279
+
280
+ def stock_analysis(ticker, start_date, end_date):
281
+ # Download stock data from Yahoo Finance
282
+ df = yf.download(ticker, start=start_date, end=end_date)
283
+
284
+ # Generate signals
285
+ df = generate_trading_signals(df)
286
+
287
+ # Last 60 days for plotting
288
+ df_last_60 = df.tail(60)
289
+
290
+ # Plot combined signals
291
+ fig_signals = plot_combined_signals(df_last_60, ticker)
292
+
293
+ # Plot individual signals
294
+ fig_individual_signals = plot_individual_signals(df_last_60, ticker)
295
+
296
+ # Display signals DataFrame
297
+ signals_df = df_last_60[['Close', 'SMA_Signal', 'MACD_Signal', 'RSI_Signal', 'BB_Signal',
298
+ 'Stochastic_Signal', 'ATR_Signal', 'CMF_Signal',
299
+ 'CCI_Signal']]
300
+
301
+ return fig_signals, fig_individual_signals
302
+
303
+
304
+
305
+ # %%
306
+ # Define Gradio interface
307
+ with gr.Blocks() as demo:
308
+ gr.Markdown("## Stock Market Analysis App")
309
+
310
+ ticker_input = gr.Textbox(label="Enter Stock Ticker (e.g., AAPL, NVDA)", value="NVDA")
311
+ start_date_input = gr.Textbox(label="Start Date (YYYY-MM-DD)", value="2022-01-01")
312
+ end_date_input = gr.Textbox(label="End Date (YYYY-MM-DD)", value="2025-01-01")
313
+
314
+ # Create a submit button that runs the stock analysis function
315
+ button = gr.Button("Analyze Stock")
316
+
317
+ # Outputs: Display results, charts
318
+ combined_signals_output = gr.Plot(label="Combined Trading Signals")
319
+ individual_signals_output = gr.Plot(label="Individual Trading Signals")
320
+ #signals_df_output = gr.Dataframe(label="Buy/Sell Signals")
321
+
322
+ # Link button to function
323
+ button.click(stock_analysis, inputs=[ticker_input, start_date_input, end_date_input],
324
+ outputs=[combined_signals_output, individual_signals_output])
325
+
326
+ # Launch the interface
327
+ demo.launch()
328
+
329
+
330
+