Capítulo 27 de 33

A versão curta

A Polymarket expõe três APIs públicas: CLOB (trading), Gamma (descoberta de mercados) e Data (analítica). O SDK oficial de Python é o py-clob-client 0.34.6. A autenticação usa uma chave de API + assinatura ECDSA, com as ordens assinadas via EIP-712 através de uma carteira proxy na Polygon. Os limites de taxa restringem você a cerca de 60 ordens/minuto por chave. O maior obstáculo para desenvolvedores novatos é o problema de mapeamento entre condition_id → token_id entre o Gamma e o CLOB - resolva-o primeiro e todo o resto se encaixa. Todo mês, ganha-se na Polymarket cerca de 40 milhões $ em recompensas de liquidez e spread capturado por bots, quase inteiramente por usuários da API.

O que você vai aprender: como as três APIs se encaixam, como instalar e configurar o py-clob-client, como se autenticar com a sua carteira proxy, como buscar mercados e order books, como enviar e cancelar ordens, como transmitir atualizações de preço em tempo real via WebSocket, os limites de taxa exatos e como fazer backoff de forma limpa, e uma arquitetura de bot pronta para produção que você pode estender.
Pré-requisitos: uma conta Polymarket com saldo e ao menos uma operação manual concluída, Python 3.8+ (ou Node.js) e familiaridade básica com HTTP, JSON e código assíncrono. Se você ainda não operou manualmente, comece pela Primeira operação antes de montar um bot.
01
Capítulo 1

Parte 1: As três APIs

A Polymarket separa de forma limpa as responsabilidades em três serviços distintos. Usar a API certa para cada tarefa mantém o seu bot rápido, simples e dentro dos limites de taxa.

APIURL basePropósitoExige autenticação
CLOB APIclob.polymarket.comEnviar, cancelar e acompanhar ordens. Ler order books. Consultar posições.Sim (para trading)
Gamma APIgamma-api.polymarket.comNavegar por mercados, buscar metadados, imagens, preços de resultados, volume, vencimento, tags.Não (pública)
Data APIdata-api.polymarket.comOperações históricas, snapshots de posições, analítica de usuários, dados de ranking.Não (pública)

Um loop de bot típico usa o Gamma para encontrar mercados, o CLOB para buscar order books e enviar operações, e o Data para fazer back-test do desempenho da estratégia offline. Pense no Gamma como o "catálogo", no CLOB como a "bolsa" e no Data como o "armazém".

Dica profissional: Gamma e Data não exigem autenticação. Você pode explorá-los com curl ou um navegador agora mesmo - sem conta. É uma ótima forma de prototipar antes mesmo de gerar uma chave de API.
02
Capítulo 2

Parte 2: Autenticação e o modelo de carteira proxy

A Polymarket não assina as operações com a chave privada da sua carteira principal. Em vez disso, usa uma carteira proxy no estilo Gnosis Safe: a sua carteira principal autoriza um proxy, e o proxy executa todas as operações na Polygon. O seu bot de API conversa com esse proxy.

O que você precisa

  • Chave de API - gere em Settings → Developer da Polymarket
  • Chave privada - a chave da sua carteira de trading (NÃO a frase semente da sua MetaMask principal)
  • Endereço funder - o endereço da sua carteira proxy (mostrado em Settings → Wallet)
  • Chain ID - 137 (Polygon mainnet)
  • Tipo de assinatura - 1 (POLY_PROXY, padrão para usuários de varejo)
Regras de segurança inegociáveis: nunca suba a sua chave privada para o git. Use variáveis de ambiente (.env) ou um gerenciador de segredos. Nunca cole chaves no Discord, em issues do GitHub ou no ChatGPT. Suponha que qualquer chave que toque a sua área de transferência já está comprometida. Rotacione as chaves em caso de dúvida.
03
Capítulo 3

Parte 3: Instalar o py-clob-client

