Real-time market data via WebSocket.
Real-time market data via WebSocket. Subscribe to order books, trades, tickers, prices, candlesticks, and open interest across supported exchanges.
WebSocket URL: wss://md.liquiditytech.com/marketdata/v2/public
Supported exchanges: BINANCE / OKX / EDX
Connection
Responses are GZIP-compressed by default. To receive plain text, append ?binary=false to the URL:
wss://md.liquiditytech.com/marketdata/v2/public?binary=false
To decompress in Python:
import zlib
# binary_data is the raw bytes received from ws.recv()
decompressed = zlib.decompress(binary_data, zlib.MAX_WBITS | 16).decode('utf-8')
Authentication
Authentication is optional. Unauthenticated connections work immediately but have lower rate limits.
To authenticate, send a login message after connecting and before subscribing
{
"action": "login",
"args": {
"apiKey": "your_api_key",
"timestamp": "1597026383085",
"sign": "your_signature"
}
}
Note: the login message uses
"action"and"args"(an object), while subscribe/unsubscribe messages use"event"and"arg"(an array). These are different field names.
Signature: HMAC-SHA256(secret, timestamp + "GET" + "/users/self/verify"), hex-encoded.
import hmac, hashlib, time
api_key = "your_api_key"
secret = "your_secret_key"
timestamp = str(int(time.time()))
message = timestamp + "GET" + "/users/self/verify"
sign = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
Response:
{ "event": "login", "code": "200000", "msg": "success" }
Rate Limits
| Unauthenticated | Authenticated | |
|---|---|---|
| Max connections per IP | 5 | 40 |
| Max trading pairs per connection | 5 | 50 |
Subscription rate: max 50 subscribe/unsubscribe requests per second per IP. Exceeding this returns error 11260.
Limits are counted by trading pair, not by channel. Subscribing to
TICKER,ORDER_BOOK, andTRADEfor the same symbol counts as 1 trading pair.
Heartbeat
The server sends a WebSocket protocol-level ping shortly after the connection is established. Most WebSocket client libraries handle this automatically.
The connection is closed if the client is inactive for 60 seconds. To keep the connection alive, the client must send a JSON ping at regular intervals (recommended: every 20 seconds):
The client can also send a ping at any time:
{ "ping": 1769050973831 }
Server response:
{ "pong": 1769050974552 }
For subscribed connections receiving frequent pushes (e.g.
TICKER,BBO), the data flow itself keeps the connection alive. Explicit pings are only required when subscribed to low-frequency or no channels.
Symbol Format
Symbols follow the pattern {EXCHANGE}_{TYPE}_{BASE}_{QUOTE}:
| Part | Values | Example |
|---|---|---|
EXCHANGE | BINANCE / OKX / EDX | BINANCE |
TYPE | SPOT / PERP (perpetual futures) | PERP |
BASE | Base currency | BTC |
QUOTE | Quote currency | USDT |
Examples: BINANCE_PERP_BTC_USDT, OKX_SPOT_ETH_USDT
Futures-only channels (
MARK_PRICE,INDEX_PRICE,OPEN_INTEREST, etc.) require aPERPsymbol. Using aSPOTsymbol with these channels returns error11100.
Subscribe & Unsubscribe
Multiple channels can be included in a single request.
Subscribe:
{
"event": "subscribe",
"arg": [
{ "channel": "TICKER", "sym": "BINANCE_PERP_BTC_USDT" },
{ "channel": "ORDER_BOOK", "sym": "OKX_SPOT_ETH_USDT", "level": 50 }
]
}
Unsubscribe:
{
"event": "unsubscribe",
"arg": [
{ "channel": "TICKER", "sym": "BINANCE_PERP_BTC_USDT" }
]
}
Success response:
{
"event": "subscribe",
"arg": [{ "channel": "TICKER", "sym": "BINANCE_PERP_BTC_USDT" }],
"code": 0,
"message": "Success"
}
Failure response:
{
"event": "subscribe",
"arg": [{ "channel": "TICKER", "sym": "INVALID_SYM" }],
"code": 11100,
"message": "invalid symbols"
}
All channel names must be uppercase. Using lowercase returns error
11103.
Available Channels
| Channel | Description | Push Frequency | Scope |
|---|---|---|---|
TICKER | 24-hour rolling ticker | 2000ms | All |
ORDER_BOOK | Order book depth | 250ms | All |
BBO | Best bid & offer | On change | All |
TRADE | Latest trades | Real-time | All |
MARK_PRICE | Mark price | Real-time | Futures only |
INDEX_PRICE | Index price | Real-time | Futures only |
KLINE | Candlestick (trade price) | Real-time | All |
INDEX_KLINE | Candlestick (index price) | Real-time | Futures only |
MARK_PRICE_KLINE | Candlestick (mark price) | Real-time | Futures only |
OPEN_INTEREST | Contract open interest | Real-time | Futures only |
Error Codes
| Code | Description |
|---|---|
200000 | Login successful |
11100 | Invalid symbol |
11101 | Invalid candlestick interval |
11102 | Invalid event type |
11103 | Invalid channel name (must be uppercase) |
11106 | Unknown protocol version |
11107 | Depth data not found |
11108 | Response too long |
11109 | Too many symbols subscribed |
11112 | Invalid depth level |
11200 | Invalid request parameter |
11210 | Exceeded 5-symbol limit (unauthenticated) |
11220 | Exceeded 50-symbol limit (authenticated) |
11230 | Exceeded 5-connection limit (unauthenticated) |
11240 | Exceeded 40-connection limit (authenticated) |
11250 | Symbol not currently supported |
11260 | Exceeded 50 requests/second limit |
