New grammar panel replaces free-text AI prompt with a two-step workflow:
1. NL to Grammar: GPT-4o converts description to patch ops (new endpoint ai-to-grammar)
2. Apply: frontend parser applies grammar locally without AI
Grammar syntax: (+|-|~)(node|edge|coef|input|instruments) key=val key=val
Sign shortcuts: + positive, - negative, = neutral
Auto-positions new nodes when x/y omitted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Library:
- Color chip filters: category (with per-category colors), sub_type, instrument
- Date range filter (created_at) + text search
- Category labels unified to cover event_calendar, fundamental, calendar_event etc.
- Editer button on selected template → opens in editor tab
- Show created_at + created_by in template detail
Editor:
- Accepts initialId prop so Library can pre-load a template
- AI Modify zone: textarea prompt + button calls /api/causal-lab/template/{id}/ai-modify
- Returns modified graph_json from GPT-4o, applied live — user reviews then saves
Backend:
- New POST /api/causal-lab/template/{id}/ai-modify endpoint
- Sends current graph_json + user prompt to GPT-4o
- Returns validated modified graph_json (nodes/edges required)
- Does not auto-save (user controls save)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
YFINANCE_MAP now includes GBPUSD, USDJPY, USDCHF, AUDUSD, NZDUSD, USDCAD, XAGUSD, NASDAQ, DAX, FTSE, WTI, US30Y, DXY.
Frontend diagnostic panel shows db_state rows after Recalculer and raw prediction_json prefix per event.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- refreshDebug state lives in parent (InstrumentDashboard) so it survives
fetchSnapshotSilent re-render (ExplanationScore no longer loses debugInfo
when onRefreshDone triggers setLoading → unmount)
- fetchSnapshotSilent: re-fetches snapshot without setLoading(true) so
ExplanationScore stays mounted with its state
- Refresh filter now catches rows where prediction_json is empty even if
actual_json is populated, and handles '[]' / null variants
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_run_auto_analysis now returns a rich dict {ok, inputs, node_values, actual_moves, error}
instead of bool. The refresh endpoint captures and forwards:
- inputs: what values were fed to evaluate_graph
- node_keys: which nodes were computed in prediction
- actual_moves: actual price pips fetched
- run_error: exception message if it failed
Frontend shows all of this after clicking Recalculer so the root cause is visible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-generated templates had no lag_days on edges → effective_lag_days=0 →
_drift_metrics used exact-date daily bar (often empty) → actual_json='{}' →
comprehensionScore returned null even after prediction_json was populated.
- Default effective_lag_days=5 when computed as 0 in _run_auto_analysis
- Add lag_days:3 to all auto-generated template edges in _build_graph_json_from_spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Events with surprise_pct=NULL (bootstrap or older events) got inputs={} → evaluate_graph
returned {} → prediction_json='{}' → all scores showed 'En attente'.
Three-step fallback in _run_auto_analysis:
1. Use event.surprise_pct if set (existing behaviour)
2. Compute from actual_value / expected_value stored in market_events
3. Look up most recent ff_calendar release by currency + date
Frontend diagnostic now shows surprise_pct per event and exposes actual/expected
in the refresh result panel to make the source visible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TabLibrary: bouton Supprimer (templates user uniquement)
- TabEditor: inputMapping dans EditorState, panneau mapping visible quand noeud observable selectionne
- TabEditor: edition d aretes (cliquer sur arête pour modifier style/force/signe/label)
- Backend: GET /api/causal-lab/data-sources (prices/macro_series/ff_events)
- analyze: auto-fetch market_watchlist+economic_events+ff_calendar depuis input_mapping
- TabAnalyze: affiche inputs auto-recuperes vs manuels dans les resultats
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TabEditor: updateExisting() + bouton bleu visible si templateId set
- Bouton Creer renomme en copie pour clarifier
- PATCH /api/causal-lab/template/{id} pour graph_json + metadonnees
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend (routers/simulator.py):
- GET /api/simulator/baseline aggregates current market values:
1. macro_gauge_snapshots → VIX, Brent oil
2. FRED economic_events → FEDFUNDS, ECBDFR, DFII10 (real yield)
3. yfinance live → EURUSD=X, ^IRX+^FVX interpolated US 2Y,
DE2YT=RR EU 2Y (or ECB rate +15bps fallback),
^VIX, BZ=F
- Returns sources dict so frontend can show data provenance
Frontend (EuroSimulator.tsx):
- Fetch /api/simulator/baseline on mount; use as base anchors
- compute(p, base) now takes dynamic base instead of hardcoded constants
- Reset button returns to today's live baseline, not hardcoded fallback
- Live/Fallback status badge with fetch date
- Sources panel showing data origin per field
- Chart reference line updates to show live base values
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a one-click upload+parse flow for the TE calendar page HTML.
The TE page (tradingeconomics.com/calendar) contains ~1000 events with
actuals, previous, and analyst consensus (forecast) values.
- Add backend/services/te_html_parser.py:
- parse_html(html): extracts events from <tr data-event> rows
- Maps 14 countries to major currencies (all Eurozone → EUR)
- Impact inferred from data-category (high/medium/low)
- Times converted from Europe/Zurich (CET/CEST) → UTC via zoneinfo
- Actual=td[5], Forecast=td[7] (analyst consensus), Previous=td[6]
- Add POST /api/eco/te-html-upload (saves file to /tmp)
- Add POST /api/eco/te-html-import + GET /status (background parse)
- Add "Import TE HTML" upload button in CalendarPage ImportPanel
Tested locally: 993 events parsed, 854 with forecast, 861 with actual,
date range 2025-03-31 → 2026-06-17, timezone conversion verified.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FXStreet calendar.fxstreet.com/eventdate/ returns ~300-400 events over
6 weeks including consensus forecasts, no authentication required.
FF HTML scraper is blocked by Cloudflare even on residential IPs.
FMP free plan returns 403 on /economic_calendar (requires Starter plan).
- Add backend/services/fxstreet_calendar.py: single GET request returning
all major currencies; maps Volatility 0/1/2 → low/medium/high
- Add POST /api/eco/fxs-sync + GET /api/eco/fxs-sync/status endpoints
- Add FXStreet to daily background sync in main.py (runs every 24h)
- Add "Sync Upcoming (FXStreet)" button in ImportPanel (no key needed)
- Fix FMP 403 error message to say endpoint requires Starter plan
- Keep FMP panel for users who upgrade to FMP Starter ($14.99/month)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>