pyroleli commited on
Commit
fb158f8
·
verified ·
1 Parent(s): f91a8df

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -83
app.py CHANGED
@@ -2,111 +2,100 @@ import gradio as gr
2
  import pandas as pd
3
  import yfinance as yf
4
  import plotly.graph_objects as go
 
5
  from statsforecast import StatsForecast
6
  from statsforecast.models import AutoARIMA
7
- import nltk
8
- from nltk.sentiment.vader import SentimentIntensityAnalyzer
9
 
10
- # Initialize Sentiment Engine
11
- try:
12
- nltk.data.find('vader_lexicon')
13
- except LookupError:
14
- nltk.download('vader_lexicon')
15
- sia = SentimentIntensityAnalyzer()
16
-
17
- def get_pro_analytics(df, ticker):
18
- # 1. Volume Surge Alert (Compares current volume to 20-day average)
19
- avg_vol = df['Volume'].tail(20).mean()
20
- curr_vol = df['Volume'].iloc[-1]
21
- surge_ratio = curr_vol / avg_vol
22
- surge_alert = f"⚡ VOLUME SURGE: {surge_ratio:.1f}x" if surge_ratio > 2.0 else "Normal Volume"
23
 
24
- # 2. News Sentiment
25
- stock = yf.Ticker(ticker)
26
- news = stock.news[:3]
27
- scores = []
28
- headlines_html = ""
29
- for article in news:
30
- s = sia.polarity_scores(article['title'])['compound']
31
- scores.append(s)
32
- icon = "🟢" if s > 0.05 else "🔴" if s < -0.05 else "⚪"
33
- headlines_html += f"<div style='font-size:11px; margin-bottom:4px;'>{icon} {article['title'][:60]}...</div>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- avg_sent = sum(scores)/len(scores) if scores else 0
36
- return surge_alert, avg_sent, headlines_html
37
 
38
- def analyze_full(ticker, horizon):
39
  try:
40
- # Data Acquisition
41
- df = yf.download(ticker, period="1y", multi_level_index=False)
42
- if df.empty: return None, "⚠️ Symbol Error"
 
 
 
 
 
43
 
44
- # 1. Forecasting with StatsForecast
 
 
 
45
  data = df.reset_index()[['Date', 'Close']]
46
  data.columns = ['ds', 'y']
47
  data['unique_id'] = ticker
 
 
48
  sf = StatsForecast(models=[AutoARIMA(season_length=5)], freq='B')
49
  sf.fit(data)
50
  forecast = sf.predict(h=horizon, level=[80])
51
 
52
- # 2. Extract Analytics
53
- surge_text, sent_score, news_html = get_pro_analytics(df, ticker)
 
54
 
55
- # 3. Confidence Calculation
56
- math_move = ((forecast['AutoARIMA'].iloc[-1] - df['Close'].iloc[-1]) / df['Close'].iloc[-1]) * 100
57
- # Correlation check: Is news sentiment in the same direction as the math?
58
- is_aligned = (math_move > 0 and sent_score > 0) or (math_move < 0 and sent_score < 0)
59
- confidence = 85 if is_aligned else 60
60
-
61
- # 4. Charting with Confidence Zone
62
- fig = go.Figure()
63
- # History
64
- fig.add_trace(go.Scatter(x=df.index, y=df['Close'], name='Market History', line=dict(color='#2962FF', width=2)))
65
- # Shaded Confidence Zone (80% Level)
66
- fig.add_trace(go.Scatter(
67
- x=pd.concat([forecast['ds'], forecast['ds'][::-1]]),
68
- y=pd.concat([forecast['AutoARIMA-hi-80'], forecast['AutoARIMA-lo-80'][::-1]]),
69
- fill='toself', fillcolor='rgba(242, 54, 69, 0.1)',
70
- line=dict(color='rgba(255,255,255,0)'), name='AI Confidence Zone'
71
- ))
72
- # Median Forecast
73
- fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['AutoARIMA'], name='AI Target', line=dict(color='#F23645', width=3)))
74
-
75
- fig.update_layout(template='plotly_dark', paper_bgcolor='#131722', plot_bgcolor='#131722',
76
- margin=dict(l=10, r=10, t=10, b=10), legend=dict(orientation="h", y=1.1))
77
-
78
- # 5. UI Summary
79
- color = "#00ff88" if math_move > 0 else "#ff4444"
80
- surge_color = "#FFD700" if "SURGE" in surge_text else "#787b86"
81
-
82
- summary = f"""
83
- <div style='background: #1e222d; padding: 15px; border-radius: 8px; border-top: 4px solid {color};'>
84
- <h3 style='margin:0; color:{color};'>{'BULLISH' if math_move > 0 else 'BEARISH'} ({math_move:+.1f}%)</h3>
85
- <p style='color:{surge_color}; font-weight:bold; margin:5px 0;'>{surge_text}</p>
86
- <p style='font-size: 13px;'>AI Confidence: <b>{confidence}%</b></p>
87
- <hr style='border:0.1px solid #363c4e;'>
88
- <p style='font-size: 12px; font-weight:bold; margin-bottom:5px;'>LIVE SENTIMENT FEED:</p>
89
- {news_html}
90
  </div>
91
  """
92
- return fig, summary
93
-
94
  except Exception as e:
95
- return None, f"<div style='color:red;'>Error: {str(e)}</div>"
96
 
97
- # --- UI INTERFACE ---
98
- with gr.Blocks(title="Quant-Node Pro Elite", theme=gr.themes.Default()) as demo:
99
- gr.HTML("<div style='text-align:center; padding:15px; background:#131722;'><h1 style='color:#2962FF; margin:0;'>QUANT-NODE <span style='color:white;'>ELITE</span></h1></div>")
100
-
101
  with gr.Row():
