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:
OpenSquared
2026-06-20 16:51:02 +02:00
parent 50ba75e468
commit 9c0ebbd138
7 changed files with 451 additions and 13 deletions

View File

@@ -379,6 +379,12 @@ def init_db():
details TEXT
)""")
c.execute("""CREATE TABLE IF NOT EXISTS cycle_context_snapshots (
run_id TEXT PRIMARY KEY,
ts TEXT NOT NULL DEFAULT (datetime('now')),
context_json TEXT NOT NULL
)""")
c.execute("""CREATE TABLE IF NOT EXISTS skipped_trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
run_id TEXT,
@@ -2090,6 +2096,40 @@ def clear_system_logs(older_than_days: int = 30) -> int:
return deleted
# ── Cycle Context Snapshots ───────────────────────────────────────────────────
def save_cycle_context_snapshot(run_id: str, context: dict) -> None:
import json as _json
conn = get_conn()
conn.execute(
"INSERT OR REPLACE INTO cycle_context_snapshots (run_id, context_json) VALUES (?, ?)",
(run_id, _json.dumps(context, ensure_ascii=False, default=str)),
)
conn.commit()
conn.close()
def get_cycle_context_snapshot(run_id: str) -> Optional[dict]:
import json as _json
conn = get_conn()
row = conn.execute(
"SELECT run_id, ts, context_json FROM cycle_context_snapshots WHERE run_id = ?", (run_id,)
).fetchone()
conn.close()
if not row:
return None
return {"run_id": row["run_id"], "ts": row["ts"], "context": _json.loads(row["context_json"])}
def list_cycle_context_snapshots(limit: int = 30) -> list:
conn = get_conn()
rows = conn.execute(
"SELECT run_id, ts FROM cycle_context_snapshots ORDER BY ts DESC LIMIT ?", (limit,)
).fetchall()
conn.close()
return [{"run_id": r["run_id"], "ts": r["ts"]} for r in rows]
# ── Knowledge Base Decay ──────────────────────────────────────────────────────
def decay_kb_confidence() -> int: