Commit Graph

177 Commits

Author SHA1 Message Date
OpenSquared
3133e073f7 Vix barre 2026-06-26 22:27:26 +02:00
OpenSquared
c36f11ad32 fix: VIX slider bar overflow — clamp pivot to range, add center prop
Slider was computing mid = (0 - 10) / (60 - 10) * 100 = -20% for VIX
(0 outside the 10-60 range), causing the colored track to start at a negative
left position and overflow the container.

Fix: add overflow-hidden on the track div; add center prop (defaults 0)
that the caller sets to the actual baseline value when 0 is out of range.
VIX now pivots at 18, real yield US at 2.1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:24:31 +02:00
OpenSquared
a24cac38ad feat: eco desk enhanced config + EUR/USD causal simulator
Eco desk (market_event_detector.py + AIDesks.tsx):
- Add currencies filter (USD via FRED, EUR/GBP/JPY/etc via ff_calendar)
- Add min_impact filter (high / high+medium / all levels)
- Add create_market_event toggle — detect surprises without creating events
- Add lookback_releases — inject last N historical releases into event description
- New _check_ff_calendar_surprises() for non-USD surprising releases
- Frontend EcoConfig: currency chips, impact dropdown, releases input, toggle

EUR/USD Simulator (EuroSimulator.tsx):
- Pure frontend causal model — no API calls, no historical data
- 3-column layout: controls | causal chain SVG | results
- FED/BCE rate sliders + hawkish/dovish tone selector
- CPI/NFP/PMI surprise inputs
- SVG causal chain: CPI→CB→2Y→ΔRate→EURUSD with dynamic colors
- Real-time pip decomposition by factor, sensitivity bars
- Route /simulator + sidebar entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 22:17:33 +02:00
OpenSquared
dd2876325a chore: remove FMP panel — economic calendar not available on free plan
FMP /economic_calendar endpoint returns 403 on free plan (requires Starter
at $14.99/month). The panel adds clutter without value. Removed component,
its import, and the TEKeyStatus type that was only used by it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:57:10 +02:00
OpenSquared
87ded9434f feat: import Trading Economics HTML calendar — 993 events with forecasts
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>
2026-06-26 18:15:02 +02:00
OpenSquared
bdbb87962d feat: FXStreet calendar — free upcoming events with forecasts (no API key)
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>
2026-06-26 17:54:15 +02:00
OpenSquared
5c86d6e715 feat: replace Trading Economics with FMP for upcoming calendar forecasts
TE costs $199/month and its Economic Calendar is not in the free tier.
FMP (Financial Modeling Prep) offers a free API key (250 req/day) with
full economic calendar coverage including consensus estimates (forecasts).

- Add backend/services/fmp_calendar.py: fetches upcoming events from
  GET /api/v3/economic_calendar (one request, all countries, date range)
- Replace /api/eco/te-key + te-sync endpoints with fmp-key + fmp-sync
- Update daily background sync in main.py to use fmp_calendar
- Replace TEPanel with FMPPanel in CalendarPage.tsx (link to FMP docs)
- Remove broken Cloudflare-blocked FF HTML scrape button from ImportPanel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:42:09 +02:00
OpenSquared
ec6fcc1e3d feat: Trading Economics API for upcoming events with forecasts
- New services/te_calendar.py: fetch_upcoming(weeks_ahead) calls TE API
  for 9 countries (USD/EUR/GBP/JPY/AUD/CAD/NZD/CHF/CNY), converts to
  ff_calendar format, upserts with source='te_api'
- New endpoints: GET/POST /api/eco/te-key, POST /api/eco/te-sync,
  GET /api/eco/te-sync/status
- Daily scheduler in main.py: FF live sync + TE sync (if key configured)
  run 60s after startup then every 24h
- CalendarPage: TEPanel with key input (password field, Enter to save,
  "Get free key" link to tradingeconomics.com/api/login),
  "Sync upcoming (6 weeks)" button with polling

FF HTML scraper kept as fallback but TE API is the primary source
for upcoming forecasts (no Cloudflare blocking on server IPs).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:30:16 +02:00
OpenSquared
d9762deca7 feat: custom date range filter on calendar page
- Backend: /api/eco/calendar accepts date_from + date_to query params
  when period=custom; get_calendar() uses them directly without override
  Limit raised to 5000 for wide date ranges
