Skip to navigation

Quickstart

Stream trades from the market-data socket

This walks the market-data WebSocket end to end: connect, authenticate, subscribe, read frames. You need a token first — see Authentication.

1

Connect

Open a WebSocket to the production endpoint. One connection carries every topic you subscribe to.

wss://marketdata.immix.xyz
2

Authenticate

Send your token as a message once the socket is open — the socket authenticates by message, not in the handshake:

{"op": "auth", "reqId": "auth-1", "params": {"token": "<your token>"}}

The acknowledgement echoes your reqId. Wait for it before you subscribe:

{"op": "auth", "reqId": "auth-1", "success": true}

A token that does not verify is answered "success": false with "error": "invalid_token".

3

Subscribe

A topic is a dotted string: the channel, then the instrument’s symbol.

{"op": "subscribe", "reqId": "sub-1", "params": {"topics": ["trade.OKX@BTC/USDT", "tob.OKX@BTC/USDT"]}}

The acknowledgement answers every topic on its own, in the order you sent them, so one bad symbol never rejects the batch:

{"op": "subscribe", "reqId": "sub-1", "success": true,
"topics": [{"topic": "trade.OKX@BTC/USDT", "state": "live"},
{"topic": "tob.OKX@BTC/USDT", "state": "live"}]}
4

Read frames

Every data frame names its event and its topic:

{"event": "trade", "topic": "trade.OKX@BTC/USDT", "seq": "…", "seqTs": "…",
"data": [{"px": "64887.7", "qty": "0.002", "side": "buy", "tradeId": "…", "exchTs": "…"}]}

Prices and quantities are exact decimal strings: parse them with a decimal type, never a float. Sequence numbers and timestamps are decimal strings too, because they exceed what a JSON number holds exactly.

The same in Python

import asyncio
import json
import os
import websockets # pip install websockets
URL = "wss://marketdata.immix.xyz"
async def expect_ack(ws, op: str) -> None:
"""Read until the acknowledgement of `op` — a heartbeat may arrive first."""
async for raw in ws:
frame = json.loads(raw)
if frame.get("op") == op:
if not frame.get("success"):
raise SystemExit(f"{op} refused: {frame.get('error')}")
return
async def main() -> None:
async with websockets.connect(URL) as ws:
await ws.send(json.dumps({"op": "auth", "reqId": "auth-1",
"params": {"token": os.environ["IMMIX_TOKEN"]}}))
await expect_ack(ws, "auth")
await ws.send(json.dumps({"op": "subscribe", "reqId": "sub-1",
"params": {"topics": ["trade.OKX@BTC/USDT"]}}))
async for raw in ws:
frame = json.loads(raw)
if frame.get("event") == "trade":
for fill in frame["data"]:
print(frame["topic"], fill["side"], fill["qty"], "@", fill["px"])
asyncio.run(main())

What to know next

  • Heartbeats. Every session receives a heartbeat carrying streamAgeMs, the stream-freshness floor: it tells a quiet market from a stalled stream.
  • Falling behind. A session that cannot keep up is disconnected, not throttled. Reconnect, authenticate and subscribe again: a latest-image topic such as tob pushes its current image when you subscribe, and a synced book its snapshot.
  • Books. A book topic may answer syncing rather than live: its snapshot arrives the moment the book is synced. A stale marker means the book cannot be trusted until the restatement that follows it.
  • Conflation. Append a conflation tier to a topic to receive it at a fixed cadence rather than every update — the tiers, every channel and every frame are in the Market Data WebSocket reference.