Polymarket Bot Tutorial · Розділ 8 із 32

Polymarket CLOB API для botів: REST endpoints для order book snapshots, WebSocket subscriptions для real-time updates, parsing bids/asks, обчислення mid-price і depth, code samples.

Що охоплює цей розділ

CLOB API - це місце, де orders підписуються, надсилаються, match-аться, і де живе order book. У Polymarket є два покоління SDK - застарілий v1 і поточний v2. У цьому розділі розглядається лише v2; v1 не має з’являтися в жодному bot, який ви випускаєте у 2026 році. Ми пройдемо шлях REST snapshot, канал WebSocket updates, деталі parsing, на яких спотикаються нові розробники, і reconnect logic, без якої long-running bot за кілька годин роз’їжджається із синхронізації.

  • CLOB v1 vs v2 (use v2)
  • Order book REST snapshot
  • WebSocket subscriptions: market and user channels
  • Parsing bids/asks/depth
  • Computing mid-price and best-bid/ask
  • Maker fees, taker fees, rebates
  • Code: connect WS and process price-change events
  • Reconnect and gap-handling

CLOB v1 vs v2 (use v2)

Polymarket підтримує два покоління SDK. v1 (@polymarket/clob-client на npm, py-clob-client <0.30) застарілий і не має кількох типів orders, доданих у 2024 році. v2 (@polymarket/clob-client-v2 v1.0.6 у Node, py-clob-client 0.34.6+ у Python) - поточний стандарт.

Три конкретні відмінності. v2 підтримує прапорець negRisk для markets із кількома outcome - це потрібно з моменту запуску NegRisk exchange наприкінці 2024 року. v2 постачається з TypeScript types для формату повідомлень WebSocket; v1 повертає any. v2 нативно обробляє signature flow Gnosis Safe від серпня 2025 року; v1 потребує custom signing glue.

Уся решта цього розділу написана з припущенням, що всюди використовується v2. Якщо ви бачите код v1 в старішому tutorial, вважайте його зламаним, доки не доведено протилежне - особливо placement orders у NegRisk markets під v1 може мовчки піти до неправильного exchange contract.

Order book REST snapshot

REST snapshot endpoint повертає повний book для одного token у конкретний момент часу.

GET https://clob.polymarket.com/book?token_id=<ERC1155_TOKEN_ID>

Форма відповіді:

{
  "market": "0x...",
  "asset_id": "5413...",
  "timestamp": "1715600000000",
  "hash": "0x...",
  "bids": [{"price":"0.45","size":"120"}, {"price":"0.44","size":"380"}, ...],
  "asks": [{"price":"0.47","size":"85"}, {"price":"0.48","size":"210"}, ...]
}

Ціни подаються як strings із 2-3 знаками після коми; sizes - як strings, що представляють кількість shares (не долари). Bids відсортовані від вищої до нижчої ціни, asks - від нижчої до вищої. hash - це marker дедуплікації: повторні запити до незмінного book повертають той самий hash, і ваш bot може пропустити обробку.

REST snapshot - правильний вибір для разових перевірок (price check під час ухвалення рішення про вхід). Для безперервного моніторингу використовуйте канал WebSocket нижче.

WebSocket subscriptions: market and user channels

Мають значення два канали WebSocket.

Market channel: wss://ws-subscriptions-clob.polymarket.com/ws/market. Підписуйтеся на один або багато tokens; отримуйте order-book updates у міру їх появи.

{"type":"Market","markets":["0xCondId1","0xCondId2"]}

Повідомлення приходять при кожній зміні. Типи включають book (повний snapshot), price_change (delta), tick_size_change (рідко) і last_trade_price (останнє виконання).

User channel: wss://ws-subscriptions-clob.polymarket.com/ws/user. Authenticated; отримуйте події власних orders - fills, partial fills, cancellations.

{"type":"User","auth":{"apiKey":"...","secret":"...","passphrase":"..."}}

User channel - найчистіший спосіб виявити fill. Polling endpoint REST для orders коштує дорожче і може пропускати зміни стану між запитами; WebSocket надсилає подію в момент, коли matcher її підтверджує.

Parsing bids/asks/depth

Order book - це список цінових рівнів із агрегованим обсягом. Є дві конвенції parsing, які важливо зробити правильно.

Напрямок order: bids - це buy orders (хтось хоче КУПИТИ за цією ціною). Коли ВАШ bot продає, ви б’єте bid. Коли ваш bot купує, ви піднімаєте ask. Polymarket UI показує той самий напрямок; на деяких інших exchanges він інвертований.

