new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Quant · Exchange APIs · all subjects

WebSocket and reconnects

5 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

How do I keep a Binance user data stream alive (listenKey)?

Pattern: `POST /api/v3/userDataStream` (spot) or `POST /fapi/v1/listenKey` (futures) returns a listenKey; connect to the WS endpoint with that key in the path. Keepalive: `PUT` the same endpoint every 30 minutes — the key dies after 60 minutes without one, and the stream silently stops. On reconnect, mint a FRESH key. Events: `executionReport` (order/fill updates) and `outboundAccountPosition` (balances) on spot; `ORDER_TRADE_UPDATE` and `ACCOUNT_UPDATE` on futures. Treat REST account snapshot + stream deltas as your authoritative state. As of early 2026 Binance has been migrating user data toward direct WebSocket-API session subscriptions (`session.logon`) — the listenKey pattern still works, but verify current docs before building new integrations.

How do I maintain a local order book from the diff depth stream?

Canonical recipe: 1) open the diff stream (`<symbol>@depth@100ms`) and BUFFER incoming events; 2) fetch a REST snapshot (`GET /api/v3/depth?limit=1000`; futures `/fapi/v1/depth` — mind the higher weight for deep limits); 3) drop buffered events with `u <= snapshot.lastUpdateId`; 4) the first applied event must satisfy `U <= lastUpdateId + 1 <= u`, proving continuity; 5) from then on, each event's `pu` must equal the previous event's `u` — any mismatch is a gap: discard everything and restart from step 1. Apply deltas level by level; a quantity of `0` removes the level. Depth beyond the snapshot limit is invisible, so choose the limit to cover your strategy's price range. Never try to 'skip ahead' after a gap — full resync, always.

What do the u, U and pu fields mean and when do I resync?

In Binance diff depth events: `U` = first update ID in this event, `u` = last update ID, `pu` = the `u` of the PREVIOUS event (chain-continuity check; `pu` arrived on spot later than on futures — verify per stream). A single event can straddle your snapshot point, which is exactly why the alignment rule is `U <= lastUpdateId+1 <= u`, not a simple equality. Gaps happen on any disconnect, TCP stall, or exchange overload — you usually cannot distinguish 'no updates' from 'lost updates' except via `pu` or a silent timeout on a busy symbol. Resync triggers: `pu` mismatch, socket error, heartbeat timeout, or a stale book (no event for N seconds on an active symbol). Log resync counts; frequent resyncs mean your snapshot/apply loop is too slow, not that the exchange is flaky.

How should I handle ping/pong and reconnects on exchange WebSockets?

Binance sends protocol-level ping frames about every 3 minutes and drops the connection if no pong arrives within ~10 minutes — most libraries auto-pong, but custom stacks must reply, and an event loop blocked by heavy book processing will miss pongs. Connections are also capped in lifetime (roughly 24h on Binance spot), so schedule rolling reconnects instead of treating drops as anomalies. Bybit v5 and OKX require APPLICATION-level pings (send `{"op":"ping"}` / `ping` every ~20 s) on top of protocol frames. On every reconnect: resubscribe all streams, refresh the listenKey/session, resync order books, and reconcile private state via REST. Back off with jitter — a fleet reconnecting in lockstep after an exchange blip is how you earn a REST ban while already wounded.

Why must I reconcile via REST after any WebSocket gap?

User data streams are at-most-once: during a reconnect, fills and balance changes are lost, and there is no replay. After any gap (or suspected gap) pull ground truth from REST: open orders (`GET /api/v3/openOrders`, futures `/fapi/v1/openOrders`), positions (`/fapi/v2/positionRisk`), and balances (`GET /api/v3/account`, `/fapi/v2/account`), then rebuild local state from the REST answer — REST wins every conflict. Make fill processing idempotent regardless: the same fill can legitimately arrive via both a WS event and a REST poll, so dedupe by trade id. Also schedule a periodic full reconcile (every few minutes) even without detected gaps — silent state drift is the failure mode you do not see until PnL does not tie out.

Give your agent this brain