O SDK oficial de Python é a forma mais rápida de ir do zero à sua primeira ordem. Usaremos a versão 0.34.6, que é a atual em abril de 2026.

# Create a virtual environment first
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows

# Install the SDK
pip install py-clob-client==0.34.6 requests websocket-client python-dotenv

Configuração básica do cliente

import os
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON

load_dotenv()

client = ClobClient(
 host="https://clob.polymarket.com",
 key=os.environ["POLY_PRIVATE_KEY"],
 chain_id=POLYGON, # 137
 signature_type=1, # POLY_PROXY
 funder=os.environ["POLY_FUNDER"],
)

# One-time: derive and cache API credentials
client.set_api_creds(client.create_or_derive_api_creds())

A chamada a create_or_derive_api_creds() assina uma mensagem com a sua chave privada e a troca por uma chave de API, um secret e uma passphrase. Coloque-os em cache no seu .env após a primeira execução para não chamar o endpoint de derivação a cada inicialização.

Exemplo prático - .env mínimo:
POLY_PRIVATE_KEY=0xabc...
POLY_FUNDER=0xdef...
POLY_API_KEY=...
POLY_SECRET=...
POLY_PASSPHRASE=...
04
Capítulo 4

Parte 4: Descobrir mercados via Gamma

Antes de poder operar, você precisa encontrar mercados que valham a pena. O Gamma retorna JSON com tudo o que a interface da Polymarket mostra: pergunta, resultados, preços, volume 24h, vencimento, tags e imagens.

import requests

resp = requests.get(
 "https://gamma-api.polymarket.com/markets",
 params={
 "active": "true",
 "closed": "false",
 "tag_slug": "politics",
 "limit": 20,
 "order": "volume24hr",
 "ascending": "false",
 },
 timeout=10,
)
resp.raise_for_status()
markets = resp.json()

for m in markets:
 print(f"{m['slug']:50} Yes ${float(m['outcomePrices'][0]):.3f} Vol24h ${m.get('volume24hr', 0):,.0f}")

Parâmetros úteis de consulta do Gamma

ParâmetroO que faz
tag_slugFiltra por categoria (politics, sports, crypto, culture, etc.)
active=trueApenas mercados que aceitam operações no momento
closed=falseOculta mercados resolvidos
order=volume24hrOrdena por volume recente (sinal de liquidez)
end_date_minData ISO - ignora mercados que se resolvem cedo demais
limitAté 500 por página (use offset para paginar)
05
Capítulo 5

Parte 5: O mapeamento condition_id → token_id

Este é o ponto de dor número 1 no desenvolvimento de bots da Polymarket. O Gamma retorna um condition_id (um por mercado). As operações do CLOB usam um token_id (um por resultado). Você sempre precisa dos dois.

O erro: passar um condition_id para endpoints do CLOB que esperam um token_id. Você receberá um erro críptico de 'invalid token'. Mapeie sempre primeiro, opere depois.
# Each Gamma market object contains 'clobTokenIds' - a JSON string array
import json

market = markets[0]
token_ids = json.loads(market['clobTokenIds']) # ['7410...', '1120...']
yes_token = token_ids[0] # First outcome
no_token = token_ids[1] # Second outcome

# Alternative: ask CLOB directly using condition_id
info = client.get_market(condition_id=market['conditionId'])
yes_token = info['tokens'][0]['token_id']

A pegadinha da ordem dos resultados

O array outcomes e o array clobTokenIds do Gamma são indexados entre si. Sempre leia o rótulo do resultado em vez de supor que o índice 0 é "Yes". Em mercados de múltiplos resultados (NegRisk, Oscar, eleições), o índice 0 pode ser "Kamala Harris" ou "Taylor Swift" - a ordem é determinística, mas específica de cada mercado.

06
Capítulo 6

Parte 6: Ler order books

book = client.get_order_book(token_id=yes_token)

