GUARDLABS
GuardLabs · Technical note

Architecting Rate-Limit-Free WebSockets for Binance and OKX Live Prices

Connecting to Binance and OKX WebSockets for real-time price feeds often triggers rate limits or IP bans when implemented incorrectly. Neither exchange offers an "unlimited" API, but you can stream hundreds of live pairs without hitting rate limits by leveraging server-push streams, combined stream multiplexing, and proper connection management.

Understanding How Exchange Limits Apply to WebSockets

Rate limits on WebSocket APIs apply to client-to-server requests (such as sending subscribe, unsubscribe, or ping messages), not to incoming price data pushed by the exchange.

  • Binance: Allows up to 1,024 streams per WebSocket connection. Incoming client messages are capped at 5 per second. Connection attempts are capped at 300 per 5 minutes per IP.
  • OKX: Allows up to 240 channel subscriptions per WebSocket connection. Outgoing requests sent to the server are limited to 100 requests per 2-second window.

Strategy 1: Multiplexing via Combined Streams

Opening a separate WebSocket connection for each trading pair rapidly exhausts connection caps and triggers IP bans. Instead, pass all required streams in the initial connection URL (Binance) or send a single batch subscription payload (OKX).

Binance Combined Stream Endpoint:

wss://stream.binance.com:9443/stream?streams=btcusdt@ticker/ethusdt@ticker/solusdt@ticker

OKX Batch Subscription Payload:

{
  "op": "subscribe",
  "args": [
    {"channel": "tickers", "instId": "BTC-USDT"},
    {"channel": "tickers", "instId": "ETH-USDT"}
  ]
}

Strategy 2: Production Python Implementation

This asynchronous Python implementation uses asyncio and websockets to consume price feeds from both Binance and OKX on persistent, multiplexed connections.

import asyncio
import json
import websockets

BINANCE_URL = "wss://stream.binance.com:9443/stream?streams=btcusdt@ticker/ethusdt@ticker"
OKX_URL = "wss://ws.okx.com:8443/ws/v5/public"

async def listen_binance():
    async for websocket in websockets.connect(BINANCE_URL):
        try:
            async for message in websocket:
                data = json.loads(message)
                payload = data.get("data", {})
                print(f"[Binance] {payload.get('s')}: {payload.get('c')}")
        except websockets.ConnectionClosed:
            await asyncio.sleep(2)  # Exponential backoff prevents reconnect bans

async def listen_okx():
    sub_payload = {
        "op": "subscribe",
        "args": [
            {"channel": "tickers", "instId": "BTC-USDT"},
            {"channel": "tickers", "instId": "ETH-USDT"}
        ]
    }
    async for websocket in websockets.connect(OKX_URL):
        try:
            await websocket.send(json.dumps(sub_payload))
            async for message in websocket:
                data = json.loads(message)
                if "data" in data:
                    for ticker in data["data"]:
                        print(f"[OKX] {ticker['instId']}: {ticker['last']}")
        except websockets.ConnectionClosed:
            await asyncio.sleep(2)

async def main():
    await asyncio.gather(listen_binance(), listen_okx())

if __name__ == "__main__":
    asyncio.run(main())

Best Practices for High-Volume Data Ingestion

  • Chunk Connection Pools: If tracking more than 1,000 Binance pairs or 240 OKX channels, pool your requests across multiple WebSocket instances (e.g., Connection 1 for pairs 1–200, Connection 2 for 201–400).
  • Implement Exponential Backoff: On socket disconnects, wait before attempting to reconnect (e.g., 1s, 2s, 4s, 8s). Tight reconnection loops will trigger temporary IP bans.
  • Manage Client Pings: OKX requires a string message "ping" sent every 20 seconds to keep the connection alive. Binance sends ping frames automatically; ensure your client library responds with pong frames.
  • Use Lightweight Payloads: Use @bookTicker (best bid/ask) or @miniTicker on Binance instead of full order book streams (@depth) to minimize CPU usage and bandwidth overhead.

Need this done fast? order a fix on Kwork.

Published 2026-07-27 2 min read All articles
Need help with this?

I take on freelance fixes and builds in this area.