Сортування: bids приходять відсортованими за спаданням (найкращий bid першим). asks приходять відсортованими за зростанням (найкращий ask першим). Найкращий bid - це bids[0]; найкращий ask - asks[0]. Увага: public WebSocket іноді надсилає partial book updates, які не відсортовані заздалегідь - завжди перестраховуйтеся й повторно сортуйте після будь-якого merge.

Depth на рівні - це грошовий обсяг, який можна виконати: price * size. Depth на перших 5 рівнях - поширений metric ліквідності: sum(b.price * b.size for b in bids[:5]). Якщо depth на top-5 менший за $100, book є неліквідним, і більшість припущень strategy ламаються.

Computing mid-price and best-bid/ask

Три похідні цінові точки, які потрібні вашому bot.

  • Best bid / best ask: bids[0].price і asks[0].price. Ціни, за якими ви реально можете торгувати, одна share.
  • Mid-price: (best_bid + best_ask) / 2. Математичний центр spread. Корисний для valuation; ви ніколи не торгуєте по mid.
  • VWAP price for size N: проходьте book, доки cumulative size не досягне N, і повертайте size-weighted average price. Реальна вартість КУПІВЛІ N shares прямо зараз з урахуванням sweep у глибші рівні.

Крайній випадок: порожня сторона bid або ask (немає тих, хто продає, або немає тих, хто купує) означає, що book односторонній. У структурі markets Polymarket це трапляється для resolved або майже resolved markets, де одна сторона стоїть на 0.999, а ніхто не пропонує ліквідність на стороні, що програла. Сприймайте best-bid = 0 або best-ask = 1 як сигнал «не торгувати».

Maker fees, taker fees, rebates

Більшу частину своєї історії Polymarket узагалі не брав trading fees. У 2026 році це змінилося: fees запровадили на початку року на 15-хвилинних crypto markets, 30 березня 2026 поширили на Sports, а потім викотили на більшість категорій. Будь-який туторіал, що досі стверджує, ніби Polymarket без fees, застарів - і той, хто проґавить це у високочастотній strategy, буде тихо з'їдений. Ось як модель працює насправді, станом на середину 2026 року.

Спершу про дві сторони кожної угоди. Maker - це той, хто кладе в book спокійний limit order, що лишається чекати; taker - це той, хто надсилає order, який виконується одразу проти вже наявної ліквідності. Makers і далі сплачують нуль fee та ще й отримують rebate; fee сплачують лише takers.

Taker fee - це не фіксований відсоток. Вона йде за кривою, що залежить і від розміру order, і від ціни:

fee = shares × feeRate × price × (1 - price)

Член price × (1 - price) максимальний за ціни 0.50 (справжній ринок «орел чи решка») і зменшується до 0 або 1. Інакше кажучи, на найбільш невизначених markets ви платите найвищу fee, а на майже вирішених - майже нічого. feeRate задається за категоріями:

  • Crypto: feeRate 0.07 (найвища, пік близько 1.8% ефективних), maker rebate 20%.
  • Sports: feeRate 0.03 (пік близько 0.75%), maker rebate 25%.
  • Finance, Politics, Tech, Mentions: feeRate 0.04, maker rebate 25%.
  • Economics, Culture, Weather, загальне: feeRate 0.05, maker rebate 25%.
  • Geopolitics та великі світові події: 0, і далі без fee.

Приклад розрахунку. Припустимо, ваш bot бере 100 shares crypto market за ціною 0.50. Fee становитиме 100 × 0.07 × 0.50 × (1 - 0.50) = 100 × 0.07 × 0.25 = $1.75. Якщо ж ви візьмете ті самі 100 shares за 0.90, fee впаде до 100 × 0.07 × 0.90 × 0.10 = $0.63, бо ціна далеко від невизначеної середини. Для bot висновок однозначний: брати ліквідність на волатильних, майже збалансованих crypto та sports markets коштує максимуму fee - отже саме там найвигідніше котируватися як maker і забирати rebate, а не платити fee.

Окрім явної fee, ви щоразу платите bid-ask spread, коли його перетинаєте. Spread - це розрив між найкращою ціною купівлі та найкращою ціною продажу, і для strategy, що входить і виходить як taker, цей розрив - реальна вартість поверх fee. Припускайте 1-3 центи round-trip на типових books, більше - на неліквідних. NegRisk markets (multi-outcome exchange) використовують ту саму модель fee, але сетляться на окремому contract, тож їхні rewards нараховуються окремо. Розділ 19 розглядає liquidity-rewards farming, де забір maker rebates - це сама strategy, а не лише побічний ефект.