- Frontend: "Custom" tab at end of period list; shows two date inputs
  (from/to) with Apply button; displays day count; fetches on Apply click
  (not on every keystroke to avoid hammering the API)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:17:01 +02:00
OpenSquared
c36b2b2198 feat: FF HTML scraper for upcoming weeks with forecasts
- scrape_upcoming(weeks_ahead=5) in ff_calendar.py:
  fetches forexfactory.com/calendar?week=... HTML for N weeks ahead,
  parses calendar__table (date/time/currency/impact/event/forecast/previous),
  converts ET times to UTC, upserts into ff_calendar
- Daily scheduler in main.py: runs scrape_upcoming at startup (after 30s delay)
  then every 24h — no manual action needed
- New endpoints: POST /api/eco/ff-scrape?weeks=5, GET /api/eco/ff-scrape/status
- CalendarPage: "Scrape Upcoming (5w)" button (indigo) with polling + result

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:14:00 +02:00
OpenSquared
a69ced8fff chore: ignore forex_factory_cache.csv (already imported in DB) 2026-06-26 17:08:15 +02:00
OpenSquared
808bd2b564 fix: FF auto-import always runs if CSV present, deletes CSV after success
- Remove count>0 guard — import runs regardless of existing rows (idempotent upsert)
- After successful import, CSV is deleted from /app so next restart skips cleanly
- No more need to manually trigger import or remove CSV from git separately

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:05:01 +02:00
OpenSquared
600b86e75f Calendar 2026-06-26 17:00:41 +02:00
OpenSquared
7aca0c307a feat: FF CSV bundled in image + auto-import on startup
- forex_factory_cache.csv moved to backend/ (Docker build context)
  → available at /app/forex_factory_cache.csv inside container
- main.py startup: auto-imports CSV in background thread if ff_calendar empty
  (idempotent — skips if rows already present)
- CSV path candidates: /app/ (Docker) → /tmp/ (upload) → local dev paths
- CalendarPage: remove Upload CSV + Import into DB buttons
  → replaced by auto-import status indicator + Sync Live only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 16:58:31 +02:00
OpenSquared
afbfeff468 feat: FF→FRED series mapping + MacroSeries visualization page
Backend:
- ff_calendar: add series_id column (migration) + FF_TO_FRED mapping dict
  (NFP→PAYEMS, CPI→CPIAUCSL, Jobless Claims→ICSA, GDP→GDPC1, FEDFUNDS, PCE)
- import_csv + sync_live now populate series_id on each FF event
- New GET /api/eco/series/{id}/history: FRED time series + linked FF events
  (surprises, forecast, actual) merged by date — enables context queries

Frontend:
- New MacroSeriesPage.tsx: sidebar with 11 FRED series grouped by category,
  recharts ComposedChart with area + z-score surprise reference lines (|z|≥1.5),
  KPI cards (latest/prev/min/max), FF events table (actual vs forecast coloring),
  z-score bar chart for recent surprises, range selector (1Y/2Y/5Y/10Y/All)
- Route /macro-series + Sidebar entry "Macro Series"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 16:51:55 +02:00
OpenSquared
b187107468 fix: FF calendar upload endpoint + path resolution for server deployment
- Add POST /api/eco/ff-upload to receive CSV from browser (saves to /tmp)
- _find_csv() checks /tmp, /app, project root — works local + Docker
- _run_ff_import now takes explicit csv_path parameter
- Frontend: Upload CSV button (file input) → uploads to server first,
  then Import into DB — with upload progress messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 16:36:31 +02:00
OpenSquared
4053e0669d feat: Forex Factory calendar — unified past+future list style Trading Economics
- New ff_calendar table (event_date, time, currency, impact, actual, forecast, previous)
- New service ff_calendar.py: bulk CSV import (83K events 2007-2025) + live sync
  from faireconomy.media JSON endpoint (this week / next week)
- New API endpoints: POST /api/eco/ff-import, POST /api/eco/ff-sync,
  GET /api/eco/calendar (period filter), GET /api/eco/ff-stats
- CalendarPage.tsx full rewrite: period tabs (Recent/Today/Tomorrow/This Week…),
  currency flags filter, impact filter, unified date-grouped table with
  Time·Flag·Currency·Impact·Event·Actual·Forecast·Previous columns,
  green/red actual vs forecast, TODAY badge, auto-refresh 60s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 16:32:26 +02:00
