Polymarket Bot Tutorial · Chapter 7 of 32
Глубокий разбор Polymarket Gamma API: endpoints /events и /markets, pagination, tag IDs (864 Tennis, 745 NBA и т. д.), фильтрация по 24h volume, rate limits, а также примеры кода на Python и Node.
Что охватывает эта глава
Gamma - это catalog API Polymarket: он перечисляет каждое event, каждый market, tag, image и resolved outcome, которые отображает front-end. CLOB API торгует; Gamma описывает, чем можно торговать. Большинство багов bot на уровне discovery возникает из-за путаницы между ними или из-за пропуска pagination contract. Эта глава - field reference по основным endpoints Gamma с точным поведением параметров, на которое опираются наши production fetchers.
- Gamma vs CLOB: когда использовать что
- Структура endpoint /events
- Структура endpoint /markets
- Tags и tag IDs (проверенный список)
- Filtering: active, closed, volume24hr ordering
- Pagination и limits
- Rate limits и caching
- Code: fetch top 24h-volume markets
Gamma vs CLOB: когда использовать что
Два разных сервиса для двух разных задач.
Gamma (gamma-api.polymarket.com): catalog. Перечисляет events, markets, tags, descriptions, images, resolved outcomes, 24-hour volume, total volume, end dates. Read-only HTTP. Для большинства reads authentication не требуется. Обновляется непрерывно, но eventually consistent - market, который только что закрылся, еще может показывать closed: false в течение нескольких секунд.
CLOB (clob.polymarket.com): trading + order book. Перечисляет current best bid/ask, top-N book depth, recent trades. Для write endpoints требуется authentication (order placement, cancellation). Доступны real-time WebSocket channels для обновлений book.
Правило простое: используйте Gamma, чтобы найти, чем торговать; используйте CLOB, чтобы торговать этим. Bot, который читает prices из Gamma, использует stale data - fields price в Gamma обновляются реже, чем order book в CLOB. Bot, который читает market metadata из CLOB, делает больше запросов, чем нужно.
Структура endpoint /events
GET /events возвращает данные на уровне event. "Event" - это страница Polymarket; один event может содержать несколько markets (например, event 2024 Presidential Election имеет один market на каждого кандидата).
Ключевые fields:
slug: URL-safe identifier, стабильный на протяжении жизни event.title,description: для отображения человеку.endDate(ISO 8601): когда event закрывается.active,closed: boolean; используйте в query вместе с?active=true&closed=falseдля live events.volume,volume24hr: суммы в USD.tags: array объектов tag (см. раздел tags ниже).markets: array дочерних объектов market (см. структуру/markets).
Самый частый pattern для discovery: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Возвращает 100 currently-live events с самым большим volume.
Структура endpoint /markets
GET /markets возвращает данные на уровне market. Market - это один контракт Y/N или multi-outcome; он находится внутри event.
Ключевые fields:
slug: URL-safe identifier.question: заголовок, отображаемый на trading page (например, "Will Trump be president on January 1, 2027?").outcomes: JSON string с названиями outcomes, например'["Yes","No"]'. Для binary всегда два элемента; для NegRisk - больше.outcomePrices: JSON string с текущими prices в виде decimals, например'["0.62","0.38"]'. Обе стороны в сумме дают примерно 1.0 минус spread.clobTokenIds: JSON string с ERC-1155 token IDs, выровненными по outcomes. Это токены, которые вы фактически покупаете/продаете.negRisk: boolean; true для multi-outcome markets, где сумма равна 1. Важно для order placement (глава 11).
Поля outcomes / outcomePrices / clobTokenIds приходят как JSON strings, а не как распарсенные arrays - выполните JSON-decode перед использованием.
Tags и tag IDs (проверенный список)
Tags - это категориальные labels (Sports, Crypto, Tennis, NBA и т. д.). Проверенные production tag IDs для самых используемых категорий:
| Tag | ID | Tag | ID |
|---|---|---|---|
| Sports | 1 | NBA | 745 |
| Crypto | 21 | NFL | 450 |
| Politics | 2 | Tennis | 864 |
| Bitcoin | 100196 | Esports | 702 |
| Ethereum | 100383 | Soccer | 1059 |
| Election | 3 | EPL | 739 |
| Middle East | 1432 | UCL | 2186 |
Фильтруйте по tag с помощью ?tag_id=745 для конкретного tag или ?tag_slug=nba, используя slug. Фильтрация по slug более читабельна в code, но немного медленнее; фильтрация по ID - production default.
Filtering: active, closed, volume24hr ordering
Четыре измерения filtering, которые вы будете использовать в 95% случаев.
active=true|false:trueисключает markets, которые команда Polymarket скрыла из UI.closed=true|false:falseисключает resolved markets. Комбинацияactive=true&closed=false- самый частый live filter.order=volume24hr,order=volume,order=endDate: key для сортировки. Самый полезный -volume24hrдля поиска currently-active markets.ascending=true|false: по умолчанию true на большинстве endpoints; для volume ordering почти всегда нуженfalse.
Оговорка: filtering по tag_id в сочетании с order=volume24hr и ascending=false иногда возвращает пустую page, если у tag очень мало live markets. Всегда over-fetch (запрашивайте больше, чем отображаете) и затем post-filter, чтобы это учитывать.
Pagination и limits
Параметр limit принимает от 1 до 500 на один вызов. Если не указан, значение по умолчанию - 100. Выше 500 server silently caps запрос - вы получите 500, но response не покажет, что больше данных есть.
Pagination основана на offset: ?limit=500&offset=500 для второй page. Cursor-based pagination нет, поэтому concurrent inserts могут сдвигать границы страниц между вызовами. Для большинства bot discovery это приемлемо; для archive scrapes сортируйте по стабильному field (endDate или createdAt) и обнаруживайте overlap по slug.
Практический pattern для "all live markets": fetch limit=500&order=volume24hr&ascending=false. Это покрывает top 500 по volume, то есть практически все markets с заметной активностью. Выходить за пределы page 1 обычно не нужно - markets в хвосте распределения по volume по определению не там, где происходит основное движение.
Rate limits и caching
Gamma находится за Cloudflare и имеет soft rate limits по IP. Эмпирические thresholds, наблюдаемые под production load:
- До примерно 30 req/sec с одного IP на постоянной основе: нормально.
- Bursts 100+ req/sec: иногда 429, retries проходят.
- Примерно 500 req/sec на постоянной основе: page rate-limit или temporary block (10-60s).
Опубликованные response headers содержат значения Cache-Control 30-60 секунд для большинства endpoints. Соблюдайте их - нет смысла запрашивать один и тот же event 10 раз в минуту. Production caching pattern: in-process LRU + TTL, keyed по full URL, TTL 30s. Это экономит количество requests и снижает latency.
Для high-frequency strategies зеркалируйте данные Gamma в local store, обновляемый одним fetcher process; пусть несколько consumers читают из этого store. Один fetcher × много consumers > много fetchers × Gamma.
Code: fetch top 24h-volume markets
Reference fetcher на трех языках, возвращающий top 50 live markets по 24-hour volume.
Python:
import requests
r = requests.get("https://gamma-api.polymarket.com/events",
params={"active":"true","closed":"false",
"order":"volume24hr","ascending":"false","limit":50},
timeout=10)
for ev in r.json()[:50]:
print(ev["slug"], ev.get("volume24hr"))
Node:
const url = "https://gamma-api.polymarket.com/events?active=true&closed=false" +
"&order=volume24hr&ascending=false&limit=50";
const events = await fetch(url).then(r => r.json());
for (const ev of events) console.log(ev.slug, ev.volume24hr);
Curl:
curl -s "https://gamma-api.polymarket.com/events?active=true&closed=false&order=volume24hr&ascending=false&limit=50" \
| jq '.[].slug'
Endpoint Polymarket gamma /events НЕ поддерживает free-text search parameter - добавление ?q=foo или ?search=foo silently возвращает default ordering. Вместо этого фильтруйте по slug или tag.












