spread_pct P0: real decision-time bid/ask spread as an observe-only metric #3

Merged
fez5587 merged 1 commits from claude/float-recreation-trading-gcn42l into master 2026-06-29 17:48:39 -04:00
1 Commits
Author SHA1 Message Date
Claude 37f39299ad spread_pct P0: real decision-time bid/ask spread as an observe-only metric
GO_LIVE flags `spread_pct` as a not-yet-real field. The reason it was null is
structural: OHLCV bars carry no NBBO, so `minute_bars.spread_pct` can never be
populated from the bars endpoint. The execution-relevant figure is the spread at
the moment a setup is evaluated — a wide book quietly eats R on the thin sub-$20
names this system trades.

This makes that metric real, shadow-first (measure before gating), mirroring how
the catalyst score was introduced:

- `strategy/evaluation/liquidity.py`: pure `compute_spread_pct(bid, ask)` →
  (ask-bid)/mid, or None for missing/crossed/non-positive quotes (None never
  collapses to a real 0.0). Unit-tested.
- `AlpacaPaperClient.get_latest_quotes`: batched latest-NBBO fetch, mirrors
  `get_latest_trades`.
- `Watcher`: optional injected `spread_provider` (same shape as
  `catalyst_score_provider`); default None == prior behavior byte-for-byte.
  Computed spread is logged onto the criteria_evaluated and signal_ready events.
  Observe-only — it does NOT gate ready/blocked.
- `run_live_paper`: TTL-cached spread provider off the client; degrades to None
  on any fault, SPREAD_PCT_ENABLED=0 to silence.

The dead `scanner.spread_pct_max` knob is intentionally left for a later
promotion, once the logged data shows spread separates outcomes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019psgRHdtTXz6TCnnqPiqGw
2026-06-29 21:47:41 +00:00