102
  with gr.Column(scale=1):
103
- ticker = gr.Textbox(label="Market Symbol", value="TSLA")
104
- horizon = gr.Slider(7, 90, value=30, label="Days to Forecast")
105
- btn = gr.Button("EXECUTE QUANT STRATEGY", variant="primary")
106
- output_panel = gr.HTML(label="Intelligence Summary")
107
- with gr.Column(scale=3):
108
- plot = gr.Plot()
109
 
110
- btn.click(analyze_full, [ticker, horizon], [plot, output_panel])
111
 
112
  demo.launch()
 
2
  import pandas as pd
3
  import yfinance as yf
4
  import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
  from statsforecast import StatsForecast
7
  from statsforecast.models import AutoARIMA
 
 
8
 
9
+ def calculate_indicators(df):
10
+ # RSI Calculation
11
+ delta = df['Close'].diff()
12
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
13
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
14
+ rs = gain / loss
15
+ df['RSI'] = 100 - (100 / (1 + rs))
 
 
 
 
 
 
16
 
17
+ # MACD Calculation
18
+ df['EMA12'] = df['Close'].ewm(span=12, adjust=False).mean()
19
+ df['EMA26'] = df['Close'].ewm(span=26, adjust=False).mean()
20
+ df['MACD'] = df['EMA12'] - df['EMA26']
21
+ df['Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
22
+ return df
23
+
24
+ def get_pro_chart(df, forecast_df, ticker):
25
+ # Professional Subplots: Price + Indicators
26
+ fig = make_subplots(rows=3, cols=1, shared_xaxes=True,
27
+ vertical_spacing=0.05, row_heights=[0.5, 0.25, 0.25],
28
+ subplot_titles=(f"{ticker} Forecast", "RSI Momentum", "MACD Trend"))
29
+
30
+ # 1. Price + Forecast
31
+ fig.add_trace(go.Scatter(x=df.index, y=df['Close'], name='Price', line=dict(color='#2962FF')), row=1, col=1)
32
+ fig.add_trace(go.Scatter(x=forecast_df['ds'], y=forecast_df['AutoARIMA'], name='AI Forecast', line=dict(color='#F23645')), row=1, col=1)
33
+
34
+ # 2. RSI
35
+ fig.add_trace(go.Scatter(x=df.index, y=df['RSI'], name='RSI', line=dict(color='#FF9800')), row=2, col=1)
36
+ fig.add_hline(y=70, line_dash="dot", line_color="red", row=2, col=1)
37
+ fig.add_hline(y=30, line_dash="dot", line_color="green", row=2, col=1)
38
+
39
+ # 3. MACD
40
+ fig.add_trace(go.Bar(x=df.index, y=df['MACD'] - df['Signal'], name='Momentum'), row=3, col=1)
41
 
42
+ fig.update_layout(template='plotly_dark', height=800, showlegend=False, paper_bgcolor='#131722', plot_bgcolor='#131722')
43
+ return fig
44
 
45
+ def analyze(ticker, horizon):
46
  try:
47
+ # Step 1: Data + Analyst Targets
48
+ stock = yf.Ticker(ticker)
49
+ df = stock.history(period="1y")
50
+ if df.empty: return None, "Symbol Error", ""
51
+
52
+ info = stock.info
53
+ target_high = info.get('targetHighPrice', 'N/A')
54
+ current_price = df['Close'].iloc[-1]
55
 
56
+ # Step 2: Accuracy Boost via Technicals
57
+ df = calculate_indicators(df)
58
+
59
+ # Step 3: Fast StatsForecast
60
  data = df.reset_index()[['Date', 'Close']]
61
  data.columns = ['ds', 'y']
62
  data['unique_id'] = ticker
63
+
64
+ # Season length 5 = Weekly trading cycle
65
  sf = StatsForecast(models=[AutoARIMA(season_length=5)], freq='B')
66
  sf.fit(data)
67
  forecast = sf.predict(h=horizon, level=[80])
68
 
69
+ # Step 4: Signal Analysis
70
+ rsi_val = df['RSI'].iloc[-1]
71
+ rsi_stat = "OVERSOLD (BUY)" if rsi_val < 30 else "OVERBOUGHT (SELL)" if rsi_val > 70 else "NEUTRAL"
72
 
73
+ signal_html = f"""
74
+ <div style='background: #1e222d; padding: 15px; border-radius: 10px; color: white;'>
75
+ <p>Current Price: <b>${current_price:.2f}</b></p>
76
+ <p>Wall St Target: <b style='color:#00ff88;'>${target_high}</b></p>
77
+ <hr>
78
+ <p>RSI (14d): <b>{rsi_val:.1f} ({rsi_stat})</b></p>
79
+ <p>AI 30d Target: <b>${forecast['AutoARIMA'].iloc[-1]:.2f}</b></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  </div>
81
  """
82
+
83
+ return get_pro_chart(df, forecast, ticker), signal_html
84
  except Exception as e:
85
+ return None, f"Error: {str(e)}"
86
 
87
+ # --- UI Layout ---
88
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
89
+ gr.Markdown("# 🏛️ INSTITUTIONAL QUANT TERMINAL")
 
90
  with gr.Row():
91
  with gr.Column(scale=1):
92
+ t_in = gr.Textbox(label="Ticker Symbol", value="NVDA")
93
+ h_in = gr.Slider(7, 90, value=30, label="Forecast Days")
94
+ btn = gr.Button("RUN ANALYSIS", variant="primary")
95
+ info_out = gr.HTML()
96
+ with gr.Column(scale=4):
97
+ plot_out = gr.Plot()
98
 
99
+ btn.click(analyze, [t_in, h_in], [plot_out, info_out])
100
 
101
  demo.launch()