feat: Phase 2 + context log — FRED releases, cycle context snapshot, onglet Contexte IA
Phase 2 — Données macro FRED :
- fred_fetcher.py (nouveau) : 7 séries FRED (CPI, NFP, UNRATE, FEDFUNDS, GDP, ICSA,
spread 10Y-2Y) avec détection direction bullish/bearish et block prompt formaté
- ai_analyzer.py : param fred_block dans suggest + score, injecté dans les deux prompts
- auto_cycle.py : fetch FRED non-bloquant avant la suggestion
Context log — Snapshot du contexte complet :
- database.py : table cycle_context_snapshots + save/get/list fonctions
- auto_cycle.py : sauvegarde le snapshot (meta, news partitionnées, FRED, tech, IV, quotes)
- cycle.py : GET /api/cycle/contexts + GET /api/cycle/contexts/{run_id}
- useApi.ts : hooks useCycleContextSnapshots + useCycleContextSnapshot
- SystemLogs.tsx : onglet "Contexte IA" avec liste de cycles et visualiseur JSON
par section (cycle_meta, macro, news, FRED, tech) avec accordéon
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -174,7 +174,7 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
save_pattern_scores, log_macro_regime, log_geo_alert, log_trade_entries,
|
||||
add_cycle_run, update_cycle_run, save_reasoning_trace,
|
||||
get_latest_portfolio_lessons, log_system_event,
|
||||
get_last_completed_cycle_ts,
|
||||
get_last_completed_cycle_ts, save_cycle_context_snapshot,
|
||||
)
|
||||
from services.data_fetcher import fetch_geo_news, get_all_quotes, get_macro_gauges, score_macro_scenarios
|
||||
from services.geo_analyzer import compute_geo_risk_score
|
||||
@@ -370,6 +370,18 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
logger.info(f"[Cycle {run_id[:16]}] Reliability map: {len(_reliability_map)} patterns")
|
||||
except Exception as _re:
|
||||
logger.warning(f"[Cycle] Reliability map failed (non-blocking): {_re}")
|
||||
# ── Phase 2: FRED recent macro releases ──────────────────────────────
|
||||
_fred_releases = []
|
||||
_fred_block = ""
|
||||
try:
|
||||
from services.fred_fetcher import get_fred_recent_releases, build_fred_context_block
|
||||
_fred_releases = get_fred_recent_releases()
|
||||
_fred_block = build_fred_context_block(_fred_releases)
|
||||
if _fred_releases:
|
||||
logger.info(f"[Cycle {run_id[:16]}] FRED: {len(_fred_releases)} releases fetched")
|
||||
except Exception as _fe:
|
||||
logger.warning(f"[Cycle] FRED fetch failed (non-blocking): {_fe}")
|
||||
|
||||
try:
|
||||
from services.data_fetcher import get_economic_calendar
|
||||
calendar = get_economic_calendar()
|
||||
@@ -406,6 +418,34 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
except Exception as _te:
|
||||
logger.warning(f"[Cycle] Tech indicators failed (non-blocking): {_te}")
|
||||
|
||||
# ── Save full context snapshot ─────────────────────────────────
|
||||
try:
|
||||
from services.ai_analyzer import apply_news_decay as _apply_decay2, partition_news_by_age as _part
|
||||
_news_snap = _part(_apply_decay2(news), cycle_meta.get("delta_minutes", 180))
|
||||
_context_snapshot = {
|
||||
"cycle_meta": cycle_meta,
|
||||
"macro_regime": {
|
||||
"dominant": (macro_regime or {}).get("scenarios", {}).get("dominant"),
|
||||
"scores": (macro_regime or {}).get("scenarios", {}).get("scores"),
|
||||
"gauges_summary": {k: v.get("value") for k, v in ((macro_regime or {}).get("gauges", {})).items()},
|
||||
},
|
||||
"geo_score": geo_score_obj,
|
||||
"news_partitioned": {
|
||||
"inter_cycle": [{"title": n.get("title"), "source": n.get("source"), "decayed_score": n.get("decayed_score"), "age_hours": n.get("age_hours")} for n in _news_snap["inter_cycle"][:10]],
|
||||
"recent_24h": [{"title": n.get("title"), "source": n.get("source"), "decayed_score": n.get("decayed_score")} for n in _news_snap["recent_24h"][:10]],
|
||||
"older": [{"title": n.get("title"), "source": n.get("source")} for n in _news_snap["older"][:5]],
|
||||
},
|
||||
"fred_releases": _fred_releases,
|
||||
"tech_indicators_block": _tech_block,
|
||||
"iv_context_preview": iv_context[:500] if iv_context else "",
|
||||
"calendar": calendar[:8] if calendar else [],
|
||||
"quotes_summary": {cls: [{"symbol": q.get("symbol"), "price": q.get("price"), "change_pct": q.get("change_pct")} for q in qs[:3]] for cls, qs in quotes.items()},
|
||||
}
|
||||
save_cycle_context_snapshot(run_id, _context_snapshot)
|
||||
logger.info(f"[Cycle {run_id[:16]}] Context snapshot saved")
|
||||
except Exception as _snap_e:
|
||||
logger.warning(f"[Cycle] Context snapshot save failed (non-blocking): {_snap_e}")
|
||||
|
||||
suggestions = suggest_patterns_from_market_context(
|
||||
news, quotes, calendar, macro_regime=macro_regime, geo_score=geo_score_obj,
|
||||
portfolio_lessons=portfolio_lessons,
|
||||
@@ -413,6 +453,7 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
iv_context=iv_context,
|
||||
cycle_meta=cycle_meta,
|
||||
tech_indicators_block=_tech_block,
|
||||
fred_block=_fred_block,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"[Cycle] Suggestion step failed: {e}")
|
||||
@@ -537,6 +578,7 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
risk_context=risk_cluster_context,
|
||||
cycle_meta=cycle_meta,
|
||||
tech_indicators_block=_tech_block,
|
||||
fred_block=_fred_block,
|
||||
)
|
||||
scored_with_id = [s for s in scored if s.get("pattern_id")]
|
||||
scored_without_id = [s for s in scored if not s.get("pattern_id")]
|
||||
|
||||
Reference in New Issue
Block a user