deveshc23 commited on
Commit
5736d03
Β·
verified Β·
1 Parent(s): 917c743

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +92 -18
app.py CHANGED
@@ -22,6 +22,20 @@ import numpy as np
22
  import plotly.graph_objects as go
23
  from plotly.subplots import make_subplots
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # -----------------------------------------------------------------------------
26
  # Hugging Face Hub / Gradio 4.42 Compatibility Shim
27
  # -----------------------------------------------------------------------------
@@ -331,21 +345,46 @@ def generate_kpi_card_html(ticker: str) -> str:
331
  def generate_macro_hud_html() -> str:
332
  """Generates high-contrast HUD cards for Macro & Quantitative Regime."""
333
  snap = STATE["macro_snapshot"]
334
- yield_slope = snap.get("yield_curve_slope", -0.55)
335
- is_inverted = snap.get("inverted_yield_curve", True)
336
  slope_color = "#ff3366" if is_inverted else "#00ff87"
337
- slope_text = "INVERTED (-0.55%)" if is_inverted else f"+{yield_slope:.2f}% (NORMAL)"
338
 
339
  vix_val = snap.get("vix", 16.50)
340
  vix_color = "#ff3366" if vix_val > 25 else ("#00ff87" if vix_val < 18 else "#ffb703")
341
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  return f"""
343
  <div class="hud-container">
344
  <!-- Card 1: Macro Radar -->
345
  <div class="hud-card">
346
  <div class="hud-title">
347
  <span style="color:#00f2fe;">🌐 MACROECONOMIC RADAR</span>
348
- <span class="hud-tag">REAL-TIME FEEDS</span>
349
  </div>
350
  <div class="hud-grid-row">
351
  <div class="hud-stat-box">
@@ -373,6 +412,7 @@ def generate_macro_hud_html() -> str:
373
  <div class="hud-val">{snap.get('usd_index', 104.20):.2f}</div>
374
  </div>
375
  </div>
 
376
  </div>
377
 
378
  <!-- Card 2: Quantitative Regime -->
@@ -731,16 +771,25 @@ def handle_run_quantagent(trading_idea: str, max_rounds: int, threshold: float):
731
  traj_md += f"> **Mentor Critique & Feedback:**\n> {critique}\n\n"
732
 
733
  status_badge = "🟒 ACCEPTED INTO KNOWLEDGE BASE" if rec.get("status") == "ACCEPTED" else "🟑 PENDING REFINEMENT"
 
 
 
 
 
 
 
 
 
734
  status_md = f"""
735
  ### Outer Feedback Loop Backtest Results: {status_badge}
736
- - **Signal Name**: `{rec.get('name', 'N/A')}`
737
- - **Information Coefficient (IC Mean)**: `{rec.get('ic_mean', 0.0):.4f}`
738
- - **IC Information Ratio (IC_IR)**: `{rec.get('ic_ir', 0.0):.3f}`
739
- - **Annualized Sharpe Ratio**: **`{rec.get('sharpe', 0.0):.2f}`**
740
- - **Annualized Return**: **`{rec.get('annualized_return_pct', 0.0):.2f}%`**
741
- - **Max Drawdown**: `{rec.get('max_drawdown_pct', 0.0):.2f}%`
742
- - **Turnover Rate**: `{rec.get('turnover_pct', 0.0):.1f}%`
743
- - **Valid Data Ratio**: `{rec.get('valid_ratio', 1.0):.1%}`
744
  """
745
 
746
  cum_fig = plot_backtest_cumulative(rec)
@@ -844,9 +893,10 @@ $$\\text{{ROE}} = \\text{{Net Profit Margin}} \\times \\text{{Asset Turnover}} \
844
 
845
 
846
  def handle_news_lookup(ticker: str):
847
- """Fetches live news headlines and calculates sentiment polarity."""
848
  ticker = ticker.strip().upper()
849
- items = news_service.fetch_ticker_news(ticker, max_items=6)
 
850
  if not items:
851
  return "No recent news found.", pd.DataFrame()
852
 
@@ -856,10 +906,22 @@ def handle_news_lookup(ticker: str):
856
  mean_score = df["Polarity Score"].mean()
857
  sentiment_label = "🟒 Bullish / Positive" if mean_score > 0.15 else ("πŸ”΄ Bearish / Negative" if mean_score < -0.15 else "🟑 Neutral")
858
 
 
 
 
 
 
 
 
 
 
 
859
  summary_md = f"""
