Ключевые выводыТри хоста — три задачи: gamma-api для метаданных рынков и событий, clob для стаканов, цен и торговли, data-api для всего, что привязано к адресу кошелька.
- Три хоста — три задачи:
gamma-apiдля метаданных рынков и событий,clobдля стаканов, цен и торговли,data-apiдля всего, что привязано к адресу кошелька. - В объектах рынка Gamma поля
outcomes,outcomePricesиclobTokenIdsимеют тип string и приходят в JSON-кодировке — декодируйте до обращения по индексу, иначе будете сравнивать символы. - Конвейер держится на ключах связи:
conditionIdсвязывает Gamma с Data API, а декодированныеclobTokenIds— этоtoken_idв CLOB иassetв Data API. - Запрашивайте события, а не рынки, где это возможно: событие несёт свои рынки внутри и вдвое сокращает число походов.
- Большие обходы листайте через
/markets/keysetи/events/keyset: курсорная пагинация,limitмаксимум 100,offsetотклоняется с кодом 422, а на последней страницеnext_cursorотсутствует; offset-эндпоинты пока работают, но постепенно выводятся из обращения. - В стакане CLOB
bidsотсортированы по цене по убыванию, аasks— по возрастанию, поэтому лучшая котировка с каждой стороны лежит по индексу0. - Бюджеты раздельные и считаются по IP: Gamma — 4 000 запросов/10 с, CLOB — 9 000, Data API — 1 000 (у
/positions— 150) под общим потолком 15 000, поэтому обогащение метаданными не конкурирует с опросом позиций. - Учётные данные нужны только для торговли и собственного журнала: подпись L1 для получения API-ключа, затем HMAC-заголовки L2, с типом подписи и адресом фандера под тип аккаунта.
Краткое содержание подготовлено с помощью ИИ.
Что покрывает Gamma
Базовый адрес Gamma API — https://gamma-api.polymarket.com, и его задача — каталог: всё, что нужно фронтенду, чтобы показать рынок ещё до того, как кто-либо начнёт торговать. В спецификации OpenAPI маршруты помечены как публичные, поэтому ни ключа, ни кошелька, ни подписи здесь не требуется.
Основной трафик несут два эндпоинта. Эндпоинт рынков Gamma API, GET /markets, отдаёт список рынков с фильтрами почти под любую задачу поиска: slug, condition_ids, clob_token_ids, id и question_ids для прямых запросов; tag_id вместе с related_tags для просмотра по категориям; liquidity_num_min/max и volume_num_min/max для порогов по размеру; start_date_min/max и end_date_min/max для временных окон; плюс limit, offset, order (список полей через запятую) и ascending для пагинации и сортировки. Параметр closed по умолчанию равен false, так что разрешившиеся рынки уже исключены, пока вы не попросите обратного.
Эндпоинт событий Gamma API, GET /events, на практике стоит брать первым. Событие — это контейнер («решение ФРС в октябре»), и приходит оно с вложенным массивом markets, поэтому один вызов события заменяет вызов рынков плюс цикл. Собственное руководство Polymarket советует то же самое: идти от событий, чтобы сократить число вызовов. Для прямого поиска по ссылке есть GET /events/slug/{slug} — слаг берётся прямо из URL Polymarket.
Одну ловушку на уровне полей стоит назвать до того, как вы напишете парсер, потому что она сидит в схеме, а не в тексте документации. В объекте рынка outcomes, outcomePrices и clobTokenIds имеют тип string, а не массив: они приходят в JSON-кодировке, поэтому market["outcomePrices"][0] вернёт символ [, а не цену. Сначала декодируйте. Всё остальное в объекте — то, чего ждёшь от каталога: conditionId, question, slug, bestBid, bestAsk, lastTradePrice, spread, volumeNum, liquidityNum, volume24hr, поля изменения цены по горизонтам, плюс операционные флаги вроде enableOrderBook, acceptingOrders, orderPriceMinTickSize и orderMinSize.
Что покрывает CLOB
Базовый адрес CLOB API — https://clob.polymarket.com, и это торговая поверхность: живой стакан плюс всё, что вы с ним делаете. Рыночные данные здесь читаются свободно и без учётных данных: /book и /books для стаканов, /price и /prices для цены одной стороны, /midpoint и /midpoints, /prices-history для ценового ряда и отдельный запрос шага цены по рынку.
Обратите внимание на формы множественного числа. Батч-варианты существуют ровно затем, чтобы вы не ходили циклом: /books и /prices принимают набор токенов одним запросом. Их квота по числу запросов ниже — 500 за 10 секунд против 1 500 у одиночных версий, — но каждый запрос покрывает много токенов, поэтому для любой многотокенной задачи они сокращают именно количество запросов, а не наоборот. Насколько именно — зависит от того, сколько токенов вы упаковываете в вызов.
Эндпоинты CLOB API для состояния аккаунта и торговли закрыты аутентификацией CLOB API, устроенной в два уровня. L1 — подпись вашим приватным ключом (EIP-712), которая один раз создаёт или выводит API-ключ. L2 — сам ключ, отправляемый HMAC-заголовками в последующих запросах. Сработает это или нет, решают две детали аккаунта: тип подписи, соответствующий тому, как аккаунт создавался (обычный EOA либо типы POLY_PROXY, GNOSIS_SAFE, POLY_1271), и адрес фандера, который фактически держит деньги — для аккаунта на EOA это сам EOA. Аутентифицированные маршруты дальше покрывают выставление и отмену ордеров плюс ваш собственный журнал через /data/orders и /data/trades — именно ваши ордера и сделки, а не произвольного кошелька.
Две детали лимитов важны здесь сильнее, чем где-либо ещё. У эндпоинтов API-ключей свой жёсткий лимит — 100 запросов за 10 секунд, а ордера и отмены управляются и IP-лимитами Cloudflare, и отдельными токен-бакетами на подписанта: то есть один аккаунт не сможет пробить потолок, распределившись по адресам, и пытаться не стоит.
Что покрывает Data API
Data API на https://data-api.polymarket.com отвечает на вопросы, ключом которых служит адрес. /positions и /closed-positions — для holdings, /activity — для хронологической ончейн-ленты, /trades — для исполнений, /value — для итога по портфелю, /holders — для крупнейших держателей конкретного рынка, плюс поверхности лидербордов.
Стоит сказать прямо, потому что это частый поисковый запрос: эндпоинта рынков у Data API нет — в смысле каталога рынков. Метаданные рынков живут в Gamma, а рыночная по форме поверхность Data API — это /holders плюс фильтры market и eventId на эндпоинтах, привязанных к адресу. Если вы ищете вопрос рынка, его слаг или ID токенов, вы не на том хосте; если ищете, кто им владеет, — на том.
Как выбрать API под задачу
Решение сводится к одному вопросу: что у вас есть в качестве ключа? Каждый API индексирован своим идентификатором, и понимание того, как пользоваться Gamma API, по большей части сводится к умению переводить между ними.
| У вас есть | Нужно | Хост | Эндпоинт |
|---|---|---|---|
| Ссылка Polymarket | Метаданные рынка | Gamma | /events/slug/{slug} |
conditionId |
Вопрос рынка, даты, флаги | Gamma | /markets?condition_ids=... |
| ID токена | Живой стакан или цена | CLOB | /book, /price |
| Адрес кошелька | Позиции, активность, сделки | Data | /positions, /activity, /trades |
| Рынок | Его крупнейшие держатели | Data | /holders |
Практическое ядро — ключи связи. conditionId связывает Gamma с Data API: он присутствует и в объекте рынка, и в объекте позиции. clobTokenIds в рынке Gamma после декодирования даёт два ID токенов исходов — это и есть token_id в терминах CLOB и asset в позиции из Data API. Отсюда каноничный конвейер: находим в Gamma, оцениваем в CLOB, атрибутируем в Data — перенося conditionId и ID токенов по цепочке.
В пользу такого разделения есть и бюджетный аргумент. У трёх хостов раздельные квоты: Gamma — 4 000 запросов за 10 секунд, CLOB — 9 000, Data API — 1 000, под общим потолком в 15 000. Документация Polymarket говорит, что Cloudflare задерживает лишние запросы и ставит их в очередь, но в нашем тесте августа 2026 года ответы 429 приходили сразу, без плавного замедления. Поскольку бюджеты раздельные, обогащение позиций метаданными рынка не расходует квоту, которая нужна опросу позиций. Самый узкий из трёх — Data API, и проектировать стоит вокруг него: /positions разрешает 150 запросов за 10 секунд, /trades — 200.
Внутри этих бюджетов вас удерживают параметры эндпоинта рынков Gamma API. Фильтрация на стороне сервера через tag_id, границы дат и пороги объёма лучше, чем выкачать широко и отфильтровать у себя, а запрос событий вместо рынков схлопывает два похода в один. И кешируйте по ходу дела: вопрос рынка, его слаг и ID токенов не меняются, поэтому им место в локальном хранилище, а не в цикле опроса.
Для обходов больших выборок новый код должен листать курсорами, а не смещениями. Polymarket добавила /markets/keyset и /events/keyset как курсорную замену offset-эндпоинтам: вы читаете next_cursor из каждого ответа и передаёте его обратно в after_cursor, при limit не выше 100 и значении по умолчанию 20. Контракт здесь строг, и это удобно: offset на этих маршрутах явно отклоняется с кодом 422, а next_cursor присутствует, только пока остаются страницы, — то есть его отсутствие и есть условие остановки, а не догадка. Offset-эндпоинты пока работают, но идут к отказу от поддержки; всё, что строится сейчас, стоит строить на keyset.
Как вызывать их из Python
Вот весь конвейер в одном примере на Python для CLOB API — от слага из ссылки до живого стакана; учётные данные нигде не нужны, так как все чтения ниже публичны.
import json, requests
GAMMA = "https://gamma-api.polymarket.com"
CLOB = "https://clob.polymarket.com"
DATA = "https://data-api.polymarket.com"
HEAD = {"User-Agent": "market-tracker/1.0"}
def event_by_slug(slug): # 1. поиск: один вызов, рынки вложены внутрь
r = requests.get(f"{GAMMA}/events/slug/{slug}", headers=HEAD, timeout=15)
r.raise_for_status()
return r.json()
def book(token_id): # 2. цена: ключ CLOB — токен, а не рынок
r = requests.get(f"{CLOB}/book", params={"token_id": token_id}, headers=HEAD, timeout=15)
r.raise_for_status()
return r.json()
def holders(condition_id): # 3. атрибуция: ключ Data — адрес или рынок
r = requests.get(f"{DATA}/holders", params={"market": condition_id}, headers=HEAD, timeout=15)
r.raise_for_status()
return r.json()
event = event_by_slug("fed-decision-in-october") # подставьте любой живой слаг
for market in event.get("markets", []):
outcomes = json.loads(market["outcomes"]) # это JSON-строки, а не массивы
token_ids = json.loads(market["clobTokenIds"])
prices = json.loads(market["outcomePrices"])
print(market["question"], "|", market["conditionId"])
for name, token, cached in zip(outcomes, token_ids, prices):
b = book(token)
# bids отсортированы по цене ПО УБЫВАНИЮ, asks — по возрастанию: лучшая котировка — индекс 0
best_bid = b["bids"][0]["price"] if b.get("bids") else None
best_ask = b["asks"][0]["price"] if b.get("asks") else None
print(f" {name:<6} gamma={cached:<8} bid={best_bid} ask={best_ask}")
top = holders(market["conditionId"]) # третий хост: ключом служит тот же conditionId
print(f" держателей получено: {len(top)}")
На что смотреть — и чего пример намеренно не делает. Три вызова json.loads и есть смысл примера: пропустите их, и все дальнейшие сравнения будут молча работать с символами. Вторая ловушка — порядок в стакане: схема документирует bids как отсортированные по цене по убыванию, а asks — по возрастанию, поэтому лучшая котировка с каждой стороны лежит по индексу 0. Потянувшись за [-1], вы получите худшую стоящую заявку в стакане — в логе это выглядит достаточно правдоподобно, чтобы пережить ревью. Заголовок User-Agent выставлен потому, что запросы без узнаваемого агента, по сообщениям разработчиков, чаще упираются в Cloudflare. Цены из Gamma — каталожные значения и могут отставать от стакана, поэтому цикл печатает обе рядом: число Gamma годится для страницы со списком, число CLOB — для всего, на чём вы собираетесь торговать. В примере нет политики ретраев, нет батчинга (/books заменил бы цикл по токенам в реальном трекере), нет вебсокета для живых обновлений и нет пагинации.
И последнее операционное замечание, которое стоит людям вечера: Gamma и документация не полностью согласуются по фильтрам. Руководство Polymarket советует active=true&closed=false для живых рынков, тогда как текущая карточка OpenAPI для /markets перечисляет среди документированных параметров closed (со значением false по умолчанию), но не active. Отправляйте то, что документировано в карточке, остальное проверяйте по живым ответам и не считайте, что фильтр работает, раз его использовал туториал.