feat: eco calendar bootstrap + driver types + timeline cursor

Backend:
- eco_calendar_bootstrap.py: 75 historical events 2020-2026 (FOMC, NFP,
  CPI, GDP, ISM, BOJ, ECB, BOE) with expected_value/actual_value/
  surprise_pct/unit/absorption_pct fields
- database.py: 5 new columns on market_events (expected_value,
  actual_value, surprise_pct, unit, sub_type) + updated save_market_event
- timeline.py: POST /api/timeline/bootstrap-eco endpoint
- instrument_service.py: _get_relevant_events now returns eco fields
- instruments.json: type field on all 90 drivers across 20 instruments
  (event_calendar | report | geopolitical | fundamental | sentiment | technical)

Frontend (InstrumentDashboard):
- EventTimelineStrip: vertical cursor line tracking crosshair selectedDate
- EventsCard: active-event highlight at hovered date + expected/actual/
  surprise_pct display + absorption progress bar
- DriversPanel: type selector dropdown per driver
- DriverTypeBadge: colored micro-badge on driver labels in strip

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-25 00:07:41 +02:00
parent aec9ced74f
commit 3470205d54
6 changed files with 878 additions and 160 deletions

View File

@@ -753,8 +753,13 @@ def init_db():
)""")
# Add columns to existing DBs (idempotent via catch)
for _col, _def in [
("absorption_pct", "REAL DEFAULT NULL"),
("relevant_indicators", "TEXT DEFAULT '[]'"),
("absorption_pct", "REAL DEFAULT NULL"),
("relevant_indicators", "TEXT DEFAULT '[]'"),
("expected_value", "TEXT DEFAULT NULL"),
("actual_value", "TEXT DEFAULT NULL"),
("surprise_pct", "REAL DEFAULT NULL"),
("unit", "TEXT DEFAULT NULL"),
("sub_type", "TEXT DEFAULT NULL"),
]:
try:
c.execute(f"ALTER TABLE market_events ADD COLUMN {_col} {_def}")
@@ -4480,12 +4485,16 @@ def save_market_event(ev: Dict[str, Any]) -> int:
try:
cur = conn.execute("""INSERT INTO market_events
(name, start_date, end_date, level, category, description, market_impact,
affected_assets, impact_score, parent_event_id)
VALUES (?,?,?,?,?,?,?,?,?,?)""",
affected_assets, impact_score, parent_event_id,
expected_value, actual_value, surprise_pct, unit, sub_type, absorption_pct)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
(ev["name"], ev["start_date"], ev.get("end_date"),
ev["level"], ev.get("category", "macro"), ev.get("description", ""),
ev.get("market_impact", ""), json.dumps(ev.get("affected_assets", [])),
ev.get("impact_score", 0.5), ev.get("parent_event_id")))
ev.get("impact_score", 0.5), ev.get("parent_event_id"),
ev.get("expected_value"), ev.get("actual_value"),
ev.get("surprise_pct"), ev.get("unit"), ev.get("sub_type"),
ev.get("absorption_pct")))
conn.commit()
return cur.lastrowid
finally: