Files
momentum-system/api
momentum devandClaude Opus 4.8 45ba264534 Fix P&L mislabelling + add a Catalyst Engine feed so the LLM is legible
Two things the operator couldn't see were wrong/opaque:

1) P&L attribution bug. query_session_pnl read each position's unrealized as
   `unrealized_pl`, but the live snapshot stores it as `unrealized_pnl` (see
   alpaca_paper/sync.py). So unrealized always read $0 and the ENTIRE broker
   equity-delta was dumped into "Realized" — a real +$330 realized / -$67
   unrealized day showed as "$263 realized, $0 unrealized, 0 closed". Fixed to
   prefer the stored key, accept the alpaca-native alias, else derive from
   qty*(price-cost). The existing test used the same wrong key (which is why it
   never caught this) — corrected, plus a regression test reproducing the exact
   broker-delta day and a derive-from-qty test.

   (Still surfaced separately: closed round-trips emit no position_closed event,
   so realized P&L is broker-derived and the trade list / win-rate read 0. That
   journaling gap is noted, not fixed here.)

2) Catalyst Engine feed. The Ollama portion only showed totals; you couldn't see
   WHAT it read or WHY it ruled. Added query_catalyst_feed (the raw stream from
   news_catalyst_cache, newest first, with a `vetoed` flag = dilutive AND
   conviction >= the 0.60 floor) -> snapshot `catalyst_feed` -> a new dashboard
   panel under Armed Triggers: time (ET), symbol, colored read (🟢/🔻/🔴 +
   type), conviction, headline, and the model's own rationale, with a red ⚠ VETO
   badge on confirmed dilution. Makes the engine legible at the open — and
   immediately exposed the 7B over-tagging one "SpaceX bear ETF" headline as
   dilutive across a dozen unrelated large-caps (harmless: none are targets).

Verified headless: strip reads total/realized/unrealized correctly; feed renders
40 reads with rationale; no JS errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 20:21:30 -04:00
..