API · Справочник

У Полимаркета две системы реального времени, на двух разных хостах. CLOB WebSocket стримит стакан заявок и обновления ваших собственных ордеров; поток RTDS стримит актуальные ценовые данные (крипто, акции) и комментарии. Их путаница — самая частая ошибка - эта страница держит их разделёнными, с точными эндпоинтами, heartbeat и корректным переподключением.

Два хоста
  • CLOB — wss://ws-subscriptions-clob.polymarket.com/ws/ · каналы market (публичный, стакан заявок), user (с аутентификацией, ваши ордера/исполнения), sports (актуальное состояние игры для спортивных рынков) и шлюз rfq (актуальное состояние Request-for-Quote — см. раздел RFQ).
  • RTDS — wss://ws-live-data.polymarket.com · топики crypto_prices, crypto_prices_chainlink, equity_prices, comments.

Канал market у CLOB (без аутентификации)

Подпишитесь на один или несколько token ID и получайте стакан заявок и обновления: начальный снимок book, затем события price_change, tick_size_change и last_trade_price. Учётные данные не нужны.

import asyncio, json, websockets

async def stream(token_ids):
    url = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
    async with websockets.connect(url, ping_interval=10) as ws:
        await ws.send(json.dumps({"assets_ids": token_ids, "type": "market"}))
        async for msg in ws:
            evt = json.loads(msg)
            print(evt.get("event_type"), evt)

asyncio.run(stream([TOKEN_ID]))
import WebSocket from "ws";
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
ws.on("open", () => ws.send(JSON.stringify({ assets_ids: [TOKEN_ID], type: "market" })));
ws.on("message", (d) => console.log(JSON.parse(d)));

Канал user у CLOB (с аутентификацией)

Канал user сообщает о жизненном цикле вашего ордера (постановка, совпадения, отмены). Ему нужны ваши apiKey/secret/passphrase, и вы подписываетесь по condition_id (рынок), а не по token ID. Подключитесь к wss://ws-subscriptions-clob.polymarket.com/ws/user и включите свою аутентификацию в payload подписки:

await ws.send(json.dumps({
    "type": "user",
    "markets": [CONDITION_ID],          # subscribe by condition_id, not token_id
    "auth": {"apiKey": API_KEY, "secret": SECRET, "passphrase": PASSPHRASE},
}))
# events: "order" (placed/cancelled) and "trade" (your fills)

Ценовые потоки RTDS

Отдельный хост — wss://ws-live-data.polymarket.com — для актуальных ценовых данных, не стаканов заявок. Подпишитесь на топик: crypto_prices (Binance), crypto_prices_chainlink (оракул Chainlink), equity_prices или comments. Полезно для базового сигнала в ботах крипто/акционных прогнозных рынков.

Heartbeat и переподключение

  • Heartbeat — отправляйте PING примерно каждые 10 секунд; сервер отвечает PONG. Пропустите его — и соединение рвётся.
  • Менять вживую — вы можете добавлять/убирать топики или активы на открытом соединении; вам не нужно переподключаться, чтобы изменить свою подписку.
  • Переподключаться правильно — после любого разрыва заново запросите REST-снимок стакана (GET /book), прежде чем снова доверять инкрементальным обновлениям. Стримленные дельты, которые вы пропустили в отключении, потеряны; REST-снимок пересинхронизирует ваш локальный стакан.

Весь паттерн в одном устойчивом цикле — heartbeat, переподключение с backoff и REST-пересинхронизация на каждом (пере)подключении:

import asyncio, json, time, requests, websockets

async def resilient_stream(token_id, on_event):
    url = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
    backoff = 1
    while True:
        try:
            async with websockets.connect(url, ping_interval=10) as ws:
                # 1) REST snapshot first so the local book is correct before deltas
                book = requests.get("https://clob.polymarket.com/book",
                                    params={"token_id": token_id}).json()
                on_event({"event_type": "snapshot", "book": book})
                # 2) subscribe and stream
                await ws.send(json.dumps({"assets_ids": [token_id], "type": "market"}))
                backoff = 1                       # reset after a clean connect
                async for msg in ws:
                    on_event(json.loads(msg))
        except Exception as e:
            print("ws drop, resync in", backoff, "s:", e)
            await asyncio.sleep(backoff)
            backoff = min(backoff * 2, 30)        # exponential backoff, capped
Не путайте хосты. Стаканы заявок и ваши ордера приходят с хоста CLOB (ws-subscriptions-clob); крипто/акционные цены и комментарии приходят с RTDS (ws-live-data). Это разные сервисы с разными payload.

Далее: Справочник CLOB REST · Лимиты запросов и backoff · Собрать: стриминг стакана в боте.