OpenSquared
915560bc31 feat: upcoming economic releases panel on Calendar page
- eco.py: GET /api/eco/upcoming — estimates next release date per series
  from last stored date + frequency + typical publication lag; returns
  status (imminent/due_soon/upcoming/scheduled/overdue/no_data)
- CalendarPage.tsx: UpcomingPanel component in right sidebar showing
  next expected dates, J-N countdown, last value + direction signal;
  color-coded by urgency (orange=cette semaine, yellow=attendu, blue=ce mois)

Dates are approximate (freq + typical lag), not official FRED schedule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 16:01:26 +02:00
OpenSquared
b058b7297a fix: use FRED official JSON API (bypasses CloudFlare) + API key UI
- fred_bootstrap.py: switch from CSV graph endpoint (CloudFlare-blocked)
  to api.stlouisfed.org/fred/series/observations JSON API; reads key
  from DB config 'fred_api_key'; returns clear error if key missing
- eco.py: add GET/POST /api/eco/fred-key to check/save the FRED API key
- CalendarPage.tsx: BootstrapPanel shows API key section with status,
  input to paste key + save button, disables Launch if key missing

Free key: fred.stlouisfed.org -> My Account -> API Keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:47:16 +02:00
OpenSquared
202a8ce97c fix: FRED fetch — add browser User-Agent + print diagnostics to stdout
FRED blocks requests without a valid User-Agent. Added headers matching
a real browser. Also added print() calls so fetch errors appear in
docker logs (logger.warning goes to system_logs table, not stdout).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:33:06 +02:00
OpenSquared
d25ca92694 fix: FRED data quality — GDP growth %, CPI/PCE YoY%, ICSA in K
- GDPC1 replaces A191RL1Q225SBEA: compute annualized QoQ growth from
  GDP level ((val/prev)^4 - 1)*100 → displays proper ~2-3% not 31 819
- CPIAUCSL/CPILFESL/PCEPILFE: yoy_pct transform (val/val_12m_ago-1)*100
  → displays 3.x% YoY inflation, not raw index level 334
- ICSA: div1000 transform → displays 226 K claims, not 226 000 K
- delta_absolute flag: pp change for rate/% series, % change for levels
- SurprisePct component: shows 'pp' suffix for %, '%' for K/levels
- Column header renamed from 'Δ%' to 'Δ vs préc.' with tooltip
- Deprecated A191RL1Q225SBEA rows cleaned from DB on next bootstrap
- Warm-up periods: 2yr for yoy_pct, 3yr for qoq_annualized, 1yr others

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:16:44 +02:00
OpenSquared
2469b76769 fix: CalendarPage API calls use relative URLs (not localhost:8000)
All fetch() calls now use relative paths (/api/eco/...) so nginx
can proxy them to the backend container in production.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:00:56 +02:00
OpenSquared
77b3a27495 fix: TS2322 in CalendarPage — typed bootstrap result vars outside JSX
Record<string, T> index type prevents 'error' in narrowing, causing
string | T to leak into ReactNode positions. Fix: precompute
bootstrapError (string|null) and bootstrapEntries ([string, T][])
before JSX so TypeScript can resolve types correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 14:50:07 +02:00
OpenSquared
64ff777da6 feat: FRED bootstrap + Calendar page complete rebuild
- backend/services/fred_bootstrap.py: fetch 11 FRED series (PAYEMS, UNRATE, CPI, PCE, FEDFUNDS, ICSA, GDP, HY spread, T10Y2Y, T10Y3M) from public CSV endpoint — no API key needed; computes rolling z-scores and upserts into economic_events table
- backend/routers/eco.py: new /api/eco router with bootstrap (POST + status GET), events list with full filtering (date range, category, series, min z-score, direction, sort/pagination), series catalog, and db status endpoints
- backend/main.py: register eco router
- frontend/src/pages/CalendarPage.tsx: complete rewrite — real data table from /api/eco/events, Bootstrap FRED button with live polling, filter bar (date range, category, series chips, |z| threshold, direction), sort by date/z-score/series, pagination, z-score badges with color coding, sidebar with series inventory + geo alerts + z-score guide

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 14:42:44 +02:00
OpenSquared
325d52b3b9 feat: market events db migration + generation date filter
Database migration:
- Add 'origin' and 'source_refs' columns to market_events ALTER TABLE migration
  (sub_type/actual_value/expected_value/surprise_pct were already there)
