feat: driver-based timeline strip, regime signal metrics, drivers editor
- 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>
This commit is contained in:
@@ -42,6 +42,33 @@ def get_instrument(instrument_id: str) -> Optional[Dict]:
|
||||
return _configs.get(instrument_id.upper())
|
||||
|
||||
|
||||
def update_instrument_drivers(instrument_id: str, drivers: List[Dict]) -> None:
|
||||
"""Persist updated drivers to instruments.json and refresh in-memory config."""
|
||||
global _configs
|
||||
if _configs is None:
|
||||
_load_configs()
|
||||
|
||||
uid = instrument_id.upper()
|
||||
if uid not in _configs:
|
||||
raise ValueError(f"Instrument {uid} not found")
|
||||
|
||||
# Load raw JSON, update the matching instrument, save back
|
||||
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
|
||||
raw = json.load(f)
|
||||
|
||||
for inst in raw["instruments"]:
|
||||
if inst["id"] == uid:
|
||||
inst["drivers"] = drivers
|
||||
break
|
||||
|
||||
with open(CONFIG_PATH, "w", encoding="utf-8") as f:
|
||||
json.dump(raw, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# Refresh in-memory cache
|
||||
_configs[uid]["drivers"] = drivers
|
||||
logger.info(f"[instrument_service] Updated drivers for {uid} ({len(drivers)} drivers)")
|
||||
|
||||
|
||||
# ── DataFrame helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
def _ohlcv_to_df(records: List[Dict]) -> pd.DataFrame:
|
||||
|
||||
Reference in New Issue
Block a user