860
- ### πŸ“° Live News & Sentiment Catalyst Radar: `{ticker}`
 
861
  - **Overall Catalyst Bias**: **`{sentiment_label}`** (Average Polarity: `{mean_score:+.2f}`)
862
  - **Analyzed Articles Count**: `{len(items)}`
 
863
  - **Signal Impact**: Real-time sentiment feeds modulate alpha exposure weights in the Multi-Agent Synthesizer.
864
  """
865
  return summary_md, df
@@ -1490,8 +1552,8 @@ Enter your Hugging Face write token and the target Space ID (`deveshc23/quantage
1490
  gr.Markdown("### πŸ”‘ Optional API Keys (Upgrades functionality)")
1491
  with gr.Row():
1492
  gemini_key_input = gr.Textbox(label="Google Gemini API Key", type="password", placeholder="AIza...")
1493
- finnhub_key_input = gr.Textbox(label="Finnhub API Key", type="password", placeholder="Optional...")
1494
- fred_key_input = gr.Textbox(label="FRED API Key", type="password", placeholder="Optional...")
1495
  save_keys_btn = gr.Button("Save API Keys")
1496
 
1497
  def save_keys_action(gemini_k, finnhub_k, fred_k):
@@ -1500,9 +1562,21 @@ Enter your Hugging Face write token and the target Space ID (`deveshc23/quantage
1500
  quant_engine.llm = llm_client
1501
  if finnhub_k:
1502
  news_service.finnhub_key = finnhub_k
 
1503
  if fred_k:
1504
  macro_service.fred_key = fred_k
1505
- return "βœ… API Keys updated successfully!"
 
 
 
 
 
 
 
 
 
 
 
1506
 
1507
  keys_status_md = gr.Markdown("")
1508
  save_keys_btn.click(save_keys_action, [gemini_key_input, finnhub_key_input, fred_key_input], keys_status_md)
 
22
  import plotly.graph_objects as go
23
  from plotly.subplots import make_subplots
24
 
25
+ # Auto-load .env file if present
26
+ _env_path = os.path.join(os.path.dirname(__file__), ".env")
27
+ if os.path.exists(_env_path):
28
+ try:
29
+ with open(_env_path, "r", encoding="utf-8") as _ef:
30
+ for _line in _ef:
31
+ _line = _line.strip()
32
+ if _line and not _line.startswith("#") and "=" in _line:
33
+ _k, _v = _line.split("=", 1)
34
+ if _k.strip() not in os.environ:
35
+ os.environ[_k.strip()] = _v.strip()
36
+ except Exception:
37
+ pass
38
+
39
  # -----------------------------------------------------------------------------
40
  # Hugging Face Hub / Gradio 4.42 Compatibility Shim
41
  # -----------------------------------------------------------------------------
 
345
  def generate_macro_hud_html() -> str:
346
  """Generates high-contrast HUD cards for Macro & Quantitative Regime."""
347
  snap = STATE["macro_snapshot"]
348
+ yield_slope = snap.get("yield_curve_slope", 0.31)
349
+ is_inverted = snap.get("inverted_yield_curve", False)
350
  slope_color = "#ff3366" if is_inverted else "#00ff87"
351
+ slope_text = f"{yield_slope:+.2f}% ({'INVERTED' if is_inverted else 'NORMAL'})"
352
 
353
  vix_val = snap.get("vix", 16.50)
354
  vix_color = "#ff3366" if vix_val > 25 else ("#00ff87" if vix_val < 18 else "#ffb703")
355
 
356
+ fred_tag = '<span class="hud-tag" style="border-color:#00ff87; color:#00ff87;">ST. LOUIS FED (FRED) ACTIVE</span>' if snap.get("fred_active") else '<span class="hud-tag">REAL-TIME FEEDS</span>'
357
+
358
+ fedfunds_row = ""
359
+ if snap.get("fred_active"):
360
+ fedfunds_row = f"""
361
+ <div class="hud-grid-row" style="margin-top:6px; border-top:1px solid rgba(255,255,255,0.06); padding-top:6px;">
362
+ <div class="hud-stat-box">
363
+ <div class="hud-lbl">FED FUNDS RATE</div>
364
+ <div class="hud-val" style="color:#00f2fe;">{snap.get('fed_funds_rate', 3.75)}%</div>
365
+ </div>
366
+ <div class="hud-stat-box">
367
+ <div class="hud-lbl">UNEMPLOYMENT</div>
368
+ <div class="hud-val">{snap.get('unemployment_rate', 4.20)}%</div>
369
+ </div>
370
+ <div class="hud-stat-box">
371
+ <div class="hud-lbl">HY CREDIT SPREAD</div>
372
+ <div class="hud-val">{snap.get('high_yield_spread', 3.40)}%</div>
373
+ </div>
374
+ <div class="hud-stat-box">
375
+ <div class="hud-lbl">SPY 200DMA STATUS</div>
376
+ <div class="hud-val" style="color:#00ff87; font-size:11px;">BULLISH TREND</div>
377
+ </div>
378
+ </div>
379
+ """
380
+
381
  return f"""
382
  <div class="hud-container">
383
  <!-- Card 1: Macro Radar -->
384
  <div class="hud-card">
385
  <div class="hud-title">
386
  <span style="color:#00f2fe;">🌐 MACROECONOMIC RADAR</span>
387
+ {fred_tag}
388
  </div>
389
  <div class="hud-grid-row">
390
  <div class="hud-stat-box">
 
412
  <div class="hud-val">{snap.get('usd_index', 104.20):.2f}</div>
413
  </div>
414
  </div>
415
+ {fedfunds_row}
416
  </div>
417
 
418
  <!-- Card 2: Quantitative Regime -->
 
771
  traj_md += f"> **Mentor Critique & Feedback:**\n> {critique}\n\n"
772
 
773
  status_badge = "🟒 ACCEPTED INTO KNOWLEDGE BASE" if rec.get("status") == "ACCEPTED" else "🟑 PENDING REFINEMENT"
774
+ rec_name = str(rec.get('name', 'N/A'))
775
+ ic_str = f"{float(rec.get('ic_mean', 0.0)):.4f}"
776
+ ic_ir_str = f"{float(rec.get('ic_ir', 0.0)):.3f}"
777
+ sharpe_str = f"{float(rec.get('sharpe', 0.0)):.2f}"
778
+ ann_ret_str = f"{float(rec.get('annualized_return_pct', 0.0)):.2f}"
779
+ mdd_str = f"{float(rec.get('max_drawdown_pct', 0.0)):.2f}"
780
+ turnover_str = f"{float(rec.get('turnover_pct', 0.0)):.1f}"
781
+ valid_str = f"{float(rec.get('valid_ratio', 1.0)):.1%}"
782
+
783
  status_md = f"""
784
  ### Outer Feedback Loop Backtest Results: {status_badge}
785
+ - **Signal Name**: `{rec_name}`
786
+ - **Information Coefficient (IC Mean)**: `{ic_str}`
787
+ - **IC Information Ratio (IC_IR)**: `{ic_ir_str}`
788
+ - **Annualized Sharpe Ratio**: **`{sharpe_str}`**
789
+ - **Annualized Return**: **`{ann_ret_str}%`**
790
+ - **Max Drawdown**: `{mdd_str}%`
791
+ - **Turnover Rate**: `{turnover_str}%`
792
+ - **Valid Data Ratio**: `{valid_str}`
793
  """
794
 
795
  cum_fig = plot_backtest_cumulative(rec)
 
893
 
894
 
895
  def handle_news_lookup(ticker: str):
896
+ """Fetches live news headlines, analyst consensus, and calculates sentiment polarity."""
897
  ticker = ticker.strip().upper()
