# Phase 6: Combined WS Implementation - Context

**Gathered:** 2026-03-19
**Status:** Ready for planning

<domain>
## Phase Boundary

Implement `CombinedWebSocketStream` as a new struct in `crates/opendeviationbar-providers/src/binance/` that connects to `wss://stream.binance.com:9443/stream?streams=...` with all 18 symbols on a single connection (1x18 config — spike-tested winner at 52.5 msg/s, 0 TID gaps). Demuxes combined stream envelope `{"stream":"btcusdt@aggTrade","data":{...}}` to per-symbol `mpsc::Sender<AggTrade>` channels. Replace per-symbol `BinanceWebSocketStream` connections in `LiveBarEngine::start_ws()`.

</domain>

<decisions>
## Implementation Decisions

### Configuration

- **1x18 topology** (spike test winner) — single connection, all 18 symbols
- New `CombinedWebSocketStream` struct (NOT a mode in existing `BinanceWebSocketStream`)
- Combined stream URL: `wss://stream.binance.com:9443/stream?streams=btcusdt@aggTrade/ethusdt@aggTrade/...`
- Envelope format: `{"stream":"btcusdt@aggTrade","data":{<AggTrade fields>}}`

### Architecture

- Outputs to per-symbol `mpsc::Sender<AggTrade>` channels — same channels `symbol_task()` already reads from
- `symbol_task()` interface UNCHANGED — it consumes from `mpsc::Receiver<AggTrade>` regardless of source
- Antaeus reconnection logic (backon ExponentialBuilder + jitter) reused for combined stream
- On reconnect, Puck fills each symbol's gap independently

### Claude's Discretion

- Internal struct layout, error types, module organization
- Whether to put in `combined_ws.rs` or extend `websocket.rs`
- Demux implementation details (HashMap<String, Sender> vs match)
- Tracing span structure for combined stream events

</decisions>

<code_context>

## Existing Code Insights

### Reusable Assets

- `BinanceWebSocketStream` in `crates/opendeviationbar-providers/src/binance/websocket.rs` — per-symbol WS pattern
- `BinanceAggTrade` / `AggTrade` types — trade struct with all fields
- `ReconnectionPolicy` — configurable backoff parameters
- `run_with_reconnect()` — Antaeus reconnection loop pattern
- `start_ws()` in `live_engine.rs` — creates per-symbol connections, can be modified to create one combined connection

### Key Files

- `crates/opendeviationbar-providers/src/binance/websocket.rs` — existing WS implementation
- `crates/opendeviationbar-providers/src/binance/mod.rs` — module exports
- `crates/opendeviationbar-streaming/src/live_engine.rs` — `start_ws()` creates connections, `symbol_task()` consumes trades

### Integration Points

- `start_ws()` in `live_engine.rs` — replace per-symbol WS spawn with single combined WS spawn + demux
- Per-symbol `mpsc::Sender<AggTrade>` channels — combined stream feeds into these same channels
- Shutdown signal — combined stream must respect the existing `CancellationToken`

</code_context>

<specifics>
## Specific Ideas

MATICUSDT showed 0 messages in spike test — may be delisted. The implementation should handle symbols with zero trades gracefully (no panic, just log).

Fallback to 2x9_even is possible by changing only the connection count and symbol grouping — architecture supports N connections with arbitrary symbol splits.

</specifics>

<deferred>
## Deferred Ideas

None

</deferred>
