Fix unbounded universe -> over-cap ingest 400 (audit HIGH #2)

The live 'symbols' list only ever grew (discover appends every 5 min, dashboard
injects add more) and was comma-joined into ONE bars request; once >~100 symbols
Alpaca 400s the whole batch -> ALL minute-bar ingestion silently stops mid-session.

- client.get_minute_bars / get_daily_bars / get_latest_trades batch symbols in
  chunks of 100 (cap-safe) and merge; get_daily_bars also paginates now.
- run_live_paper bounds the watchlist (WATCHER_MAX_UNIVERSE, default 80) so it
  rotates toward current movers instead of growing all day.

Found by the silent-failure audit workflow. Verified _chunked(250)->[100,100,50],
live calls intact. 71/71 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
momentum devandClaude Opus 4.8 committed 2026-06-16 13:43:35 -04:00
1 parent 3e2b4f562e
commit e134818aea
2 files changed
+66 -39

No files matched your search

+6
View File
@@ -373,6 +373,12 @@ def main(argv: list[str] | None = None) -> int:
# pulls their bars and the watcher evaluates them
added = [s for s in res.universe if s not in symbols]
symbols.extend(added)
# Keep the watchlist BOUNDED so it rotates toward current movers instead
# of growing all session. (Ingestion is now batched so an over-cap list
# no longer 400s, but an unbounded list is still wasteful and stale.)
max_uni = int(os.environ.get("WATCHER_MAX_UNIVERSE", "80"))
if len(symbols) > max_uni:
del symbols[: len(symbols) - max_uni]
return (f"universe={len(res.universe)} gappers={len(res.gappers)}"
+ (f" +{len(added)} new" if added else ""))