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 для самых используемых категорий:

TagIDTagID
Sports1NBA745
Crypto21NFL450
Politics2Tennis864
Bitcoin100196Esports702
Ethereum100383Soccer1059
Election3EPL739
Middle East1432UCL2186

Фильтруйте по 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.

Часто задаваемые вопросы

Что такое Polymarket Gamma API?
Gamma - это metadata и discovery API Polymarket. Он обслуживает списки event/market, titles, descriptions, end dates, tags и aggregate volume. Он НЕ обслуживает real-time order book data - это находится в CLOB API. Для большинства use cases discovery и analytics вы начинаете с Gamma.
В чем разница между event и market на Polymarket?
Event объединяет один или несколько markets, которые связаны общей темой вопроса. Market - это конкретный Yes/No outcome со своим order book и token IDs. Event "2026 NBA Champion" содержит 30 markets (по одному на каждую команду). Для binary Yes/No events у event есть 1 underlying market.
Как найти Polymarket tag IDs?
Tags доступны через endpoint gamma /tags. Проверенные IDs, которые мы используем в production: 864 Tennis, 745 NBA. Tag slugs в URL (?tag_slug=tennis) и free-text query (?q=tennis) ненадежны - используйте только numerical tag_id. Проверьте /tags, прежде чем полагаться на slug.
Как отсортировать Polymarket events по 24h volume?
/events?order=volume24hr&ascending=false - это то, что лежит в основе большинства виджетов "trending markets". Комбинируйте с active=true&closed=false, чтобы исключить expired или paused markets. Limit по умолчанию 25; максимум 500 на один вызов.
Есть ли лимиты pagination в Gamma?
Да. Endpoints /events и /markets принимают limit (максимум 500 на один вызов) и offset для pagination. Большинство libraries не paginate автоматически - если вам нужен полный universe, циклически увеличивайте offset, пока не получите page с количеством результатов меньше `limit`.
Поддерживает ли Gamma WebSocket?
Нет. Gamma - только REST. Для real-time updates (changes price, new markets, order book) используйте CLOB WebSocket - это будет рассмотрено в главе 8 этой серии.