Polymarket Bot Tutorial · Capítulo 7 de 32
Análise aprofundada da Gamma API da Polymarket: endpoints /events e /markets, paginação, tag IDs (864 Tennis, 745 NBA, etc), filtro por volume de 24h, rate limits, e exemplos de código em Python e Node.
O que este capítulo cobre
Gamma é a API de catálogo da Polymarket - ela lista cada event, cada market, tag, imagem e resultado resolvido que o front-end exibe. A CLOB API negocia; a Gamma descreve o que está disponível para trade. A maioria dos bugs de bot na camada de descoberta vem de confundir as duas, ou de ignorar o contrato de paginação. Este capítulo é a referência de campo para os principais endpoints da Gamma, com o comportamento exato dos parâmetros de que nossos fetchers de produção dependem.
- Gamma vs CLOB: quando usar cada um
- Anatomia do endpoint /events
- Anatomia do endpoint /markets
- Tags e tag IDs (lista verificada)
- Filtros: active, closed, ordenação por volume24hr
- Paginação e limites
- Rate limits e caching
- Código: buscar os mercados com maior volume em 24h
Gamma vs CLOB: quando usar cada um
Dois serviços diferentes para trabalhos diferentes.
Gamma (gamma-api.polymarket.com): catálogo. Lista events, markets, tags, descrições, imagens, resultados resolvidos, volume de 24 horas, volume total, datas de encerramento. Somente HTTP de leitura. Não exige autenticação para a maioria das consultas. É atualizada continuamente, mas de forma eventualmente consistente - um market que acabou de fechar pode ainda mostrar closed: false por alguns segundos.
CLOB (clob.polymarket.com): trading + order book. Lista melhor bid/ask atual, profundidade do book top-N, trades recentes. Autenticado para endpoints de escrita (envio e cancelamento de ordens). Canais WebSocket em tempo real disponíveis para atualizações do book.
Regra prática: use Gamma para encontrar o que operar; use CLOB para operar de fato. Um bot que lê preços da Gamma está usando dados defasados - os campos de preço da Gamma atualizam com menos frequência que o order book da CLOB. Um bot que lê metadados de market na CLOB está fazendo mais requests do que o necessário.
Anatomia do endpoint /events
GET /events retorna dados no nível de event. Um "event" é uma página da Polymarket; um único event pode conter vários markets (por exemplo, o event da Eleição Presidencial de 2024 tem um market por candidato).
Campos principais:
slug: identificador seguro para URL, estável durante a vida do event.title,description: exibição para humanos.endDate(ISO 8601): quando o event é encerrado.active,closed: booleanos; combine em uma query com?active=true&closed=falsepara events ao vivo.volume,volume24hr: totais em USD.tags: array de objetos tag (veja a seção de tags abaixo).markets: array de objetos market filhos (veja a anatomia de/markets).
O padrão de descoberta mais comum: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Retorna os 100 events ao vivo com maior volume.
Anatomia do endpoint /markets
GET /markets retorna dados no nível de market. Um market é um contrato Y/N ou de múltiplos resultados; ele fica dentro de um event.
Campos principais:
slug: identificador seguro para URL.question: o título exibido na página de trading (por exemplo, "Will Trump be president on January 1, 2027?").outcomes: string JSON com nomes dos resultados, por exemplo'["Yes","No"]'. Sempre dois elementos para binary; mais para NegRisk.outcomePrices: string JSON com os preços atuais como decimais, por exemplo'["0.62","0.38"]'. Os dois lados somam aproximadamente 1,0 menos o spread.clobTokenIds: string JSON com os token IDs ERC-1155 alinhados aos outcomes. Estes são os tokens que você realmente compra/vende.negRisk: booleano;truepara markets de múltiplos outcomes cuja soma é 1. Importa para o envio de ordens (capítulo 11).
Os campos outcomes / outcomePrices / clobTokenIds chegam como strings JSON, não como arrays já parseados - faça JSON-decode antes de usar.
Tags e tag IDs (lista verificada)
Tags são rótulos categóricos (Sports, Crypto, Tennis, NBA, etc.). Os tag IDs de produção verificados para as categorias mais usadas:
| 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 |
Filtre por tag com ?tag_id=745 para uma tag específica, ou ?tag_slug=nba usando o slug. O filtro por slug é mais legível no código, mas um pouco mais lento; por ID é o padrão de produção.
Filtros: active, closed, ordenação por volume24hr
As quatro dimensões de filtro que você usará em 95% das vezes.
active=true|false:trueexclui markets que a equipe da Polymarket ocultou da UI.closed=true|false:falseexclui markets resolvidos. A combinaçãoactive=true&closed=falseé o filtro ao vivo mais comum.order=volume24hr,order=volume,order=endDate: chave de ordenação. O mais útil évolume24hrpara encontrar markets atualmente ativos.ascending=true|false: o padrão na maioria dos endpoints é true; quase sempre você vai quererfalsepara ordenações por volume.
Aviso: filtrar por tag_id combinado com order=volume24hr e ascending=false às vezes retorna uma página vazia quando a tag tem pouquíssimos markets ao vivo. Sempre faça over-fetch (peça mais do que vai exibir) e aplique pós-filtro para lidar com isso.
Paginação e limites
O parâmetro limit aceita de 1 a 500 por chamada. O padrão é 100 se não for especificado. Acima de 500 o servidor limita silenciosamente - você recebe 500, mas a resposta não indica que há mais.
A paginação é baseada em offset: ?limit=500&offset=500 para a segunda página. Não há paginação baseada em cursor, então inserções concorrentes podem deslocar os limites da página entre chamadas. Para a maioria dos casos de descoberta de bot isso é aceitável; para scrapes de arquivo, ordene por um campo estável (endDate ou createdAt) e detecte sobreposição por slug.
Padrão prático para "todos os markets ao vivo": busque limit=500&order=volume24hr&ascending=false. Isso cobre os 500 principais por volume, que na prática é quase todo market com atividade relevante. Ir além da página 1 raramente é útil - markets na cauda da distribuição de volume, por definição, não são onde a ação está.
Rate limits e caching
A Gamma é protegida pela Cloudflare e tem rate limits suaves por IP. Limiares empíricos observados sob carga de produção:
- Até cerca de 30 req/sec de um único IP de forma sustentada: ok.
- Rajadas de 100+ req/sec: ocasionalmente 429s, retries funcionam.
- Cerca de 500 req/sec sustentados: página de rate limit ou bloqueio temporário (10-60s).
Os response headers publicados incluem valores de Cache-Control de 30-60 segundos para a maioria dos endpoints. Respeite-os - não há benefício em refazer o fetch do mesmo event 10 vezes por minuto. Padrão de caching em produção: LRU em processo + TTL, chaveado pela URL completa, TTL de 30s. Economiza requests e reduz latência.
Para estratégias de alta frequência, replique os dados da Gamma para um armazenamento local atualizado por um único processo fetcher; deixe múltiplos consumidores lerem desse storage. Um fetcher × muitos consumidores > muitos fetchers × Gamma.
Código: buscar os markets com maior volume em 24h
Fetcher de referência em três linguagens, retornando os 50 markets ao vivo com maior volume em 24 horas.
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'
O endpoint /events da Polymarket Gamma NÃO suporta um parâmetro de busca em texto livre - adicionar ?q=foo ou ?search=foo retorna silenciosamente a ordenação padrão. Filtre por slug ou tag em vez disso.












