prasad6145 commited on
Commit
818024d
·
verified ·
1 Parent(s): 344fd95

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +502 -0
app.py ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import yfinance as yf
4
+ import plotly.graph_objects as go
5
+ import numpy as np
6
+
7
+ # Functions for calculating indicators
8
+ def calculate_sma(df, window):
9
+ return df['Close'].rolling(window=window).mean()
10
+
11
+ def calculate_ema(df, window):
12
+ return df['Close'].ewm(span=window, adjust=False).mean()
13
+
14
+ def calculate_macd(df):
15
+ short_ema = df['Close'].ewm(span=12, adjust=False).mean()
16
+ long_ema = df['Close'].ewm(span=26, adjust=False).mean()
17
+ macd = short_ema - long_ema
18
+ signal = macd.ewm(span=9, adjust=False).mean()
19
+ return macd, signal
20
+
21
+ def calculate_rsi(df):
22
+ delta = df['Close'].diff()
23
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
24
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
25
+ rs = gain / loss
26
+ rsi = 100 - (100 / (1 + rs))
27
+ return rsi
28
+
29
+ def calculate_bollinger_bands(df):
30
+ middle_bb = df['Close'].rolling(window=20).mean()
31
+ upper_bb = middle_bb + 2 * df['Close'].rolling(window=20).std()
32
+ lower_bb = middle_bb - 2 * df['Close'].rolling(window=20).std()
33
+ return middle_bb, upper_bb, lower_bb
34
+
35
+ def calculate_stochastic_oscillator(df):
36
+ lowest_low = df['Low'].rolling(window=14).min()
37
+ highest_high = df['High'].rolling(window=14).max()
38
+ slowk = ((df['Close'] - lowest_low) / (highest_high - lowest_low)) * 100
39
+ slowd = slowk.rolling(window=3).mean()
40
+ return slowk, slowd
41
+
42
+ def calculate_cmf(df, window=20):
43
+ mfv = ((df['Close'] - df['Low']) - (df['High'] - df['Close'])) / (df['High'] - df['Low']) * df['Volume']
44
+ cmf = mfv.rolling(window=window).sum() / df['Volume'].rolling(window=window).sum()
45
+ return cmf
46
+
47
+ def calculate_cci(df, window=20):
48
+ typical_price = (df['High'] + df['Low'] + df['Close']) / 3
49
+ sma = typical_price.rolling(window=window).mean()
50
+ mean_deviation = (typical_price - sma).abs().rolling(window=window).mean()
51
+ cci = (typical_price - sma) / (0.015 * mean_deviation)
52
+ return cci
53
+
54
+ # Function to adjust thresholds based on sensitivity
55
+ def adjust_thresholds_by_sensitivity(sensitivity):
56
+ """
57
+ Convert a single sensitivity value (1-10) to appropriate thresholds
58
+ 1 = Most sensitive (more signals)
59
+ 10 = Least sensitive (fewer, stronger signals)
60
+ """
61
+ # Map sensitivity to thresholds
62
+ if sensitivity == 1: # Most sensitive
63
+ return {
64
+ 'SMA': 5,
65
+ 'RSI_lower': 30,
66
+ 'RSI_upper': 70,
67
+ 'BB': 0.5,
68
+ 'Stochastic_lower': 20,
69
+ 'Stochastic_upper': 80,
70
+ 'CMF': 0.1,
71
+ 'CCI': 100
72
+ }
73
+ elif sensitivity == 10: # Least sensitive
74
+ return {
75
+ 'SMA': 50,
76
+ 'RSI_lower': 5,
77
+ 'RSI_upper': 95,
78
+ 'BB': 5,
79
+ 'Stochastic_lower': 5,
80
+ 'Stochastic_upper': 95,
81
+ 'CMF': 0.6,
82
+ 'CCI': 300
83
+ }
84
+ else:
85
+ # Linear interpolation between extremes
86
+ factor = (sensitivity - 1) / 9 # 0 to 1
87
+ return {
88
+ 'SMA': int(5 + (50 - 5) * factor),
89
+ 'RSI_lower': int(30 - (30 - 5) * factor),
90
+ 'RSI_upper': int(70 + (95 - 70) * factor),
91
+ 'BB': 0.5 + (5 - 0.5) * factor,
92
+ 'Stochastic_lower': int(20 - (20 - 5) * factor),
93
+ 'Stochastic_upper': int(80 + (95 - 80) * factor),
94
+ 'CMF': 0.1 + (0.6 - 0.1) * factor,
95
+ 'CCI': int(100 + (300 - 100) * factor)
96
+ }
97
+
98
+ def generate_trading_signals(df, thresholds, enabled_signals):
99
+ # Calculate various indicators
100
+ df['SMA_30'] = calculate_sma(df, 30)
101
+ df['SMA_100'] = calculate_sma(df, 100)
102
+ df['EMA_12'] = calculate_ema(df, 12)
103
+ df['EMA_26'] = calculate_ema(df, 26)
104
+ df['RSI'] = calculate_rsi(df)
105
+ df['MiddleBB'], df['UpperBB'], df['LowerBB'] = calculate_bollinger_bands(df)
106
+ df['SlowK'], df['SlowD'] = calculate_stochastic_oscillator(df)
107
+ df['CMF'] = calculate_cmf(df)
108
+ df['CCI'] = calculate_cci(df)
109
+
110
+ # Initialize all signals as 0 (no signal)
111
+ signal_columns = ['SMA_Signal', 'MACD_Signal', 'RSI_Signal', 'BB_Signal',
112
+ 'Stochastic_Signal', 'CMF_Signal', 'CCI_Signal']
113
+ for col in signal_columns:
114
+ df[col] = 0
115
+
116
+ # Only generate signals for enabled indicators
117
+
118
+ # SMA Signal
119
+ if 'SMA' in enabled_signals:
120
+ sma_threshold = thresholds['SMA']
121
+ df['SMA_Diff_Pct'] = (df['SMA_30'] - df['SMA_100']) / df['SMA_100'] * 100
122
+ df['SMA_Signal'] = np.where(df['SMA_Diff_Pct'] > sma_threshold, 1, 0)
123
+ df['SMA_Signal'] = np.where(df['SMA_Diff_Pct'] < -sma_threshold, -1, df['SMA_Signal'])
124
+
125
+ # MACD Signal
126
+ if 'MACD' in enabled_signals:
127
+ macd, signal = calculate_macd(df)
128
+ df['MACD'] = macd
129
+ df['MACD_Signal_Line'] = signal
130
+ df['MACD_Signal'] = np.select([(macd > signal) & (macd.shift(1) <= signal.shift(1)),
131
+ (macd < signal) & (macd.shift(1) >= signal.shift(1))], [1, -1], default=0)
132
+
133
+ # RSI Signals
134
+ if 'RSI' in enabled_signals:
135
+ rsi_lower = thresholds['RSI_lower']
136
+ rsi_upper = thresholds['RSI_upper']
137
+ df['RSI_Signal'] = np.where(df['RSI'] < rsi_lower, 1, 0)
138
+ df['RSI_Signal'] = np.where(df['RSI'] > rsi_upper, -1, df['RSI_Signal'])
139
+
140
+ # Bollinger Bands
141
+ if 'BB' in enabled_signals:
142
+ bb_buffer = thresholds['BB'] / 100 # Convert percentage to decimal
143
+ df['BB_Signal'] = np.where(
144
+ (df['Close'] < df['LowerBB'] * (1 - bb_buffer)) &
145
+ (df['Close'].shift(1) < df['LowerBB'].shift(1) * (1 - bb_buffer)) &
146
+ (df['Close'].shift(2) < df['LowerBB'].shift(2) * (1 - bb_buffer)), 1, 0
147
+ )
148
+ df['BB_Signal'] = np.where(
149
+ (df['Close'] > df['UpperBB'] * (1 + bb_buffer)) &
150
+ (df['Close'].shift(1) > df['UpperBB'].shift(1) * (1 + bb_buffer)) &
151
+ (df['Close'].shift(2) > df['UpperBB'].shift(2) * (1 + bb_buffer)), -1, df['BB_Signal']
152
+ )
153
+
154
+ # Stochastic signals
155
+ if 'Stochastic' in enabled_signals:
156
+ stoch_lower = thresholds['Stochastic_lower']
157
+ stoch_upper = thresholds['Stochastic_upper']
158
+ df['Stochastic_Signal'] = np.where((df['SlowK'] < stoch_lower) & (df['SlowD'] < stoch_lower), 1, 0)
159
+ df['Stochastic_Signal'] = np.where((df['SlowK'] > stoch_upper) & (df['SlowD'] > stoch_upper), -1, df['Stochastic_Signal'])
160
+
161
+ # CMF Signals
162
+ if 'CMF' in enabled_signals:
163
+ cmf_threshold = thresholds['CMF']
164
+ df['CMF_Signal'] = np.where(df['CMF'] > cmf_threshold, -1, np.where(df['CMF'] < -cmf_threshold, 1, 0))
165
+
166
+ # CCI Signals
167
+ if 'CCI' in enabled_signals:
168
+ cci_threshold = thresholds['CCI']
169
+ df['CCI_Signal'] = np.where(df['CCI'] < -cci_threshold, 1, 0)
170
+ df['CCI_Signal'] = np.where(df['CCI'] > cci_threshold, -1, df['CCI_Signal'])
171
+
172
+ return df
173
+
174
+ def plot_simplified_signals(df, ticker, enabled_signals):
175
+ # Create a figure with improved styling
176
+ fig = go.Figure()
177
+
178
+ # Use a line chart instead of candlestick for simplicity
179
+ fig.add_trace(go.Scatter(
180
+ x=df.index,
181
+ y=df['Close'],
182
+ mode='lines',
183
+ name='Price',
184
+ line=dict(color='#26a69a', width=2),
185
+ opacity=0.9
186
+ ))
187
+
188
+ # Add SMA lines
189
+ fig.add_trace(go.Scatter(
190
+ x=df.index, y=df['SMA_30'],
191
+ mode='lines',
192
+ name='SMA 30',
193
+ line=dict(color='#42a5f5', width=1.5, dash='dot')
194
+ ))
195
+
196
+ fig.add_trace(go.Scatter(
197
+ x=df.index, y=df['SMA_100'],
198
+ mode='lines',
199
+ name='SMA 100',
200
+ line=dict(color='#5e35b1', width=1.5, dash='dot')
201
+ ))
202
+
203
+ # Add bollinger bands with lighter appearance
204
+ if 'BB' in enabled_signals:
205
+ fig.add_trace(go.Scatter(
206
+ x=df.index, y=df['UpperBB'],
207
+ mode='lines',
208
+ name='Upper BB',
209
+ line=dict(color='rgba(250, 250, 250, 0.3)', width=1),
210
+ showlegend=True
211
+ ))
212
+
213
+ fig.add_trace(go.Scatter(
214
+ x=df.index, y=df['LowerBB'],
215
+ mode='lines',
216
+ name='Lower BB',
217
+ line=dict(color='rgba(250, 250, 250, 0.3)', width=1),
218
+ fill='tonexty',
219
+ fillcolor='rgba(173, 216, 230, 0.1)',
220
+ showlegend=True
221
+ ))
222
+
223
+ # Group signals by type to reduce legend clutter
224
+ buy_signals_df = pd.DataFrame(index=df.index)
225
+ sell_signals_df = pd.DataFrame(index=df.index)
226
+
227
+ signal_names = [f"{signal}_Signal" for signal in enabled_signals]
228
+
229
+ # Collect all buy and sell signals
230
+ for signal in signal_names:
231
+ buy_signals_df[signal] = np.where(df[signal] == 1, df['Close'], np.nan)
232
+ sell_signals_df[signal] = np.where(df[signal] == -1, df['Close'], np.nan)
233
+
234
+ # Add hover data
235
+ buy_hovers = []
236
+ for idx in buy_signals_df.index:
237
+ signals_on_day = [col.split('_')[0] for col in buy_signals_df.columns
238
+ if not pd.isna(buy_signals_df.loc[idx, col])]
239
+ if signals_on_day:
240
+ hover_text = f"Buy Signals: {', '.join(signals_on_day)}<br>Date: {idx.strftime('%Y-%m-%d')}<br>Price: ${df.loc[idx, 'Close']:.2f}"
241
+ buy_hovers.append((idx, df.loc[idx, 'Close'], hover_text))
242
+
243
+ sell_hovers = []
244
+ for idx in sell_signals_df.index:
245
+ signals_on_day = [col.split('_')[0] for col in sell_signals_df.columns
246
+ if not pd.isna(sell_signals_df.loc[idx, col])]
247
+ if signals_on_day:
248
+ hover_text = f"Sell Signals: {', '.join(signals_on_day)}<br>Date: {idx.strftime('%Y-%m-%d')}<br>Price: ${df.loc[idx, 'Close']:.2f}"
249
+ sell_hovers.append((idx, df.loc[idx, 'Close'], hover_text))
250
+
251
+ # Add buy signals (single trace for all buy signals)
252
+ if buy_hovers:
253
+ buy_x, buy_y, buy_texts = zip(*buy_hovers)
254
+ fig.add_trace(go.Scatter(
255
+ x=buy_x,
256
+ y=[y * 0.995 for y in buy_y], # Position slightly below price for visibility
257
+ mode='markers',
258
+ marker=dict(symbol='triangle-up', size=10, color='#00e676', line=dict(color='white', width=1)),
259
+ name='Buy Signals',
260
+ hoverinfo='text',
261
+ hovertext=buy_texts
262
+ ))
263
+
264
+ # Add sell signals (single trace for all sell signals)
265
+ if sell_hovers:
266
+ sell_x, sell_y, sell_texts = zip(*sell_hovers)
267
+ fig.add_trace(go.Scatter(
268
+ x=sell_x,
269
+ y=[y * 1.005 for y in sell_y], # Position slightly above price for visibility
270
+ mode='markers',
271
+ marker=dict(symbol='triangle-down', size=10, color='#ff5252', line=dict(color='white', width=1)),
272
+ name='Sell Signals',
273
+ hoverinfo='text',
274
+ hovertext=sell_texts
275
+ ))
276
+
277
+ # Improve the layout with larger dimensions
278
+ fig.update_layout(
279
+ title=dict(
280
+ text=f'{ticker}: Technical Analysis & Trading Signals',
281
+ font=dict(size=24, color='white'),
282
+ x=0.5
283
+ ),
284
+ xaxis=dict(
285
+ title='Date',
286
+ gridcolor='rgba(255, 255, 255, 0.1)',
287
+ linecolor='rgba(255, 255, 255, 0.2)'
288
+ ),
289
+ yaxis=dict(
290
+ title='Price',
291
+ side='right',
292
+ gridcolor='rgba(255, 255, 255, 0.1)',
293
+ linecolor='rgba(255, 255, 255, 0.2)',
294
+ tickprefix='$'
295
+ ),
296
+ plot_bgcolor='#1e1e1e',
297
+ paper_bgcolor='#1e1e1e',
298
+ font=dict(color='white'),
299
+ hovermode='closest',
300
+ legend=dict(
301
+ bgcolor='rgba(30, 30, 30, 0.8)',
302
+ bordercolor='rgba(255, 255, 255, 0.2)',
303
+ borderwidth=1,
304
+ font=dict(color='white', size=10),
305
+ orientation='h',
306
+ yanchor='bottom',
307
+ y=1.02,
308
+ xanchor='center',
309
+ x=0.5
310
+ ),
311
+ margin=dict(l=50, r=50, b=100, t=100, pad=4),
312
+ height=800, # Increased height
313
+ width=1200 # Increased width
314
+ )
315
+
316
+ # Add range selector for better time navigation
317
+ fig.update_xaxes(
318
+ rangeslider_visible=True,
319
+ rangeselector=dict(
320
+ buttons=list([
321
+ dict(count=1, label="1m", step="month", stepmode="backward"),
322
+ dict(count=3, label="3m", step="month", stepmode="backward"),
323
+ dict(count=6, label="6m", step="month", stepmode="backward"),
324
+ dict(count=1, label="YTD", step="year", stepmode="todate"),
325
+ dict(count=1, label="1y", step="year", stepmode="backward"),
326
+ dict(step="all")
327
+ ]),
328
+ bgcolor='rgba(30, 30, 30, 0.8)',
329
+ activecolor='#536dfe',
330
+ font=dict(color='white')
331
+ )
332
+ )
333
+
334
+ return fig
335
+
336
+ def stock_analysis(ticker, start_date, end_date,
337
+ sensitivity, # New simplified parameter
338
+ use_sma, use_macd, use_rsi, use_bb,
339
+ use_stoch, use_cmf, use_cci):
340
+ try:
341
+ # Download stock data from Yahoo Finance
342
+ df = yf.download(ticker, start=start_date, end=end_date)
343
+
344
+ # Check if data was retrieved
345
+ if df.empty:
346
+ fig = go.Figure()
347
+ fig.add_annotation(
348
+ text="No data found for this ticker and date range",
349
+ xref="paper", yref="paper",
350
+ x=0.5, y=0.5,
351
+ showarrow=False,
352
+ font=dict(color="white", size=16)
353
+ )
354
+ fig.update_layout(
355
+ plot_bgcolor='#1e1e1e',
356
+ paper_bgcolor='#1e1e1e',
357
+ height=800,
358
+ width=1200
359
+ )
360
+ return fig
361
+
362
+ # If the DataFrame has a MultiIndex for columns, handle it
363
+ if isinstance(df.columns, pd.MultiIndex):
364
+ df.columns = df.columns.droplevel(1) if len(df.columns.levels) > 1 else df.columns
365
+
366
+ # Create list of enabled signals
367
+ enabled_signals = []
368
+ if use_sma: enabled_signals.append('SMA')
369
+ if use_macd: enabled_signals.append('MACD')
370
+ if use_rsi: enabled_signals.append('RSI')
371
+ if use_bb: enabled_signals.append('BB')
372
+ if use_stoch: enabled_signals.append('Stochastic')
373
+ if use_cmf: enabled_signals.append('CMF')
374
+ if use_cci: enabled_signals.append('CCI')
375
+
376
+ # If no signals are enabled, enable all by default
377
+ if not enabled_signals:
378
+ enabled_signals = ['SMA', 'MACD', 'RSI', 'BB', 'Stochastic', 'CMF', 'CCI']
379
+
380
+ # Get thresholds from sensitivity
381
+ thresholds = adjust_thresholds_by_sensitivity(sensitivity)
382
+
383
+ # Generate signals
384
+ df = generate_trading_signals(df, thresholds, enabled_signals)
385
+
386
+ # Last 360 days for plotting (or all data if less than 360 days)
387
+ df_last_360 = df.tail(min(360, len(df)))
388
+
389
+ # Plot simplified signals
390
+ fig = plot_simplified_signals(df_last_360, ticker, enabled_signals)
391
+
392
+ return fig
393
+
394
+ except Exception as e:
395
+ # Create error figure
396
+ fig = go.Figure()
397
+ fig.add_annotation(
398
+ text=f"Error: {str(e)}",
399
+ xref="paper", yref="paper",
400
+ x=0.5, y=0.5,
401
+ showarrow=False,
402
+ font=dict(color="#ff5252", size=16)
403
+ )
404
+ fig.update_layout(
405
+ plot_bgcolor='#1e1e1e',
406
+ paper_bgcolor='#1e1e1e',
407
+ font=dict(color='white'),
408
+ height=800,
409
+ width=1200
410
+ )
411
+ return fig
412
+
413
+ # Define Gradio interface with improved styling
414
+ custom_theme = gr.themes.Monochrome(
415
+ primary_hue="blue",
416
+ secondary_hue="purple",
417
+ neutral_hue="gray",
418
+ radius_size=gr.themes.sizes.radius_sm,
419
+ font=[gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"],
420
+ )
421
+
422
+ with gr.Blocks(theme=custom_theme) as demo:
423
+ gr.Markdown("# Technical Analysis")
424
+ gr.Markdown("This app helps you analyze stocks with technical indicators and generates trading signals.")
425
+
426
+ with gr.Row():
427
+ with gr.Column(scale=1):
428
+ ticker_input = gr.Textbox(
429
+ label="Stock Ticker Symbol",
430
+ placeholder="e.g., AAPL, NVDA, MSFT",
431
+ value="NVDA"
432
+ )
433
+ start_date_input = gr.Textbox(
434
+ label="Start Date",
435
+ placeholder="YYYY-MM-DD",
436
+ value="2022-01-01"
437
+ )
438
+ end_date_input = gr.Textbox(
439
+ label="End Date",
440
+ placeholder="YYYY-MM-DD",
441
+ value="2026-01-01" # Updated to current date
442
+ )
443
+
444
+ gr.Markdown("### Choose Indicators")
445
+ with gr.Row():
446
+ use_sma = gr.Checkbox(label="SMA", value=True)
447
+ use_macd = gr.Checkbox(label="MACD", value=True)
448
+ use_rsi = gr.Checkbox(label="RSI", value=True)
449
+ use_bb = gr.Checkbox(label="Bollinger", value=True)
450
+ use_stoch = gr.Checkbox(label="Stochastic", value=True)
451
+ use_cmf = gr.Checkbox(label="CMF", value=True)
452
+ use_cci = gr.Checkbox(label="CCI", value=True)
453
+
454
+ gr.Markdown("### Signal Sensitivity")
455
+ with gr.Row():
456
+ sensitivity = gr.Slider(
457
+ label="Signal Sensitivity",
458
+ minimum=1,
459
+ maximum=10,
460
+ step=1,
461
+ value=5,
462
+ info="1 = (sensitive), 10 = (strict)"
463
+ )
464
+
465
+ # Create a submit button with styling
466
+ button = gr.Button("Analyze Stock", variant="primary")
467
+
468
+ # Output: Signals plot with increased height
469
+ signals_output = gr.Plot(label="Technical Analysis & Trading Signals")
470
+
471
+ # Link button to function with updated parameters
472
+ button.click(
473
+ stock_analysis,
474
+ inputs=[
475
+ ticker_input, start_date_input, end_date_input,
476
+ sensitivity, # Single threshold parameter
477
+ use_sma, use_macd, use_rsi, use_bb,
478
+ use_stoch, use_cmf, use_cci
479
+ ],
480
+ outputs=[signals_output]
481
+ )
482
+
483
+ gr.Markdown("""
484
+ ## 📈 Trading Signals Legend
485
+ - **Green Triangle Up (▲)** indicates Buy signals
486
+ - **Red Triangle Down (▼)** indicates Sell signals
487
+ - Hover over signals to see which indicators triggered them
488
+
489
+ ## 🔍 Signal Sensitivity Explained
490
+ - **Lower values (1-3)**: More frequent signals, good for short-term trading
491
+ - **Medium values (4-6)**: Balanced approach, moderate number of signals
492
+ - **Higher values (7-10)**: Fewer but potentially stronger signals, good for long-term investors
493
+
494
+ ## 🛠️ Trading Strategy Tips
495
+ - **Day Trading**: Use lower sensitivity with multiple indicators
496
+ - **Swing Trading**: Use medium sensitivity with 3-4 indicators
497
+ - **Long-term Investing**: Use higher sensitivity focusing on trend indicators
498
+ - **Combine**: Using multiple indicators helps confirm signals and reduce false positives
499
+ """)
500
+
501
+ # Launch the interface
502
+ demo.launch()