Skip to content

WebSocket Integration

This guide explains how to integrate with the TradeX Market Data WebSocket API for real-time market data: trades, order books, tickers, candles, mark prices, index prices, and funding rates.

ws://localhost:8080/ws # local
wss://marketdata.dokploy.samarpit.dev/ws # production

One connection is multiplexed across all channels. You subscribe per (channel, symbol). Rate limit: 100 messages/second per client.

One channel + one symbol per message:

{ "op": "subscribe", "channel": "book", "symbol": "BTCUSDT-PERP" }

Channels: book, ticker, trades, mark, index, funding, candle:<interval> (intervals 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w). Send one subscribe per channel/symbol you want.

{ "op": "unsubscribe", "channel": "book", "symbol": "BTCUSDT-PERP" }

Set arbitrary decimal price rounding for book (applies to your connection):

{ "op": "config", "prec": 0.5 }
{ "op": "ping" }

Every server frame has a type and (for channel data) channel, symbol, data, and an optional stale flag:

{ "type": "snapshot", "channel": "book", "symbol": "BTCUSDT-PERP", "data": { "bids": [], "asks": [], "seq": 0 } }
{ "type": "delta", "channel": "trades", "symbol": "BTCUSDT-PERP", "data": { }, "stale": false }

type is one of:

  • snapshot — full current state for a channel (sent on subscribe, and for book on rounding changes).
  • delta — an incremental update.
  • pong — reply to ping.
  • ack — reply to config (data: { "prec": 0.5 }).
  • errordata: { "message": "..." }.

Candle frames use the channel name candle:<interval>:

{ "type": "delta", "channel": "candle:1m", "symbol": "BTCUSDT-PERP", "data": { } }
const ws = new WebSocket('wss://marketdata.dokploy.samarpit.dev/ws');
ws.onopen = () => {
ws.send(JSON.stringify({ op: 'subscribe', channel: 'trades', symbol: 'BTCUSDT-PERP' }));
ws.send(JSON.stringify({ op: 'subscribe', channel: 'book', symbol: 'BTCUSDT-PERP' }));
ws.send(JSON.stringify({ op: 'config', prec: 0.5 }));
};
ws.onmessage = (event) => {
const frame = JSON.parse(event.data);
switch (frame.type) {
case 'snapshot':
case 'delta':
handleUpdate(frame.channel, frame.symbol, frame.data, frame.stale);
break;
case 'pong': break;
case 'ack': break;
case 'error': console.error('WS error:', frame.data?.message); break;
}
};
import asyncio, json, websockets
async def subscribe():
uri = "wss://marketdata.dokploy.samarpit.dev/ws"
async with websockets.connect(uri) as ws:
await ws.send(json.dumps({"op": "subscribe", "channel": "trades", "symbol": "BTCUSDT-PERP"}))
async for raw in ws:
frame = json.loads(raw)
if frame.get("type") in ("snapshot", "delta"):
print(frame["channel"], frame["symbol"], frame["data"])
asyncio.run(subscribe())

On reconnect, re-send a subscribe for every (channel, symbol) you had, then re-send config if you use non-default rounding. Use exponential backoff.

  1. Subscribe only to the channels/symbols you need (one message each).
  2. Re-subscribe on reconnect; the server does not remember prior subscriptions.
  3. Honour the stale flag — surface stale feeds in the UI rather than treating them as live.
  4. Respect the 100 msg/s/client rate limit.