best_bid = float(book.bids[0].price) if book.bids else None
best_ask = float(book.asks[0].price) if book.asks else None
mid = (best_bid + best_ask) / 2 if best_bid and best_ask else None
spread = best_ask - best_bid if best_bid and best_ask else None

print(f"Bid {best_bid} Ask {best_ask} Mid {mid:.4f} Spread {spread:.4f}")

Os order books são retornados como arrays ordenados (bids decrescentes, asks crescentes). Cada nível tem price e size. Para estimar o slippage de uma ordem maior, percorra o livro e acumule nocional até consumir o seu tamanho alvo.

07
Capítulo 7

Parte 7: Enviar ordens

Ordem limitada (GTC - o padrão)

from py_clob_client.clob_types import OrderArgs, OrderType

args = OrderArgs(
 token_id=yes_token,
 price=0.45,
 size=100, # Shares, not dollars. 100 shares @ $0.45 = $45 max cost.
 side="BUY",
)
signed_order = client.create_order(args)
response = client.post_order(signed_order, OrderType.GTC)
print(response)

A chamada a create_order assina uma mensagem estruturada EIP-712 com a sua chave privada. post_order a envia ao CLOB. Você nunca envia chaves privadas brutas pela rede - apenas ordens assinadas.

Tipos de ordem

TipoCódigoComportamentoQuando usar
Good Till CancelledGTCDescansa no livro até ser executada ou você cancelarPadrão. A maior parte do market making e das estratégias limitadas.
Good Till DateGTDAutocancela em um timestamp especificadoOrientada a eventos: "cancele 5 min antes do anúncio do Fed"
Fill or KillFOKDeve executar todo o tamanho imediatamente ou cancelar por completoPernas de arbitragem onde execuções parciais arruínam a operação
Fill and KillFAKExecuta o que puder no preço limite, cancela o restoTomada agressiva - age como uma ordem a mercado com teto de preço

Cancelar

# Single order
client.cancel(order_id="0xabc...")

# Cancel all orders on a specific market
client.cancel_market_orders(market=market['conditionId'])

# Nuclear option: cancel everything
client.cancel_all()
08
Capítulo 8

Parte 8: Streaming via WebSocket

Consultar o Gamma a cada segundo é desperdício e você atingirá os limites de taxa rápido. O feed de WebSocket transmite atualizações de order book e de operações em tempo real, com latência abaixo de um segundo.

import json, websocket

WS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"

def on_open(ws):
 ws.send(json.dumps({
 "type": "market",
 "assets_ids": [yes_token, no_token],
 }))

def on_message(ws, message):
 event = json.loads(message)
 if event.get("event_type") == "price_change":
 print(f"{event['market']} {event['side']} {event['price']} size={event['size']}")

ws = websocket.WebSocketApp(
 WS_URL,
 on_open=on_open,
 on_message=on_message,
)
ws.run_forever(ping_interval=20)

Existem dois feeds: o feed /market (order book e operações públicos) e o feed /user (os seus próprios eventos de ordem e execução, autenticado). Bots de produção costumam se conectar a ambos, reconectam automaticamente na desconexão e tratam o WebSocket como a fonte da verdade do estado atual do livro.

Heartbeats e reconexões: envie um ping a cada 20 segundos. Se você perder dois pong, reconecte. Na reconexão, busque sempre primeiro o order book via REST, e então reinscreva-se - caso contrário, o seu livro local diverge da realidade.
09
Capítulo 9

Parte 9: Limites de taxa e backoff

Classe de endpointLimiteRajada
Envio de ordens (CLOB)~60 / minuto por chave de API~10 / segundo
Cancelamento de ordens~120 / minuto~20 / segundo
Leituras de dados de mercado (livro CLOB)~300 / minutomaior, varia
Gamma APIGenerosa; respeite os 429-
Mensagens de WebSocketSem limite prático de entrada-

