- New ai_desks table with CRUD (get_all/by_type/upsert/delete)
- ai_desks router: REST API + GET /signal-catalog (7 extensible signals)
- News Desk: semantic dedup via AI (±N days window, system_prompt hint)
- Technical Desk: 4 signal detectors driven by desk config
(ma_cross, rsi_extreme, bb_squeeze, new_52w_extreme)
- 3 more signals in catalog ready to enable: price_gap, volume_spike, macd_crossover
- market_event_detector.py loads desk configs at runtime, falls back to legacy params
- AIDesks.tsx: full editor UI with signal toggles, param sliders, instrument multi-select
- Sidebar: Bot icon + /ai-desks route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The LEFT JOIN on instrument_impacts (added for the evaluated subquery)
generates N rows per event when the event has N impacts. GROUP BY was
only applied when the instrument filter was active — now it's always on.
Fixes: total=2 but list shows 6+ duplicates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: add evaluated subquery column to list SELECT so each event
returns evaluated=1/0 (was missing, causing all events to appear
as unevaluated regardless of filter)
- Frontend: AbortController cancels the previous in-flight fetch when
a new load fires, preventing stale results from overwriting current
filter state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MarketEvents: date presets (7j/30j/3m/6m/1an/Tout/Perso), instrument
impact filter (ticker + min score + direction → auto-sort by inst score),
sort controls (date/score/nom + asc/desc), clear-all button, count bar
- Market events list endpoint: full SQL JOIN rewrite supporting instrument
filter, date range, origin, sort_by=instrument_score
- Disable auto-bootstrap on startup (macro/eco/categories) — manual only
- CycleActions: bootstrap group (Macro/Eco/Categories) with force checkbox,
grouped layout (detection / bootstrap / data / ai / portfolio)
- cycle_actions router: /bootstrap-macro, /bootstrap-eco, /bootstrap-categories
endpoints + group field on all action catalogue entries
- InstrumentChart: greedy row placement for star labels (4 rows × 20px)
to eliminate horizontal overlap; labels now inline (★ + text)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB: colonne origin (migration + UPDATE heuristique sur données legacy)
- save/update_market_event: persist origin
- Tous les points de création taguent leur origine:
bootstrap_macro/eco/ma/legacy | detector_news/eco/technical/report | manual
- UI MarketEvents: badge d'origine avec icône + description dans le panneau détail,
icône tooltip dans la liste gauche, message explicite si pas de source_refs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add macro_regime (goldilocks/stagflation/recession/etc.) to every instrument snapshot via get_macro_gauges() + score_macro_scenarios()
- RegimeCard now shows global macro cycle section (emoji + label + top-3 scenarios) above technical signals
- Fix _detect_regime() confidence: capped at 85% max; add late-bull (dist_MA200 > 20%) and correction-in-bull (MA50 > MA200 but momentum < -3%) detection so regime no longer locks at 100%
- Add macro_events_bootstrap.py with 30 curated historical events (FOMC 2022-2025, CPI surprises, Ukraine/Hamas/Iran geopolitics, BOJ pivots, Bitcoin ETF, Liberation Day tariffs, SVB crisis, etc.)
- POST /api/timeline/bootstrap-macro endpoint (idempotent, deduplicates by name)
- Fix event date filter in _get_relevant_events(): overlap logic instead of start-only filter — events extending into the chart window are now included
- EventTimelineStrip: add "Signaux Techniques" fallback row for events not matched by any driver keyword (MA crossovers are now always visible)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- instruments.json: add keywords array to every driver across 20 instruments
(Fed, BCE, BOJ, OPEC, CPI, AI, EIA, etc.) for event-to-driver matching
- instrument_service.py: add update_instrument_drivers() persisting changes to JSON
and refreshing in-memory cache
- instruments.py: add PUT /api/instruments/{id}/drivers endpoint (DriverUpdate model)
- InstrumentDashboard:
* RegimeCard: replace regime score bars with 6-metric signal grid
(MA50/MA200 position, MA50 slope, MA200 slope, momentum 20j, dist MA200, ATR vol ratio)
with colour-coded values and contextual sub-labels (Golden cross, Surextension, etc.)
* EventTimelineStrip: rows now keyed by top-4 instrument drivers (by weight)
instead of LT/MT/CT; events matched via case-insensitive keyword scan against
title + description + category; fallback dashed line when no events match
* DriversPanel: inline edit panel (toggle via Drivers button in header);
edit label, weight, keywords (comma-separated) per driver; add/remove drivers;
saves via PUT /api/instruments/{id}/drivers; optimistic local state update
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TimelineVertical: replace horizontal frise with Y=time vertical layout,
3 columns (Long/Medium/Short), auto-scroll to selected date, sub-columns
for overlapping events, today/selected-date horizontal lines
- ma_analyzer.py: detect MA50/MA200 crossovers + MA100 slope changes +
MA20 direction swings on EUR/USD, Brent, Gold, S&P500, US10Y (5y history)
with 5-bar confirmation, dedup, GPT-4o-mini enrichment, idempotent DB save
- POST /api/timeline/bootstrap-ma endpoint to trigger analysis
- Bootstrap MA button in Timeline page with loading state + result count
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frise chronologique:
- Sub-lane stacking (assignSubLanes) — overlapping events se décalent verticalement
- Zone d'overlap semi-transparente sur la période commune entre 2 événements
- Hauteur dynamique selon nb de sub-lanes par niveau
- Événements en cours avec flèche ▶ à droite, gradient de fin
- Tri par start_date pour placement greedy
Event Manager (composant EventManager.tsx):
- Tableau filtrable par niveau (Long/Moyen/Court)
- Edit modal complet : tous les champs + absorption_pct éditable
- Bouton "IA — Enrichir" par événement → POST /api/timeline/events/{id}/ai-enrich
→ GPT-4o-mini suggère absorption_pct + indicateurs pertinents par niveau temporel
- Delete avec confirmation double-clic
- Expand row pour voir description + indicateurs
- Intégré Timeline page via bouton "Gérer événements"
Backend:
- Nouvelles colonnes market_events: absorption_pct + relevant_indicators (ALTER idempotent)
- DELETE /api/timeline/events/{id}
- POST /api/timeline/events/{id}/ai-enrich
Snapshot Externe:
- AbsorptionBar par événement dans cellule Géopolitique
- MA indicators : fetch 200j history, compute MA10/MA20/MA100 per level (short/med/long)
- Affichage prix vs MA + % écart dans CellMarkets
- Si relevant_indicators configurés sur l'event → utilise ces symbols au lieu des défauts
- Calendar : horizons exclusifs (short 0-7j, medium 8-30j, long 31-90j) — bug corrigé
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: category filter now ORs signal column so multi-category reports (category='multi') appear when filtering by Forex/Energy/Metals/Indices — fixes blank results
- Frontend: category pills expanded to match desk taxonomy (agri, crypto, bonds, indices added; equities kept for compatibility)
- Frontend: banner pointing to /specialist-desks clarifies the split between auto-fetched reports and manual desk report scheduling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleSave now shows a red toast "Lancez d'abord un backtest" instead of
silently returning when activeRun is null (was completely invisible to user)
- All toasts now color-coded: green (emerald) for success, red for errors
- list_runs now includes context_snapshot so market data table shows when
loading a historical run from the right panel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Detect yfinance quote_type (CURRENCY→forex, FUTURE→energy, INDEX→indices,
ETF→etfs, EQUITY→equities) when adding a custom ticker and persist it in
market_watchlist.asset_class
- get_all_quotes() merges custom tickers into their proper group (e.g. EURUSD=X
appears under Forex) instead of always under a separate "Custom" group
- "Custom" tab only shows tickers whose type couldn't be detected
- Add market_watchlist.asset_class migration; ensure backtest_lab_runs and
market_watchlist are always created at init_db() time
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add ability to add/remove custom tickers (e.g. EURCHF=X) on the
Markets & Prices page without editing config. Tickers are validated
via yfinance, persisted in market_watchlist SQLite table, merged into
the quotes feed as a 'custom' group, and shown in a dedicated tab
with per-card remove buttons.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix: history runs now always show results — create synthetic selected preset
from run data when no matching preset found (was broken for custom events).
Also force mode='events' and reset matchResults on history load.
Discover tab: new "Discover" panel in left sidebar (AI knowledge search).
- GPT-4o generates 6 matching events from a free-text query (date, assets, hint)
- Confidence score + category badge per event
- Click → pre-fills experiment form exactly like a preset → ready to Run
- Backend: POST /api/pattern-lab/discover (DiscoverRequest, sorted by confidence)
- Frontend: useDiscoverEvents hook + DiscoveredEvent type + Discover UI with
Enter-to-search, spinner, empty states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: PATCH /api/patterns/custom/{id} — partial update, only provided fields changed
- useApi.ts: usePatchPattern mutation hook
- PatternCard: pencil icon (non-builtin only) → edit mode with inline inputs for name, description, direction (select), category, and #regime; ✓/✗ buttons to save or cancel; card border highlights blue while editing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- GET /api/market/validate?symbol= — validates ticker against yfinance,
returns {valid, name, price} or {valid: false, reason: 'helpful message'}
- Added SLV, USO, WEAT, CORN, TUR to ETFs WATCHLIST category
Frontend:
- validateTicker() async helper exported from useApi.ts
- InstrumentPicker (PatternLab): custom ticker field now validates before selecting
Shows spinner while checking, red error message if not found on yfinance
- InstrumentLens (PatternExplorer): same validation on Go button + Enter key
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend: DELETE /api/patterns/purge-all — removes all custom + backtested patterns
(source != 'builtin'), leaves Pattern Lab run history intact.
Frontend Config > Data Management:
- New PurgeButton for Pattern Library (custom_patterns table)
- Updated note: Trade Ideas are computed live from the Pattern Library (no separate table),
so purging patterns resets trade idea generation on next cycle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- instruments.ts: 90 IB-options-tradable instruments in 12 categories
(US Indices, Europe, Asia, EM, Sectors, Forex, Bonds, Metals, Energy,
Agriculture, Crypto, Volatility) — EUR/CHF, Cotton, etc. all included
- PatternExplorer: replace text input in Instrument Lens with categorised
grid picker (category pill filters + search + custom ticker fallback)
- PatternLab: add Instrument Scan tab alongside Event Presets
- Pick any instrument from the shared categorised picker
- Set period (start/end date) + horizon per pattern
- AI scans the full period: identifies 4-6 key pattern instances each with
their own entry date, expected move, strategy
- 'Evaluate outcomes' fetches actual price at T+horizon per pattern
- 'Save pattern' promotes any instance to the Pattern Library
- backend/services/pattern_lab.py: run_instrument_scan() + evaluate_instrument_outcomes()
(per-pattern analysis_date vs shared date in event mode)
- backend/routers/pattern_lab.py: POST /instrument-scan + POST /evaluate-instrument/{id}
- useApi.ts: useInstrumentScan + useEvaluateInstrumentScan hooks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove all built-in patterns (no proof of legitimacy); seed_builtin_patterns is now a no-op
- DB: add backtest_lab_runs table + backtest_hits/runs_count columns on patterns
- services/pattern_lab.py: build_historical_context (yfinance + RSI/MA200),
run_ai_backtest (GPT-4o as historical analyst), evaluate_outcomes (actual moves at T+horizon)
- routers/pattern_lab.py: POST /run, POST /evaluate/{id}, GET /runs, DELETE /runs/{id},
POST /save-pattern (promotes hit pattern to library with reliability counters)
- PatternLab.tsx: 34 preset events 2015-2025 (macro/geo/credit/fx/commodities/volatility/tech),
3-panel layout — preset selector + wizard + run history, market data table,
AI pattern cards with hit/miss outcome display, Save to Library button
- useApi.ts: usePatternLabRuns, useRunPatternLab, useEvaluatePatternLab, useSaveLabPattern, useDeleteLabRun
- Sidebar + App.tsx: /pattern-lab route + FlaskConical nav link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New institutional_reports table (DB) with importance, signals per asset class, key points, absorption tracking
- cot_fetcher.py: CFTC Socrata API (6dca-aqww), 7 instruments (Gold/Silver/Copper/WTI/NatGas/SP500/EURUSD), net positioning + 52-week z-score
- eia_fetcher.py: EIA API v2, 4 series (crude/Cushing/gasoline/distillates), WoW surprise detection
- institutional.py router: GET /reports, GET /reports/{id}, POST /refresh, GET /stats
- institutional_scheduler.py: weekly auto-fetch (COT Saturdays, EIA Wednesday afternoons)
- ai_analyzer.py: build_institutional_block() + institutional_block param injected into AI scoring prompt
- auto_cycle.py: inject institutional block into suggestion + scoring, absorption tracking via keyword overlap after each cycle commentary
- InstitutionalReports.tsx: full page with filter bar (type/category/importance/period), cards with key point bullets, EXTREME alerts highlighted, signal badges, absorption badge, trading implications, expandable detail
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auto_cycle.py: _scheduler_loop now distinguishes weekday (interval_hours)
from weekend (weekend_cycle_times UTC slots or sleep until Monday);
_parse_weekend_times() and _next_weekend_slot() helpers;
get_status() exposes weekend_cycle_enabled + weekend_cycle_times
- cycle.py: CycleConfigRequest adds weekend_cycle_enabled + weekend_cycle_times;
update_cycle_config validates HH:MM format and persists to config DB
- Config.tsx: weekend scheduling section with enable toggle + time picker
(06:00/08:00/12:00/18:00/22:00/00:00 UTC presets, multi-select);
weekendEnabled + weekendTimes state synced from cycle status
Default: enabled with 08:00 + 22:00 UTC (covers news scan + Globex open Sunday)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- portfolio_context.py: add _safe_float() helper (converts NaN/Inf → None);
use .squeeze().dropna() on yfinance closes before computing moves;
guard division by checking closes.iloc[-2] != 0
- cycle.py: add _sanitize_floats() recursive sanitizer applied to the full
snapshot before FastAPI serializes it — catches any remaining NaN from
iv_rank, technical indicators, or other sources
Fixes 500 on GET /api/cycle/contexts/{run_id} when yfinance returns NaN
weekend data for portfolio positions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Portfolio context (portfolio_context.py):
- get_open_trades_with_moves(): fetches open trades + 1d/5d yfinance price moves
- get_portfolio_concentration(): counts by asset_class
- build_portfolio_context_block(): formatted prompt block with strict AI instructions
(no double positions, flag contradictions, avoid overweight classes)
AI call logging:
- ai_call_logs table in DB (run_id, call_type, system/user prompt, response, tokens, ms)
- _chat() now accepts log_meta dict → saves call to DB non-blocking after each call
- suggest and score_batch calls pass run_id + call_type for full traceability
auto_cycle.py:
- Builds portfolio context before snapshot and both AI calls
- Context snapshot now includes portfolio_open_positions key
SystemLogs.tsx:
- "Contexte IA" tab gains sub-tabs: Contexte / Appels IA
- AiCallRow: expandable with 3 panes (user prompt / system prompt / response)
shows model, tokens breakdown, duration, call type badge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 4 — Price Discovery Status (la pièce maîtresse) :
- price_discovery.py (nouveau) : capture_price_snapshots() sauve les prix des tickers
liés à chaque news scorée (energy→BZ=F/NG=F, metals→GC=F/HG=F, indices→^GSPC/IWM)
- compute_absorptions() mesure combien du mouvement attendu s'est déjà produit
(status: not_yet_priced <30% / partially_priced 30-80% / fully_priced >80%)
- build_price_discovery_block() → bloc prompt avec opportunités classées
- database.py : table news_price_snapshots + save/get/purge fonctions
- auto_cycle.py : capture après ai_score_news_batch, compute avant suggestions,
block injecté dans suggestion + scoring prompts + context snapshot
- ai_analyzer.py : param price_discovery_block dans suggest + score
Phase 5 — Replay historique :
- cycle.py : POST /api/cycle/contexts/{run_id}/replay — recharge le snapshot historique
et relance suggest_patterns_from_market_context avec le contexte original
- useApi.ts : hook useReplayCycle
- SystemLogs.tsx : bouton "Rejouer ce cycle" dans onglet Contexte IA avec champ
notes, résultats inline (liste des patterns générés), section price_discovery
ouverte par défaut en rouge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- Dashboard: P&L card séparé en deux colonnes (Ouvertes/Réalisées) pour Simulé et Portfolio
- Dashboard: closed trades P&L locked from pnl_realized, ne fluctue plus après fermeture
- Journal Ouvert: filtres ticker/stratégie + classe d'actif + direction (haussier/baissier)
- Journal Fermés: mêmes filtres + filtre P&L (gagnants/perdants) + bouton supprimer par ligne
- Journal Non loggés: filtres ticker + classe d'actif + raison de skip
- Backend: DELETE /api/journal/trades/{id} + delete_trade() dans database.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- get_pnl_snapshot(id) : détail complet d'un snapshot avec trades parsés
- diff_pnl_snapshots(a, b) : diff positions entre deux snapshots (nouvelles /
fermées / évolution PnL par position + delta portfolio)
- GET /api/var/pnl/snapshots/{id} : détail snapshot
- GET /api/var/pnl/diff?a=&b= : calcul du diff
Frontend PositionHistory.tsx :
- Timeline scrollable des snapshots avec sparkline PnL
- Clic snapshot → détail des positions à ce moment (prix entrée, prix actuel,
PnL %, PnL €, régime macro)
- Boutons A/B par snapshot → sélection de deux points à comparer
- Vue diff A→B : nouvelles positions, fermées, évolution PnL par trade,
delta portfolio (capital, PnL %, PnL €)
- Route /position-history + nav sidebar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dashboard: insert 2 rows of 4 mini-cards between top row and trade ideas
- Row 1: PnL Simulé, Risque Simulé, Dernier Cycle, Régime Macro
- Row 2: Super Contexte, Signaux Géo, Meilleur Pattern, Patterns Actifs
- All cards link to underlying pages via react-router Link
Journal: add 'Non loggés' tab exposing trades suggested by cycle
but skipped because no risk profile was matched
- New skipped_trades table (auto-created on backend restart)
- log_trade_entries() persists each skip with score/gain/asset_class
- GET /api/journal/skipped-trades + useSkippedTrades hook
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>