Realtime uses the binary Centrifugo Protobuf WebSocket protocol, not ConnectRPC streaming and
not SBE; order updates use the private order WebSocket (GET /v1/ws/private). Service subscribe* helpers return an AsyncSubscription you consume with async for / async with.
The SDK negotiates the centrifuge-protobuf WebSocket subprotocol. Both Centrifugo control frames
and :proto channel publications are binary Protobuf. ConnectRPC's optional JSON wire mode is
unrelated and never changes realtime framing.
Managed order-book and market-overview create methods return only after the WebSocket handshake
and initial snapshot succeed. Pass on_error= so a terminal snapshot, decode, transport, or
buffering failure is observable immediately; callback exceptions are isolated from the worker.
Contract
sub = await client.orders.subscribe(account_id=account_id)
sub.set_on_error(lambda error: print(f"realtime interruption: {error}"))
async with sub:
async for event in sub:
print(event.type)- Subscribe awaits handshake (including private token fetch) before returning.
- Initial auth failures raise; they do not spin forever in the background.
- On overflow,
PolyesterRealtimeOverflowErrorfaults the subscription (fail-closed). - Reconnect uses capped exponential backoff with per-subscription jitter.
client.orders.subscribeyields private-stream events, not bare orders. See Orders.
What you can stream
- Public trades:
client.market_data.subscribe_trades(public) - Candles:
client.market_data.subscribe_candles(public) - Order book:
client.orderbookmanaged subscription (public) - Market overview:
client.market_overview.subscribe*(public) - Heatmap:
client.heatmap.subscribe_live(public) - Lifecycle:
client.lifecycle.subscribe_open_flows/subscribe_flow_detail(public or private) - Zipped-asset supply:
client.zipper.subscribe_zipped_asset_supply(public) - Profile identity:
client.auth.profile.subscribe_identity(public) - Your orders:
client.orders.subscribe(private) - Your triggers:
client.triggers.subscribe/subscribe_events(private) - Your trades:
client.trades.subscribe(private) - Balances:
client.balances.subscribe(private) - Transfers:
client.transfers.subscribe(private) - API keys / subaccounts: matching
subscribehelpers (private) - API/subaccount policies:
client.policies.subscribe_*(private) - Address-book invalidations:
client.address_book.subscribe_view_invalidations(private)
Private streams need API-key auth and Account ID.
PolyesterAuthError is non-transient; inspect its code, context, and endpoint, then
update the key policy before reconnecting.Public trades example
subscription = await client.market_data.subscribe_trades(symbol="BTC-USDT")
async with subscription:
async for trade in subscription:
print(trade.price)
breakSnapshot-then-stream
Managed order-book subscriptions snapshot via REST, then stream deltas. Sequence gaps trigger a REST snapshot refresh. Prefer these helpers over wiring raw channels yourself.
Market overview uses the same managed snapshot-then-stream pattern. For entity streams (balances, trades, transfers, triggers), the event channel is not a complete starting snapshot: subscribe first, fetch the corresponding list/snapshot, buffer events that arrive during the read, then reconcile by entity ID plus version/timestamp. After reconnect, re-read authoritative state before declaring the bot healthy.
The private order stream resumes on its own: read list_open(), subscribe, wait for PrivateOrdersReady, then merge by version. A position the server can no longer resume arrives as
a fresh PrivateOrdersSnapshot that replaces local state.
Other typed subscriptions do not recover missed publications across reconnect. Poll sub.take_resubscribed() (or watch sub.resubscribed) after each receive and treat a latch as a
gap: rebuild from REST before trusting the stream again. A WebSocket read timeout is treated as
connection death so half-open sockets reconnect instead of freezing.
Do not place or maintain quotes from a raw order-book delta stream. Use the managed order-book helper, which detects sequence gaps and refreshes state.
Overflow
PolyesterRealtimeOverflowError and closes the
subscription. It does not silently drop updates. Fix consumer speed, then
resubscribe and rebuild authoritative state. A new subscription alone does not recover missed
entity events.Connection notes
client.realtime is always present. You rarely call it directly. Hyphenated private channel names
(for example segments containing api-keys) are valid for API-key signing.
Session model: WebSocket session model. Reference: Realtime.