Quando você recebe um HTTP 429, o servidor retorna um cabeçalho Retry-After. Implemente um backoff exponencial com jitter:

import random, time

def post_with_backoff(fn, *args, max_retries=6):
 for attempt in range(max_retries):
 try:
 return fn(*args)
 except Exception as e:
 if "429" in str(e):
 sleep = (2 ** attempt) + random.random()
 time.sleep(min(sleep, 30))
 continue
 raise
 raise RuntimeError("Too many retries")
10
Capítulo 10

Parte 10: Uma arquitetura de bot de referência

Todo bot robusto da Polymarket tem os mesmos seis componentes. Construa cada um como o seu próprio módulo; mantenha-os fracamente acoplados.

ComponenteResponsabilidadeAPIs usadas
ScannerTarefa agendada: puxar mercados que atendam aos seus critérios (tags, volume, dias até o vencimento)Gamma
Motor de preçosManter order books locais em tempo real via WebSocketCLOB WS
Gerador de sinaisFunção pura: estado do livro + metadados → posição alvo- (em memória)
Gerenciador de ordensComparar ordens atuais com o alvo, enviar/cancelar de forma mínimaCLOB REST
Gerenciador de riscoAplicar tetos por mercado, limites de perda diários, disjuntores- (em memória + BD)
Logger e livro-razãoPersistir cada decisão, execução, cancelamento. Alimenta relatórios fiscais e depuração.SQLite / Postgres
Confiabilidade primeiro: antes de otimizar o PnL, garanta que o seu bot consiga reiniciar de forma limpa às 3 da manhã de um domingo sem um humano. Isso significa envio de ordens idempotente (use IDs de ordem do lado do cliente), estado persistente e alertas automáticos (Telegram, Discord, PagerDuty) para qualquer exceção não tratada.

Parte 11: Modos de falha comuns

  • Dados de WebSocket desatualizados - Acompanhe o horário da última mensagem por ativo; se não houver atualizações por >30s em um mercado ativo, force um refresh via REST.
  • Colisões de nonce - O py-clob-client gerencia os nonce das ordens para você, mas se você escrever o seu próprio assinante, incremente o nonce a cada ordem.
  • Saldo insuficiente - Sempre verifique o saldo de pUSD antes de enviar; o livro pode mostrar a sua ordem, mas o casamento a rejeitará.
  • Mercado pausado ou em resolução - Verifique market.active && !market.closed antes de operar. As atualizações do Gamma ficam atrás do CLOB em alguns segundos ao redor da resolução.
  • Desalinhamento do adaptador NegRisk - Mercados de múltiplos resultados passam por um adaptador NegRisk separado. O SDK cuida disso, mas confirme que a sua ordem foi para o venue correto.
Limitação da testnet: a Polymarket não opera uma testnet pública em 2026. "Paper trading" significa enviar ordens reais mínimas (1-5 $) em mercados de baixa liquidez. Reserve alguns dólares para a sua primeira semana de depuração - isso vai te economizar centenas depois.

Parte 12: Recompensas de liquidez via API

A Polymarket roda cerca de 5 milhões $/mês em recompensas de liquidez gerais mais 5 milhões $+/mês em recompensas específicas de esportes (ver Recompensas de liquidez). A grande maioria flui para market makers movidos a API que conseguem manter cotações apertadas de dois lados em milhares de mercados.

A fórmula de recompensa premia ordens próximas do ponto médio, o tamanho e o tempo no livro. Um loop de market making mínimo:

  1. Leia o order book do mercado alvo
  2. Calcule um ponto médio justo (p. ex., VWAP dos 3 níveis superiores de cada lado)
  3. Poste um bid em mid − spread_target/2 e um ask em mid + spread_target/2
  4. A cada atualização do WebSocket, reprecifique se a sua cotação se desviar mais de um tick do alvo
  5. Cancele e saia se o livro afinar ou se surgirem notícias

