Repository navigation
v1.4.2 — Multi-venue paper funding + WS hybrid
What's in this release
Two paper-trading correctness/UX wins.
1. Multi-venue paper funding correctness
Single-venue paper sessions were correct; multi-venue sessions silently
underreported funding. The tick loop only queried
`session.broker.venue` from `venue_funding_rates` so a
funding-dislocation-arb session holding Drift-long + HL-short would
book Drift's rate against both legs combined and miss HL entirely.
Fix (Option A from `docs/specs/paper-multivenue-funding.md`):
- `PaperBroker.apply_funding(market, rate, mark_price, venue=None)` —
new optional venue kwarg skips the apply when the position's venue
doesn't match. - `flint/paper/engine.py`: extracted `_apply_session_funding(...)`
helper that iterates `venues_in_book` derived from the broker's
open positions, queries `venue_funding_rates` per venue, applies
per-leg with `venue=` filter. - `paper_funding_payments` table widened: `venue` column added,
PK becomes `(session_id, market, venue, ts)`. Migration mirrors
the existing candles/orderbook venue-column pattern. - `PaperSessionStore.save_funding_payment` accepts `venue=`.
Doesn't fix Gap 2 (broker.positions still keyed by market only — same-market
opposite-leg arb collides on the dict key); deferred to D-2.1.d.
7 new tests, 39/39 paper-suite green.
2. WS hybrid hooks (drop polling-only, keep safety-net)
Live + paper session pages were poll-only on a 2s interval. Pure-WS
would be cleaner code but a single WS bug = dead UI.
New `useHybridPoll<TPoll, TWs>` hook: WS-primary, polling
secondary — adapts the polling cadence to WS health.
- WS healthy → poll slowly (30s) for snapshot refresh
- WS dead/silent → polling re-arms at the original cadence (2s)
- `wsHealthy` flag exposes connection state for ConnectionBanner UX
Migrated:
- `useSessionStatus` → `/ws/paper/{id}` + REST snapshot fallback,
overlays live equity/cash/unrealized_pnl/total_trades on the snapshot - `useLiveMonitor` → `/ws/live/{id}` + REST snapshot fallback,
appends WS equity points to the polled curve and merges WS fills
with (fill_id, ts) dedupe
`usePaperPortfolio` stays poll-only (no `/ws/portfolio` aggregate
channel exists).
6 new tests, 139/139 vitest green (was 133).
Tests
- 25/25 paper-funding + multi-venue Python suite
- 139/139 vitest UI suite
- ruff clean
Files
- `flint/execution/paper_broker.py`, `flint/paper/engine.py`,
`flint/paper/session_store.py`, `flint/store.py` - `tests/test_paper_funding.py`, `tests/test_paper_multi_venue.py`
- `ui/src/hooks/useHybridPoll.ts` (new), `useLiveMonitor.ts`,
`usePaperTrading.ts` - `ui/src/test/hooks/useHybridPoll.test.ts` (new)
🤖 Generated with Claude Code