- All new tables (macro_gauge_snapshots, ai_desks) created via CREATE TABLE IF NOT EXISTS
  on next init_db() call (container restart)

Backend:
- GET /api/market-events/db-status — health check returning row counts,
  latest dates, and missing columns for all 6 tables needed by the detector
- list_events() now accepts gen_date_from / gen_date_to query params
  filtering by date(created_at) — separate from start_date event date filters

Frontend (MarketEvents.tsx):
- MarketEvent interface: add created_at field
- EventRow: show generation date as MM-DD next to event date
- Extended filters: new ' Date de génération' section with from/to inputs
  filtered independently from the event date range
- Clear-all button includes genFrom/genTo reset

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 14:23:09 +02:00
OpenSquared
d0816fd9ff feat: Sentiment desk — gauge threshold alerts (Option B)
Each macro gauge selected in the Sentiment desk can now be independently
configured with three alert criteria:
- Seuil bas (≤): alert when value crosses below
- Seuil haut (≥): alert when value crosses above
- Variation % (Δ%): alert when N-day % change exceeds threshold

Frontend: GaugeThresholdConfig component — one row per selected gauge,
compact grid layout with enable toggle + 3 numeric inputs.
Stored in config.gauge_thresholds[gauge_id].

Backend: _check_sentiment() extended — after CBOE signals, reads
macro_gauge_snapshots history, checks each enabled gauge threshold,
emits sentiment market_events with options_note for each breach.
Gauge → affected_assets mapping covers all 32 gauge keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 13:59:40 +02:00
OpenSquared
27ee4410cf refactor: separate Sentiment and Technical desks — no signal overlap
- Mark 6 price signals (ma_cross, rsi_extreme, bb_squeeze, new_52w_extreme, price_gap, volume_spike) as desk_type=technical so they no longer appear in the Sentiment desk
- Sentiment desk now shows MacroGaugeSelector (32 gauges grouped by bloc: Liquidité, Crédit, Volatilité, Métaux…) instead of the stock/ETF instrument picker
- Sentiment desk instruments seed updated to macro gauge keys (vix, vvix, skew, hyg, dxy, slope_10y3m, gold_copper_ratio)
- Signal init useEffect extended to cover sentiment desk as well as technical

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 13:48:14 +02:00
OpenSquared
85eb864584 feat: macro gauge DB + regime triggers + date-aware instrument snapshot
DB:
- New table macro_gauge_snapshots (daily snapshot of all 28+ gauges + dominant + scores)
- save_macro_gauge_snapshot / get_macro_gauge_snapshot_at / get_macro_gauge_history
- Auto-save once per calendar day on every macro-regime fetch (not just force=True)

API:
- GET /api/market/macro-gauges/at?date=YYYY-MM-DD — nearest snapshot ≤ date
- GET /api/market/macro-gauges/history?days=N

Detector (_check_macro_gauges in Eco Desk):
- Regime transition events (goldilocks→stagflation etc.) with severity scoring
- Yield curve inversion / désinversion (slope_10y3m sign change)
- DXY shock (% change over lookback window)
- Credit stress (HYG drop threshold)
- Gold/Copper ratio regime crossings

InstrumentDashboard:
- macroAtDate state: fetches /api/market/macro-gauges/at when crosshair date ≠ last date
- RegimeCard uses historical macro regime when on a past date
- MacroGaugePanel: full breakdown of all gauges by bloc (liquidité, crédit, énergie...)
  visible only when on a historical date — shows value + change_pct + regime scores bar

AIDesks: added fundamental + sentiment to AIDesk type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 09:34:35 +02:00
OpenSquared
a12d7a1ef3 feat: 6 AI desks complets — fundamental, report, sentiment (options triggers)
- Fundamental Desk: filtre corporate news (layoffs, M&A, earnings, credit)
  avec prompt dédié + dedup sémantique
- Report Desk: wiring desk config (days, min_importance, system_prompt)
- Sentiment Desk: 5 signaux VIX/SKEW pour options lab
  (vix_level thresholds, vix_spike %, vix_term_structure, vvix_extreme, skew_extreme)
  Chaque event contient options_note actionnable (vente puts, straddles, calendar spreads)
