diff --git a/backend/routers/market_events.py b/backend/routers/market_events.py index d19a1f7..183543c 100644 --- a/backend/routers/market_events.py +++ b/backend/routers/market_events.py @@ -84,6 +84,45 @@ _SORT_COLS = { "instrument_score": "COALESCE(ii.adjusted_score, ii.impact_score)", } +@router.get("/db-status") +def db_status() -> Dict[str, Any]: + """Quick health-check of all tables needed for market event generation.""" + from services.database import get_conn + conn = get_conn() + status: Dict[str, Any] = {} + + tables = { + "market_events": "SELECT COUNT(*), MAX(created_at) FROM market_events", + "economic_events": "SELECT COUNT(*), MAX(fetched_at) FROM economic_events", + "macro_gauge_snapshots":"SELECT COUNT(*), MAX(snapshot_date) FROM macro_gauge_snapshots", + "macro_regime_history": "SELECT COUNT(*), MAX(timestamp) FROM macro_regime_history", + "institutional_reports":"SELECT COUNT(*), MAX(fetch_date) FROM institutional_reports", + "ai_desks": "SELECT COUNT(*), NULL FROM ai_desks", + } + for table, sql in tables.items(): + try: + row = conn.execute(sql).fetchone() + status[table] = {"count": row[0], "latest": row[1]} + except Exception as e: + status[table] = {"count": 0, "latest": None, "error": str(e)} + + # Check market_events columns + existing_cols = {row[1] for row in conn.execute("PRAGMA table_info(market_events)").fetchall()} + required_cols = ["sub_type", "origin", "source_refs", "actual_value", "expected_value", "surprise_pct"] + status["market_events"]["columns_ok"] = all(c in existing_cols for c in required_cols) + status["market_events"]["missing_columns"] = [c for c in required_cols if c not in existing_cols] + + # Summary of ai_desks types + try: + desks = conn.execute("SELECT type, active FROM ai_desks").fetchall() + status["ai_desks"]["desks"] = [{"type": r[0], "active": bool(r[1])} for r in desks] + except Exception: + pass + + conn.close() + return status + + @router.get("") def list_events( # text / category / level @@ -91,9 +130,12 @@ def list_events( category: Optional[str] = Query(None), level: Optional[str] = Query(None), origin: Optional[str] = Query(None), - # date range + # event date range (start_date) date_from: Optional[str] = Query(None), date_to: Optional[str] = Query(None), + # generation date range (created_at) + gen_date_from: Optional[str] = Query(None, description="Filter by generation date (created_at) from"), + gen_date_to: Optional[str] = Query(None, description="Filter by generation date (created_at) to"), # global impact score min_score: float = Query(0.0, ge=0.0, le=1.0), # instrument impact filter @@ -143,6 +185,12 @@ def list_events( if date_to: where_parts.append("me.start_date<=?") params.append(date_to) + if gen_date_from: + where_parts.append("date(me.created_at)>=?") + params.append(gen_date_from) + if gen_date_to: + where_parts.append("date(me.created_at)<=?") + params.append(gen_date_to) if min_score > 0: where_parts.append("me.impact_score>=?") params.append(min_score) diff --git a/backend/services/database.py b/backend/services/database.py index ca15087..a9032a7 100644 --- a/backend/services/database.py +++ b/backend/services/database.py @@ -774,6 +774,8 @@ def init_db(): ("surprise_pct", "REAL DEFAULT NULL"), ("unit", "TEXT DEFAULT NULL"), ("sub_type", "TEXT DEFAULT NULL"), + ("origin", "TEXT DEFAULT NULL"), + ("source_refs", "TEXT DEFAULT '[]'"), ]: try: c.execute(f"ALTER TABLE market_events ADD COLUMN {_col} {_def}") diff --git a/frontend/src/pages/MarketEvents.tsx b/frontend/src/pages/MarketEvents.tsx index 9834ec7..c13b554 100644 --- a/frontend/src/pages/MarketEvents.tsx +++ b/frontend/src/pages/MarketEvents.tsx @@ -45,6 +45,7 @@ interface MarketEvent { absorption_pct: number | null source_refs: SourceRef[] origin?: string + created_at?: string impacts?: InstrumentImpact[] evaluated?: boolean } @@ -780,6 +781,11 @@ function EventRow({ {(ORIGIN_META[ev.origin] ?? ORIGIN_META['unknown']).icon} )} + {ev.created_at && ( + + ⚡{ev.created_at.slice(5, 10)} + + )}
@@ -1130,6 +1136,9 @@ export default function MarketEvents() { const [dateFrom, setDateFrom] = useState('') const [dateTo, setDateTo] = useState('') const [datePreset, setDatePreset] = useState('all') // 7d|30d|90d|6m|1y|all|custom + // Generation date filter (created_at) + const [genFrom, setGenFrom] = useState('') + const [genTo, setGenTo] = useState('') // Instrument impact filter const [instTicker, setInstTicker] = useState('') const [instMinScore, setInstMin] = useState(0.3) @@ -1177,6 +1186,8 @@ export default function MarketEvents() { if (minScore) params.set('min_score', String(minScore)) if (dateFrom) params.set('date_from', dateFrom) if (dateTo) params.set('date_to', dateTo) + if (genFrom) params.set('gen_date_from', genFrom) + if (genTo) params.set('gen_date_to', genTo) if (evaluated) params.set('evaluated', evaluated) if (instTicker) { params.set('instrument', instTicker) @@ -1197,7 +1208,7 @@ export default function MarketEvents() { if (e.name === 'AbortError') return // superseded by a newer load } setLoading(false) - }, [search, category, level, minScore, dateFrom, dateTo, evaluated, + }, [search, category, level, minScore, dateFrom, dateTo, genFrom, genTo, evaluated, instTicker, instMinScore, instDir, sortBy, sortDir]) useEffect(() => { @@ -1418,6 +1429,34 @@ export default function MarketEvents() {
)} + + {/* ── Generation date filter ── */} +
+
+ ⚡ Date de génération + {(genFrom || genTo) && ( + + )} +
+
+
+
Généré depuis
+ setGenFrom(e.target.value)} + className="w-full bg-dark-900 border border-slate-700 rounded px-2 py-1 text-slate-300 text-xs" /> +
+
+
Généré jusqu'à
+ setGenTo(e.target.value)} + className="w-full bg-dark-900 border border-slate-700 rounded px-2 py-1 text-slate-300 text-xs" /> +
+
+ {(genFrom || genTo) && ( +
+ ⚡ Filtre actif sur date de génération (created_at) +
+ )} +
)} @@ -1439,10 +1478,11 @@ export default function MarketEvents() {
{loading ? '...' : total} événement{total !== 1 ? 's' : ''} {instTicker && · impact {instTicker}} - {(category || level || search || minScore > 0 || evaluated || dateFrom || dateTo || instTicker) && ( + {(category || level || search || minScore > 0 || evaluated || dateFrom || dateTo || genFrom || genTo || instTicker) && ( )}