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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -61
app.py CHANGED
@@ -6,49 +6,42 @@ from statsforecast import StatsForecast
6
  from statsforecast.models import AutoARIMA
7
  import nltk
8
  from nltk.sentiment.vader import SentimentIntensityAnalyzer
9
- import requests
10
 
11
- # Setup AI Sentiment
12
  try:
13
  nltk.data.find('vader_lexicon')
14
  except LookupError:
15
  nltk.download('vader_lexicon')
16
  sia = SentimentIntensityAnalyzer()
17
 
18
- def get_market_mood():
19
- # Fetching the global 'Fear & Greed' sentiment
20
- try:
21
- # Note: In a real prod environment, you'd use a dedicated API key for CNN/FNG
22
- # For this terminal, we simulate the current 2026 index reading
23
- return 45, "Neutral"
24
- except:
25
- return 50, "Unknown"
26
-
27
- def get_news_sentiment(ticker):
28
- # Fetch latest headlines via yfinance
29
- stock = yf.Ticker(ticker)
30
- news = stock.news[:5] # Get top 5 stories
31
- if not news: return 0, "No recent news found."
32
 
 
 
 
33
  scores = []
34
- headlines_text = ""
35
  for article in news:
36
- title = article['title']
37
- score = sia.polarity_scores(title)['compound']
38
- scores.append(score)
39
- sentiment_label = "🟢" if score > 0.1 else "🔴" if score < -0.1 else "⚪"
40
- headlines_text += f"{sentiment_label} {title}<br>"
41
 
42
- avg_score = sum(scores) / len(scores)
43
- return avg_score, headlines_text
44
 
45
- def analyze_pro(ticker, horizon):
46
  try:
47
- # 1. Market Data
48
  df = yf.download(ticker, period="1y", multi_level_index=False)
49
- if df.empty: return None, "⚠️ Symbol Error", ""
50
 
51
- # 2. AI Forecasting (Math)
52
  data = df.reset_index()[['Date', 'Close']]
53
  data.columns = ['ds', 'y']
54
  data['unique_id'] = ticker
@@ -56,54 +49,64 @@ def analyze_pro(ticker, horizon):
56
  sf.fit(data)
57
  forecast = sf.predict(h=horizon, level=[80])
58
 
59
- # 3. Sentiment Intelligence (Mood)
60
- sent_score, headlines = get_news_sentiment(ticker)
61
- mood_val, mood_label = get_market_mood()
62
 
63
- # 4. Accuracy Correlation Logic
64
- # If Math is Bullish but Sentiment is Negative, we lower the 'Confidence'
65
  math_move = ((forecast['AutoARIMA'].iloc[-1] - df['Close'].iloc[-1]) / df['Close'].iloc[-1]) * 100
66
- conf_score = 90 if (math_move > 0 and sent_score > 0) or (math_move < 0 and sent_score < 0) else 65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- # UI Components
 
 
 
69
  color = "#00ff88" if math_move > 0 else "#ff4444"
70
- mood_color = "#FFD700" if mood_label == "Neutral" else "#ff4444"
71
 
72
- summary_html = f"""
73
- <div style='background: #1e222d; padding: 15px; border-radius: 10px; border-left: 5px solid {color};'>
74
- <h3 style='margin:0; color:{color};'>PROJECTION: {'BULLISH' if math_move > 0 else 'BEARISH'}</h3>
75
- <p style='font-size: 20px;'>Target: <b>${forecast['AutoARIMA'].iloc[-1]:.2f}</b> ({math_move:+.2f}%)</p>
76
- <p>AI Confidence: <b>{conf_score}%</b></p>
77
- <hr style='border: 0.5px solid #363c4e;'>
78
- <p>🌍 Global Market Mood: <b style='color:{mood_color};'>{mood_label} ({mood_val}/100)</b></p>
79
- <p style='font-size: 12px; color: #787b86;'>{headlines}</p>
80
  </div>
81
  """
82
-
83
- # Charting
84
- fig = go.Figure()
85
- fig.add_trace(go.Scatter(x=df.index, y=df['Close'], name='History', line=dict(color='#2962FF')))
86
- fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['AutoARIMA'], name='AI Forecast', line=dict(color='#F23645')))
87
- fig.update_layout(template='plotly_dark', paper_bgcolor='#131722', plot_bgcolor='#131722', margin=dict(l=0,r=0,t=0,b=0))
88
-
89
- return fig, summary_html
90
 
91
  except Exception as e:
92
- return None, f"<div style='color:red;'>Terminal Error: {str(e)}</div>"
93
 
94
- # --- GRADIO INTERFACE ---
95
- with gr.Blocks(title="Quant-Node Pro 2026", theme=gr.themes.Default()) as demo:
96
- gr.HTML("<div style='text-align:center; padding:20px; background:#131722;'><h1 style='color:#2962FF; margin:0;'>QUANT-NODE <span style='color:white;'>PRO</span></h1><p style='color:#787b86;'>Sentiment-Aware Forecasting Engine</p></div>")
97
 
98
  with gr.Row():
99
  with gr.Column(scale=1):
100
- ticker = gr.Textbox(label="Ticker Symbol", value="AAPL")
101
  horizon = gr.Slider(7, 90, value=30, label="Days to Forecast")
102
- btn = gr.Button("GENERATE INTELLIGENCE", variant="primary")
103
- stats = gr.HTML()
104
  with gr.Column(scale=3):
105
- chart = gr.Plot()
106
 
107
- btn.click(analyze_pro, [ticker, horizon], [chart, stats])
108
 
109
  demo.launch()
 
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
 
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()