- check_new_market_events() couvre les 6 sources, charge desk configs dynamiquement
- Signal catalog: 12 signaux (7 technical + 5 sentiment), filtrés par desk_type dans UI
- AIDesks.tsx: FundamentalConfig + ReportConfig + SignalToggle filtré par desk type
- 3 nouveaux desks seedés dans init_db (idempotent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 09:21:29 +02:00
OpenSquared
97706dea7b feat: AI Desks — configurable agent system for news/technical/eco processing
- 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>
2026-06-25 23:08:14 +02:00
OpenSquared
069b398d75 feat: apply category defaults first then AI adjusts + remove chips
Backend: merge strategy — category defaults are applied as baseline
(ai_generated=0), AI impacts override/extend them (ai_generated=1).
All N category defaults appear in the impacts list; AI covers them
explicitly with event-specific score/direction adjustments.
Prompt: instruct AI to cover ALL default instruments.

Frontend: remove default impact chips under category selector —
they now appear directly in the instrument impacts list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:23:38 +02:00
OpenSquared
06a27e4492 fix: add sub_type to update_market_event SQL — was silently dropped
The UPDATE statement listed all columns except sub_type, so the
AI-matched category auto-set was written to the object but never
persisted to the DB. The category dropdown stayed blank after evaluate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:18:09 +02:00
OpenSquared
4071193385 fix: AI returns type instead of category name — clearer prompt + guard
The AI was returning 'geopolitical' (the event type/family) instead of
a category name like 'Guerre — Moyen-Orient'. Two fixes:
1. Prompt: rename 'Type' → 'Famille', list categories as CAT_N: "name",
   explicit warning not to return a generic type, show valid name examples
2. Code: reject any response that matches a known type string before matching

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:14:21 +02:00
OpenSquared
91a448e8c9 fix: robust category matching — normalize dashes/accents + partial match
The AI often returns 'Guerre - Moyen-Orient' (ASCII dash) instead of
'Guerre — Moyen-Orient' (em-dash), causing exact match to fail silently.
Fix: normalize unicode, collapse all dash variants, then try
exact → normalized → partial substring matching.
Also log the raw AI response for debugging, increase max_tokens 1200→2000.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:07:56 +02:00
OpenSquared
7eb8c24719 feat: AI category matching — pass all categories to GPT for best-fit selection
Previously: heuristic text matching (sub_type in category.name) — failed
for semantic cases like 'Iran Ceasefire Talks' → 'Guerre — Moyen-Orient'.

Now: all EventCategories are sent in the prompt (name + type + description).
The AI picks matched_category by semantic understanding, returns it in JSON.
- Validates returned name against known categories (case-insensitive)
- Auto-sets event sub_type when AI finds a match and sub_type was empty
- Returns matched_category in evaluate response + shown in UI eval message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:02:47 +02:00
OpenSquared
bf938067a1 fix: cat_name not defined in impact_service evaluate_event_impacts
_find_cat() returned only default_impacts, never the category name.
Now returns (name, defaults) tuple; cat_name → matched_cat_name.
Fixes: 'name cat_name is not defined' on AI evaluate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:55:43 +02:00
OpenSquared
acab69b65c fix: always GROUP BY me.id in market_events list query
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>
2026-06-25 21:53:14 +02:00
OpenSquared
332d5ad743 fix: evaluated field on event list + abort race condition
- 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>
2026-06-25 21:36:12 +02:00
OpenSquared
984e6860ad feat: event category selector in detail panel
- Always-visible 'Catégorie IA' block in EventDetail (view + edit mode)
- Dropdown lists all EventCategories; selecting one instantly saves sub_type
  and updates category type via PUT (no need to enter full edit mode)
- Shows matched category description + default impacts preview (ticker chips
  with direction arrows and sensitivity %)
- Edit mode: category dropdown also auto-sets the category type field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:32:02 +02:00
OpenSquared
f71e3be3ff feat: market events filters, no-auto-bootstrap, star label deoverlap
- 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>
2026-06-25 21:27:21 +02:00
OpenSquared
0b1fcff49c feat: Market Events — catégories, cleanup sidebar, rename
- Supprime Timeline & ImpactMonitor du routing (redirects /impact + /timeline → /market-events)
- Renomme 'Instrument Snap.' → 'Instrument Analysis' dans la sidebar
- Onglet 'Catégories & Defaults' dans Market Events: CRUD complet (créer/éditer/supprimer)
  chaque catégorie a une table d'impacts par défaut (instrument, sensibilité, direction, notes)
- impact_service: meilleur matching catégorie (sub_type fuzzy + type fallback)
- DB: delete_event_category() + DELETE /api/impact/categories/{name}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:11:24 +02:00
OpenSquared
bd28b6a73a feat: origin tracing on all market_events
- 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>
2026-06-25 20:58:05 +02:00
OpenSquared
d5da4737ef feat: Market Events admin page — source_refs + per-instrument impacts
- DB: colonne source_refs sur market_events (migration idempotente)
- save/update_market_event: persist source_refs (JSON array de {url,title,source})
- market_event_detector: stocke source_refs + évalue impacts instruments après chaque création
- Nouveau router /api/market-events: CRUD + evaluate + impacts CRUD
- Page MarketEvents.tsx: liste filtrée/triée + panneau détail (sources cliquables,
  tableau impacts par instrument avec score/direction/rationale inline-éditables,
  ajout manuel, bulk-evaluate)
- Sidebar: entrée Market Events (Radio icon)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 18:29:09 +02:00
OpenSquared
e66d3ddb46 fix: use relative API URL in CycleActions (nginx proxy compat)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 18:12:01 +02:00
OpenSquared
9afc01c7f5 feat: isolated cycle action — Check New Market Events
Décompose le cycle en 8 actions appelables individuellement.
Action 1 implémentée : scan de 4 sources (news RSS, surprises FRED,
MA crossovers yfinance, rapports institutionnels) → création de
market_events avec déduplication. UI CycleActions page + sidebar link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 18:07:38 +02:00
OpenSquared
50a4a55b9e fix: stars higher above bars + bigger label (11px bold, 130px offset, capped top 30px) 2026-06-25 17:30:15 +02:00
OpenSquared
1d433b4a7a feat: replace arrowDown markers with ★ stars overlay on chart, colored by category
- InstrumentChart: remove setMarkers arrowDown (level-colored)
  Add DOM overlay div with ★ HTML characters positioned via timeToCoordinate +
  priceToCoordinate(candle.high) - 52px; sized by impact_score; colored by category
  Label (title, 22 chars) rendered above each star; redrawn on scroll/zoom via
  subscribeVisibleLogicalRangeChange; cleaned up on unmount
  ChartEvent interface: add category, impact_score, end_date, description
  Header legend: replace ▼ LT/MT/CT with ★ category color legend
- InstrumentDashboard: remove EventStarsStrip (now internal to chart)
  Remove unused dateToMs helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:24:33 +02:00
OpenSquared
51a5531454 refactor: align market_events categories with driver types + event stars on chart
- database.py: idempotent migration — calendar→event_calendar, geopolitique→geopolitical,
  macro events classified by name pattern (FOMC/CPI/BOJ/OPEC+→event_calendar,
  NVIDIA→report, rest→fundamental)
- eco_calendar_bootstrap.py: calendar→event_calendar (75 events)
- macro_events_bootstrap.py: all 30 events now carry aligned category + sub_type
  (FOMC×9, CPI×3, BOJ×3, OPEC+×2 → event_calendar ; war/geo×6 → geopolitical ;
   ChatGPT/BTC/PBOC → fundamental ; NVIDIA×2 → report)
- InstrumentDashboard: replace EventTimelineStrip (horizontal bars below chart)
  with EventStarsStrip (★ icons above chart, sized by impact_score, colored by category)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 17:01:07 +02:00
OpenSquared
a68896cf67 feat: Impact Monitor — AI impact evaluation for eco events & geopolitical news
- New DB tables: event_categories (18 bootstrap categories) + instrument_impacts
- impact_categories_bootstrap.py: FOMC/NFP/CPI/GDP/PCE/ISM/BOJ/ECB/BOE/OPEC+ + 7 géopolitical categories with per-instrument sensitivity & direction defaults
- impact_service.py: GPT-4o-mini evaluation (0-1 score, direction, rationale) + monitor data aggregation
- routers/impact.py: GET/POST endpoints for evaluate/bulk/monitor/adjust/categories
- ImpactMonitor.tsx: two-tab page (Évalués / À évaluer), top instruments bar, inline score override modal, category browser
- Startup auto-bootstrap for impact categories
- Route /impact + sidebar nav entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 16:26:13 +02:00
OpenSquared
9ed59c5ca2 feat: auto-bootstrap macro + eco events on startup
Both bootstrap_macro_events() and bootstrap_eco_events() are now called
in the FastAPI startup event. Idempotent — skips already-existing events.
Logs how many events were inserted on first run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 00:13:22 +02:00