Update app.py
Browse files
app.py
CHANGED
|
@@ -4,7 +4,7 @@ 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 |
|
|
@@ -51,7 +51,51 @@ def calculate_cci(df, window=20):
|
|
| 51 |
cci = (typical_price - sma) / (0.015 * mean_deviation)
|
| 52 |
return cci
|
| 53 |
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
# Calculate various indicators
|
| 56 |
df['SMA_30'] = calculate_sma(df, 30)
|
| 57 |
df['SMA_100'] = calculate_sma(df, 100)
|
|
@@ -63,54 +107,71 @@ def generate_trading_signals(df):
|
|
| 63 |
df['CMF'] = calculate_cmf(df)
|
| 64 |
df['CCI'] = calculate_cci(df)
|
| 65 |
|
| 66 |
-
#
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
-
macd, signal = calculate_macd(df)
|
| 73 |
-
df['MACD'] = macd
|
| 74 |
-
df['MACD_Signal_Line'] = signal
|
| 75 |
-
df['MACD_Signal'] = np.select([(macd > signal) & (macd.shift(1) <= signal.shift(1)),
|
| 76 |
-
(macd < signal) & (macd.shift(1) >= signal.shift(1))], [1, -1], default=0)
|
| 77 |
-
|
| 78 |
# RSI Signals
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
-
# Bollinger Bands
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
|
|
|
| 94 |
|
| 95 |
# Stochastic signals
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
| 99 |
# CMF Signals
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
| 102 |
# CCI Signals
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
df['Combined_Signal'] = df[['RSI_Signal', 'BB_Signal',
|
| 108 |
-
'Stochastic_Signal', 'CMF_Signal',
|
| 109 |
-
'CCI_Signal', 'MACD_Signal']].sum(axis=1)
|
| 110 |
|
| 111 |
return df
|
| 112 |
|
| 113 |
-
def plot_simplified_signals(df, ticker):
|
| 114 |
# Create a figure with improved styling
|
| 115 |
fig = go.Figure()
|
| 116 |
|
|
@@ -140,30 +201,30 @@ def plot_simplified_signals(df, ticker):
|
|
| 140 |
))
|
| 141 |
|
| 142 |
# Add bollinger bands with lighter appearance
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
|
|
|
| 160 |
|
| 161 |
# Group signals by type to reduce legend clutter
|
| 162 |
buy_signals_df = pd.DataFrame(index=df.index)
|
| 163 |
sell_signals_df = pd.DataFrame(index=df.index)
|
| 164 |
|
| 165 |
-
signal_names = [
|
| 166 |
-
'CMF_Signal', 'CCI_Signal', 'MACD_Signal', 'SMA_Signal']
|
| 167 |
|
| 168 |
# Collect all buy and sell signals
|
| 169 |
for signal in signal_names:
|
|
@@ -213,7 +274,7 @@ def plot_simplified_signals(df, ticker):
|
|
| 213 |
hovertext=sell_texts
|
| 214 |
))
|
| 215 |
|
| 216 |
-
# Improve the layout
|
| 217 |
fig.update_layout(
|
| 218 |
title=dict(
|
| 219 |
text=f'{ticker}: Technical Analysis & Trading Signals',
|
|
@@ -247,7 +308,9 @@ def plot_simplified_signals(df, ticker):
|
|
| 247 |
xanchor='center',
|
| 248 |
x=0.5
|
| 249 |
),
|
| 250 |
-
margin=dict(l=50, r=50, b=100, t=100, pad=4)
|
|
|
|
|
|
|
| 251 |
)
|
| 252 |
|
| 253 |
# Add range selector for better time navigation
|
|
@@ -270,7 +333,10 @@ def plot_simplified_signals(df, ticker):
|
|
| 270 |
|
| 271 |
return fig
|
| 272 |
|
| 273 |
-
def stock_analysis(ticker, start_date, end_date
|
|
|
|
|
|
|
|
|
|
| 274 |
try:
|
| 275 |
# Download stock data from Yahoo Finance
|
| 276 |
df = yf.download(ticker, start=start_date, end=end_date)
|
|
@@ -287,7 +353,9 @@ def stock_analysis(ticker, start_date, end_date):
|
|
| 287 |
)
|
| 288 |
fig.update_layout(
|
| 289 |
plot_bgcolor='#1e1e1e',
|
| 290 |
-
paper_bgcolor='#1e1e1e'
|
|
|
|
|
|
|
| 291 |
)
|
| 292 |
return fig
|
| 293 |
|
|
@@ -295,16 +363,33 @@ def stock_analysis(ticker, start_date, end_date):
|
|
| 295 |
if isinstance(df.columns, pd.MultiIndex):
|
| 296 |
df.columns = df.columns.droplevel(1) if len(df.columns.levels) > 1 else df.columns
|
| 297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
# Generate signals
|
| 299 |
-
df = generate_trading_signals(df)
|
| 300 |
|
| 301 |
# Last 360 days for plotting (or all data if less than 360 days)
|
| 302 |
df_last_360 = df.tail(min(360, len(df)))
|
| 303 |
|
| 304 |
# Plot simplified signals
|
| 305 |
-
|
| 306 |
|
| 307 |
-
return
|
| 308 |
|
| 309 |
except Exception as e:
|
| 310 |
# Create error figure
|
|
@@ -319,7 +404,9 @@ def stock_analysis(ticker, start_date, end_date):
|
|
| 319 |
fig.update_layout(
|
| 320 |
plot_bgcolor='#1e1e1e',
|
| 321 |
paper_bgcolor='#1e1e1e',
|
| 322 |
-
font=dict(color='white')
|
|
|
|
|
|
|
| 323 |
)
|
| 324 |
return fig
|
| 325 |
|
|
@@ -333,8 +420,8 @@ custom_theme = gr.themes.Monochrome(
|
|
| 333 |
)
|
| 334 |
|
| 335 |
with gr.Blocks(theme=custom_theme) as demo:
|
| 336 |
-
gr.Markdown("# Signal Analysis")
|
| 337 |
-
gr.Markdown("This app
|
| 338 |
|
| 339 |
with gr.Row():
|
| 340 |
with gr.Column(scale=1):
|
|
@@ -351,19 +438,45 @@ with gr.Blocks(theme=custom_theme) as demo:
|
|
| 351 |
end_date_input = gr.Textbox(
|
| 352 |
label="End Date",
|
| 353 |
placeholder="YYYY-MM-DD",
|
| 354 |
-
value="
|
| 355 |
)
|
| 356 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
# Create a submit button with styling
|
| 358 |
button = gr.Button("Analyze Stock", variant="primary")
|
| 359 |
|
| 360 |
-
# Output: Signals plot
|
| 361 |
signals_output = gr.Plot(label="Technical Analysis & Trading Signals")
|
| 362 |
|
| 363 |
-
# Link button to function
|
| 364 |
button.click(
|
| 365 |
stock_analysis,
|
| 366 |
-
inputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
outputs=[signals_output]
|
| 368 |
)
|
| 369 |
|
|
@@ -373,21 +486,16 @@ with gr.Blocks(theme=custom_theme) as demo:
|
|
| 373 |
- **Red Triangle Down (▼)** indicates Sell signals
|
| 374 |
- Hover over signals to see which indicators triggered them
|
| 375 |
|
| 376 |
-
## 🔍
|
| 377 |
-
- **
|
| 378 |
-
- **
|
| 379 |
-
- **
|
| 380 |
-
- **BB**: Bollinger Bands (with 1% buffer)
|
| 381 |
-
- **Stochastic**: Stochastic Oscillator (Buy < 5, Sell > 99)
|
| 382 |
-
- **CMF**: Chaikin Money Flow (Buy < -0.4, Sell > 0.4)
|
| 383 |
-
- **CCI**: Commodity Channel Index (Buy < -195, Sell > 195)
|
| 384 |
|
| 385 |
-
##
|
| 386 |
-
-
|
| 387 |
-
-
|
| 388 |
-
-
|
| 389 |
-
-
|
| 390 |
-
- Interactive time range selection
|
| 391 |
""")
|
| 392 |
|
| 393 |
# Launch the interface
|
|
|
|
| 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 |
|
|
|
|
| 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)
|
|
|
|
| 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 |
|
|
|
|
| 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:
|
|
|
|
| 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',
|
|
|
|
| 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
|
|
|
|
| 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)
|
|
|
|
| 353 |
)
|
| 354 |
fig.update_layout(
|
| 355 |
plot_bgcolor='#1e1e1e',
|
| 356 |
+
paper_bgcolor='#1e1e1e',
|
| 357 |
+
height=800,
|
| 358 |
+
width=1200
|
| 359 |
)
|
| 360 |
return fig
|
| 361 |
|
|
|
|
| 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
|
|
|
|
| 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 |
|
|
|
|
| 420 |
)
|
| 421 |
|
| 422 |
with gr.Blocks(theme=custom_theme) as demo:
|
| 423 |
+
gr.Markdown("# Stock Market Signal 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):
|
|
|
|
| 438 |
end_date_input = gr.Textbox(
|
| 439 |
label="End Date",
|
| 440 |
placeholder="YYYY-MM-DD",
|
| 441 |
+
value="2025-03-10" # 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 |
|
|
|
|
| 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
|