898
+ items = news_service.fetch_ticker_news(ticker, max_items=8)
899
+ recs = news_service.fetch_finnhub_recommendations(ticker)
900
  if not items:
901
  return "No recent news found.", pd.DataFrame()
902
 
 
906
  mean_score = df["Polarity Score"].mean()
907
  sentiment_label = "🟒 Bullish / Positive" if mean_score > 0.15 else ("πŸ”΄ Bearish / Negative" if mean_score < -0.15 else "🟑 Neutral")
908
 
909
+ rec_md = ""
910
+ if recs:
911
+ total = recs['strong_buy'] + recs['buy'] + recs['hold'] + recs['sell'] + recs['strong_sell']
912
+ bull_pct = round((recs['strong_buy'] + recs['buy']) / max(1, total) * 100, 1)
913
+ rec_md = f"""
914
+ #### πŸ“Š Wall Street Analyst Consensus (Finnhub Feed - {recs.get('period', 'Latest')})
915
+ - **Consensus Rating**: **{bull_pct}% Bullish Recommendation** ({recs['strong_buy'] + recs['buy']} Buy / {total} Total Analysts)
916
+ - **Breakdown**: 🟒 Strong Buy: `{recs['strong_buy']}` | 🟒 Buy: `{recs['buy']}` | 🟑 Hold: `{recs['hold']}` | πŸ”΄ Sell: `{recs['sell']}` | πŸ”΄ Strong Sell: `{recs['strong_sell']}`
917
+ """
918
+
919
  summary_md = f"""
920
+ ### πŸ“° Institutional News & Sentiment Catalyst Radar: `{ticker}`
921
+ {rec_md}
922
  - **Overall Catalyst Bias**: **`{sentiment_label}`** (Average Polarity: `{mean_score:+.2f}`)
923
  - **Analyzed Articles Count**: `{len(items)}`
924
+ - **Data Feed**: `{'Finnhub Institutional News API' if news_service.finnhub_key else 'Yahoo Financial RSS'}`
925
  - **Signal Impact**: Real-time sentiment feeds modulate alpha exposure weights in the Multi-Agent Synthesizer.
926
  """
927
  return summary_md, df
 
1552
  gr.Markdown("### πŸ”‘ Optional API Keys (Upgrades functionality)")
1553
  with gr.Row():
1554
  gemini_key_input = gr.Textbox(label="Google Gemini API Key", type="password", placeholder="AIza...")
1555
+ finnhub_key_input = gr.Textbox(label="Finnhub API Key", type="password", value=os.environ.get("FINNHUB_API_KEY", ""), placeholder="Optional...")
1556
+ fred_key_input = gr.Textbox(label="FRED API Key", type="password", value=os.environ.get("FRED_API_KEY", ""), placeholder="Optional...")
1557
  save_keys_btn = gr.Button("Save API Keys")
1558
 
1559
  def save_keys_action(gemini_k, finnhub_k, fred_k):
 
1562
  quant_engine.llm = llm_client
1563
  if finnhub_k:
1564
  news_service.finnhub_key = finnhub_k
1565
+ os.environ["FINNHUB_API_KEY"] = finnhub_k
1566
  if fred_k:
1567
  macro_service.fred_key = fred_k
1568
+ os.environ["FRED_API_KEY"] = fred_k
1569
+ STATE["macro_snapshot"] = macro_service.get_macro_snapshot()
1570
+ # Persist to local .env
1571
+ try:
1572
+ with open(".env", "w", encoding="utf-8") as ef:
1573
+ if os.environ.get("FINNHUB_API_KEY"):
1574
+ ef.write(f"FINNHUB_API_KEY={os.environ['FINNHUB_API_KEY']}\n")
1575
+ if os.environ.get("FRED_API_KEY"):
1576
+ ef.write(f"FRED_API_KEY={os.environ['FRED_API_KEY']}\n")
1577
+ except Exception:
1578
+ pass
1579
+ return "βœ… API Keys updated, activated, and persisted!"
1580
 
1581
  keys_status_md = gr.Markdown("")
1582
  save_keys_btn.click(save_keys_action, [gemini_key_input, finnhub_key_input, fred_key_input], keys_status_md)