Skip to main content

Overview

The WebSocketClient provides real-time streaming of orderbook updates and price data over a persistent WebSocket connection. It supports automatic reconnection and event-driven message handling via decorators.

Setup

from limitless_sdk.websocket import WebSocketClient, WebSocketConfig

config = WebSocketConfig(
    url="wss://ws.limitless.exchange",
    auto_reconnect=True,
    reconnect_delay=5,  # seconds between reconnection attempts
)

ws_client = WebSocketClient(config)
ParameterTypeDefaultDescription
urlstrRequiredWebSocket server URL
auto_reconnectboolTrueAutomatically reconnect on disconnection
reconnect_delayfloat1.0Seconds to wait between reconnection attempts

Event Handlers

Register handlers for specific events using the @ws_client.on() decorator:
@ws_client.on("connect")
async def on_connect():
    print("Connected to WebSocket")

@ws_client.on("orderbookUpdate")
async def on_orderbook(data):
    print("Orderbook update:", data)

@ws_client.on("newPriceData")
async def on_price(data):
    print("Price update:", data)

Available Events

EventPayloadAuthDescription
connectNoneFired when the WebSocket connection is established
orderbookUpdatedictPublicOrderbook changes (new bids/asks, removals)
newPriceDatadictPublicLatest price data for subscribed markets
positionsdictAuthenticatedYour position changes (see Authenticated Subscriptions)
orderEventdictAuthenticatedYour CLOB order lifecycle and settlement events

Subscribing to Markets

After connecting, subscribe to specific markets to receive updates:
@ws_client.on("connect")
async def on_connect():
    await ws_client.subscribe(
        "subscribe_market_prices",
        {"marketSlugs": ["btc-above-100k-march-2025"]},
    )
    print("Subscribed to market prices")
The subscribe() method takes two arguments:
ParameterTypeDescription
eventstrSubscription event name (e.g. "subscribe_market_prices")
datadictSubscription parameters including marketSlugs
You can subscribe to multiple markets at once by passing a list of slugs in marketSlugs.

Authenticated Subscriptions

The subscribe_positions and subscribe_order_events channels are per-account and require authentication. Pass hmac_credentials to the config — the SDK signs the WebSocket handshake automatically (no manual headers needed). This is the same flow as the TypeScript SDK; see Authentication to generate a token.
from limitless_sdk import HMACCredentials
from limitless_sdk.websocket import WebSocketClient, WebSocketConfig

config = WebSocketConfig(
    url="wss://ws.limitless.exchange",
    hmac_credentials=HMACCredentials(
        token_id="your_token_id",
        secret="your_token_secret",  # base64-encoded secret from token creation
    ),
    auto_reconnect=True,
)
ws_client = WebSocketClient(config)

Positions

Subscribe to real-time updates when your positions change:
@ws_client.on("connect")
async def on_connect():
    await ws_client.subscribe(
        "subscribe_positions",
        {"marketSlugs": ["btc-above-100k-march-2025"]},
    )

@ws_client.on("positions")
async def on_positions(data):
    print("Position update:", data)

Order Events

Subscribe to your CLOB order lifecycle and settlement events. This channel is per-account and takes no payload:
@ws_client.on("connect")
async def on_connect():
    await ws_client.subscribe("subscribe_order_events")

@ws_client.on("orderEvent")
async def on_order_event(event):
    # Several event shapes arrive on the same `orderEvent` name — distinguish by source, then type
    if event.get("source") == "OME":
        print("Order state:", event.get("type"), event.get("orderId"), event.get("clientOrderId"))
    else:
        print("Settlement:", event.get("type"), event.get("orderId"), event.get("txHash"))
Authenticated subscribe() calls raise ValueError if no hmac_credentials is set. Auth failures surface on the exception event. See the WebSocket Events reference for the full orderEvent payload shapes (source OME vs SETTLEMENT, and type values).

Auto-Reconnect

When auto_reconnect is enabled (the default), the client automatically reconnects after a disconnection:
  1. The connection drops (network issue, server restart, etc.)
  2. The client waits reconnect_delay seconds
  3. A new connection is established
  4. The connect event fires again, so your subscription logic re-executes
Place your subscribe() calls inside the connect handler to ensure subscriptions are restored after every reconnection.

Complete Example

import asyncio
from limitless_sdk.websocket import WebSocketClient, WebSocketConfig

async def main():
    config = WebSocketConfig(
        url="wss://ws.limitless.exchange",
        auto_reconnect=True,
        reconnect_delay=5,
    )
    ws_client = WebSocketClient(config)

    @ws_client.on("connect")
    async def on_connect():
        print("Connected")
        await ws_client.subscribe(
            "subscribe_market_prices",
            {"marketSlugs": ["btc-above-100k-march-2025"]},
        )

    @ws_client.on("orderbookUpdate")
    async def on_orderbook(data):
        slug = data.get("marketSlug", "unknown")
        bids = len(data.get("bids", []))
        asks = len(data.get("asks", []))
        print(f"[{slug}] Orderbook: {bids} bids, {asks} asks")

    @ws_client.on("newPriceData")
    async def on_price(data):
        slug = data.get("marketSlug", "unknown")
        price = data.get("price", "N/A")
        print(f"[{slug}] Price: {price}")

    # Connect, then keep the client alive to receive events
    await ws_client.connect()
    await asyncio.Event().wait()  # runs until interrupted (Ctrl+C)

asyncio.run(main())
await ws_client.connect() returns once the connection is established — it does not block. Keep the event loop alive afterwards (e.g. await asyncio.Event().wait()), otherwise the program exits before any events arrive. Register your @ws_client.on(...) handlers and subscribe() inside the connect handler before calling connect().