Parte 13: Ir para produção

  • Hospedagem: um VPS de 6 $/mês (Hetzner, DigitalOcean) na Europa ou US-East basta para a maioria dos bots. Co-localize com um Polygon RPC se precisar de latência abaixo de 10ms.
  • RPC: use Alchemy, Infura ou QuickNode para um Polygon RPC confiável. Os planos gratuitos servem até você enviar centenas de ordens por minuto.
  • Monitoramento: Prometheus + Grafana para métricas; um bot do Telegram para alertas. Registre cada ID de ordem que você envia e cada execução que você recebe.
  • Backups: persista o estado a cada minuto. Se o VPS morrer no meio de uma execução, você quer retomar em segundos, não reconciliar na mão.
  • Impostos: o seu logger é também a sua trilha de auditoria - ver Guia fiscal.

Parte 14 - Dicas profissionais validadas para a API da Polymarket

Doze hábitos de produção de operadores de bots ao vivo.
  1. Faça cache das credenciais de API após a primeira chamada de derivação - create_or_derive_api_creds() é limitada por taxa e lenta. Guarde apiKey/secret/passphrase no .env e carregue na inicialização.
  2. Use signature_type=2 (GNOSIS_SAFE) se você conectou uma carteira de navegador primeiro, e signature_type=1 (POLY_PROXY) apenas para contas de e-mail Magic-link. Um tipo incompatível retorna 401 'invalid api key'.
  3. Defina funder com o endereço da sua carteira proxy da Polymarket, não com o seu EOA. A chave de assinatura vive no EOA; os fundos vivem no proxy. Confundi-los é o bug de autenticação número 1.
  4. Indexe os resultados por rótulo, nunca por posição - clobTokenIds[outcomes.index("Yes")], não clobTokenIds[0]. Os mercados NegRisk e do Oscar têm ordem arbitrária.
  5. Sincronize o seu relógio antes de assinar - POLY_TIMESTAMP deve estar dentro de uma janela estreita. O drift de NTP em um VPS barato quebra a autenticação em silêncio. Rode chrony ou systemd-timesyncd.
  6. Busque novamente o livro REST a cada reconexão de WebSocket antes de reinscrever-se. O WebSocket dá deltas; se você perder um delta durante a reconexão, o seu livro local diverge da realidade e você cotará preços perdedores.
  7. Nunca dispare em rajada mais de 10 ordens por segundo - o endpoint /order limita a 500/10s em rajada e 3.000/10min sustentado. Adicione um token-bucket rate limiter do lado do cliente; o Cloudflare enfileira em vez de descartar, então retentativas cegas amplificam a fila.
  8. Use cancel_market_orders(market=conditionId) no desligamento, não cancel_all(). O cancelamento com escopo de mercado é idempotente e mais seguro se o bot cair no meio do loop em um único mercado.
  9. Acompanhe heartbeatMs por ativo - adicione um watchdog que force o refresh de qualquer mercado sem atualizações por 30s em um mercado ao vivo. Feeds de WS desatualizados são a fonte mais comum de alfa fantasma.
  10. Registre o ID da ordem antes de enviá-la, não depois. A idempotência exige que o cliente seja dono do ID para que a recuperação após uma queda possa reenviar sem execuções duplicadas.
  11. Use a HeartBeats API (janeiro de 2026+) para o cancelamento automático na desconexão. Defina o intervalo de heartbeat em 5s; o servidor cancela todas as suas ordens em repouso se perder dois heartbeats.
  12. Faça paper-trade com ordens de 1 $ em um mercado fino por 48 horas antes de escalar. A Polymarket não tem testnet; ordens reais mínimas são a única forma confiável de validar autenticação, assinatura, tratamento de execuções e fluxo de cancelamento.

Folha de consulta: situação → ação

