Skip to main content

Construction

The WebSocket is created with the same exchange ID and config as Exchange.new. In Python and TypeScript, call exchange.websocket() to reuse credentials.
use openpx::WebSocketInner;
use px_core::websocket::OrderBookWebSocket;
use serde_json::json;

let mut ws = WebSocketInner::new("polymarket", json!({
    "private_key": std::env::var("POLYMARKET_PRIVATE_KEY")?,
    "funder": std::env::var("POLYMARKET_FUNDER")?,
}))?;

let updates = ws.updates().expect("first call");
let session = ws.session_events().expect("first call");

ws.connect().await?;
ws.subscribe("0x311d0c4b…").await?; // condition_id token, see below

Subscription target by exchange

subscribe(market_id) takes a string whose meaning depends on the exchange:
ExchangeWhat to pass
KalshiMarket ticker (e.g. KXBTC-25MAR14-T20000)
PolymarketA CLOB token ID (e.g. Market.token_id_yes or token_id_no)
Polymarket’s WebSocket also exposes subscribe_pair(yes_token, no_token) for binary markets — both sides get full book updates, and price_change events on either side are dispatched correctly.

Outcome labels (Polymarket)

Activity events (Trade, Fill) include an outcome label ("Yes" / "No") when token IDs are registered. Either subscribe via subscribe_pair, or call:
ws.register_outcomes(yes_token_id, no_token_id)
before subscribing. No-op on Kalshi.

Reconnect & keepalive

Tunable constants in engine/core/src/websocket/traits.rs:
ConstantValuePurpose
WS_PING_INTERVAL20sKeepalive ping cadence
WS_RECONNECT_BASE_DELAY3sInitial reconnect backoff
WS_RECONNECT_MAX_DELAY60sCap on backoff
WS_MAX_RECONNECT_ATTEMPTS10Before giving up
WS_STALL_TIMEOUT90sForce reconnect if no message received
WS_STALL_CHECK_INTERVAL10sHow often the stall watchdog ticks
On a clean reconnect, expect one SessionEvent::Reconnected { gap_ms } plus a Snapshot for every previously subscribed market.