Code: connect WS and process price-change events

Мінімальний Node приклад: підключитися, підписатися, логувати кожну подію price-change для одного token.

import WebSocket from "ws";
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
ws.on("open", () => {
  ws.send(JSON.stringify({ type: "Market", markets: ["<CONDITION_ID>"] }));
});
ws.on("message", (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.event_type === "price_change") {
    console.log("price_change", msg.asset_id, msg.changes);
  } else if (msg.event_type === "book") {
    console.log("book snapshot", msg.bids?.[0], msg.asks?.[0]);
  }
});
ws.on("close", () => console.log("closed"));
ws.on("error", (e) => console.error("err", e.message));

Комфортно підписуватися на приблизно до 30 tokens на одне WebSocket connection. Понад це краще розподіляти навантаження на кілька connections - сервер іноді тихо відкидає великі subscriptions без помилки, що призводить до мовчазно застарілих reads book.

Reconnect and gap-handling

Long-running WebSocket connection обов’язково обірветься. Cloudflare циклічно перезапускає connections кожні кілька годин; мережі «мигають»; Polymarket іноді розгортає оновлення. Плануйте це заздалегідь.

Стратегія reconnect: при close або error зачекайте min(2^attempt, 30) секунд із jitter, а потім повторно підпишіться. Скидайте лічильник attempt після першого успішного повідомлення після reconnect.

Gap-handling важливіший за швидкість reconnect. Поки WebSocket був від’єднаний, book рухався. Після кожного reconnect повторно отримуйте REST snapshot для кожного підписаного token і звіряйте: будь-які open positions, чий book суттєво зрушив, потребують повторної перевірки стану, exits можуть вимагати спрацювання, alarms можуть бути застарілими. Сценарій «я пропустив 30 секунд book updates» - це тихий убивця long-running bots: вони продовжують працювати на застарілому стані й виставляють orders за цінами, яких уже не існує.

Defensive pattern: робіть snapshot кожного підписаного book раз на хвилину незалежно від стану WebSocket і розглядайте WS як fast-path optimization поверх polling snapshot.

Часті запитання

Який endpoint Polymarket CLOB API?
Базовий CLOB endpoint - https://clob.polymarket.com (REST) і wss://ws-subscriptions-clob.polymarket.com/ws/market (WebSocket). Це V2 endpoints, які використовують @polymarket/clob-client-v2 і py-clob-client.
Чи потрібен мені API key, щоб читати order book?
Ні. Reads order book (snapshots і WebSocket subscriptions) є public і не потребують authentication. API key потрібен лише для розміщення/скасування orders і читання account-specific data (positions, fills).
Наскільки швидко CLOB WebSocket надсилає price updates?
Так швидко, як відбувається match orders. На активних markets updates приходять кожні кілька сотень мілісекунд; на тонких markets - лише під час реальних orders. І зміни depth, і trade events проходять через той самий канал WS - аналізуйте event type, щоб обробляти кожен правильно.
Як обчислити mid-price order book Polymarket?
mid = (best_bid + best_ask) / 2, якщо обидва існують; інакше використовуйте last_trade_price як fallback. Будьте обережні з тонкими books, де best_bid далеко нижчий за best_ask - тоді mid може бути беззмістовним. Завжди також враховуйте spread, перш ніж вважати mid справедливою ціною.
Яка maker fee на Polymarket у 2026 році?
Makers платять 0% і отримують rebate (20% на crypto, 25% на більшості інших категорій). Fee платять лише takers, і вона не фіксована: йде за fee = shares × feeRate × price × (1 - price), тож максимальна на ринках «орел чи решка» близько 0.50 і зменшується до країв. feeRates за категоріями ідуть від 0.03 (Sports, близько 0.75% ефективного піку) до 0.07 (Crypto, близько 1.8% ефективного піку), а Geopolitics і далі без fee. Саме ця maker-taker асиметрія пояснює, чому активні bots майже завжди котируються спокійними limit orders, а не перетинають spread через market orders.
Як обробляти WebSocket disconnects?
Підключайтеся з exponential backoff (1s, 2s, 4s, max 30s), повторно підписуйтеся на ті самі markets і знову отримуйте REST snapshot, щоб заповнити будь-який gap. Ніколи не довіряйте застарілому order book - якщо ви були відключені більше ніж 5 секунд, запросіть свіжий snapshot перед розміщенням orders.