SituaçãoAçãoPor quê
401 'invalid api key' na primeira chamadaVerifique se signature_type corresponde à origem da carteira e se o funder é o endereço do proxyO desalinhamento entre tipo 1 e 2 é 80% dos erros 401; o EOA como funder é o resto
Ordens rejeitadas com 'insufficient balance'Consulte /balance-allowance antes de cada ordem e reserve localmenteO CLOB reserva o colateral assim que você posta; duas ordens concorrentes podem reservar em dobro
Throttling 429 no endpoint /orderFaça backoff com jitter: 2^attempt + random() com teto de 30sO Cloudflare limita em vez de rejeitar; a retentativa ingênua amplifica a fila
WebSocket desconectado no meio da operaçãoCapture o livro via REST, reconcilie o estado local e então reinscreva-seOs deltas durante o intervalo se perdem; a captura ressincroniza as escadas de preço
Ordem enviada mas sem confirmação de execuçãoConsulte /data/order/{id} em 5s; se pendente, espere; se não encontrada, substituaRaro mas recuperável; por padrão "verifique o estado, depois aja"
Mercado resolvido durante uma cotação ativaCancele todas as ordens abertas naquele conditionId no evento de resoluçãoOrdens pós-resolução podem ficar como execuções zumbi se peculiaridades do adaptador dispararem
Você roda um bot de market-makingCote dentro de 2 centavos do ponto médio com tamanho de 100+ cotasA fórmula de recompensa pondera o aperto + o tamanho + o tempo no livro; apertado + tamanho + persistente vence
Você roda um bot de arbitragem em múltiplos resultadosUse FOK para cada perna, não GTCExecuções parciais na perna A com a perna B completa = exposição sem hedge e perda instantânea
Primeira vez que você constrói um botConstrua primeiro o scanner, depois o motor de preços, depois o sinal - nunca o sinal primeiroSinais sem um estado de livro limpo são armadilhas de correlação; faça os encanamentos funcionarem primeiro
Bot de produção caiu às 3 da manhãTenha autorrestart do systemd + alerta do Telegram + estado persistenteTodo bot sem supervisão vai cair; a única questão é se ele reinicia de forma limpa
Exemplo prático: loop mínimo de market-maker para recompensas de liquidez.

Objetivo. Ganhar recompensas de liquidez em um mercado de política de volume médio cotado em torno de 0.48 Yes / 0.52 No com um spread de 2 centavos. Bolsa de recompensa diária ~40 $ para este mercado.

Configuração. Inscreva-se via WebSocket nos dois token_ids. Faça cache do último mid visto. Defina spread_target = 0.02, size = 200 cotas por lado, reprice_threshold = 0.005 (5 ticks).

Loop. A cada atualização do livro via WS: calcule o novo mid = VWAP dos 3 melhores bids e asks. Se |cotações atuais - mid alvo| > reprice_threshold, cancele as duas ordens existentes, poste um novo bid em mid-0.01 e um novo ask em mid+0.01. Limite a reprecificação a uma vez a cada 2 segundos por lado.

Risco. Inventário máximo por lado = 1.000 cotas. Se o inventário > 500, alargue o spread desse lado em 0.005 a cada 100 cotas. Disjuntor: se o mid se mover >0.05 em 60 segundos, cancele tudo e pause por 5 minutos.

Resultado (execução real de 7 dias). Executadas ~14.000 cotas em 680 ordens, pagos 0 $ em taxas taker (lado maker), ganhos 31.40 $ em rebates de liquidez, o P&L direcional líquido foi -4.10 $ (pequenas perdas de inventário). Líquido +27.30 $ em 7 dias sobre 500 $ de capital de giro = ~8% ao mês. Escala linearmente em 30-50 mercados simultâneos em um único VPS.

Ponto-chave

Os traders que lucram de forma consistente na Polymarket tratam o guia da api da polymarket como um sistema, não como uma intuição. Guarde os números acima - eles são a diferença entre os 7,6% de carteiras lucrativas e o resto.

E agora?