Polymarket Bot Tutorial · Capitolo 7 di 32
Approfondimento della Polymarket Gamma API: endpoint /events e /markets, pagination, tag IDs (864 Tennis, 745 NBA, ecc.), filtering per volume 24h, rate limits e sample di codice Python e Node.
Cosa copre questo capitolo
Gamma è la catalog API di Polymarket: elenca ogni event, ogni market, tag, image e resolved outcome mostrato dal front-end. La CLOB API gestisce i trade; Gamma descrive ciò che è tradeable. La maggior parte dei bug dei bot nel layer di discovery nasce dal confondere le due cose, oppure dal perdere il pagination contract. Questo capitolo è il reference pratico per i principali endpoint di Gamma, con il comportamento esatto dei parametri su cui fanno affidamento i nostri fetcher in produzione.
Questo è il capitolo 7 della nostra serie in 32 parti su come costruire un Polymarket trading bot. Trattiamo l’argomento in profondità nelle sezioni qui sotto. Il contenuto del corpo di ogni sezione viene scritto e pubblicato capitolo per capitolo; le risposte FAQ e i riferimenti sono già completi e riflettono l’esperienza in produzione derivata dall’esecuzione del nostro trader.
- Gamma vs CLOB: quando usare l’uno o l’altro
- Anatomia dell’endpoint /events
- Anatomia dell’endpoint /markets
- Tags e tag IDs (lista verificata)
- Filtering: active, closed, ordinamento per volume24hr
- Pagination e limits
- Rate limits e caching
- Code: fetch dei market con volume 24h più alto
Gamma vs CLOB: quando usare l’uno o l’altro
Due servizi diversi per due lavori diversi.
Gamma (gamma-api.polymarket.com): catalog. Elenca events, markets, tags, descriptions, images, resolved outcomes, volume a 24 ore, volume totale, date di fine. HTTP read-only. Per la maggior parte delle letture non richiede autenticazione. Viene aggiornata continuamente ma è eventually consistent: un market appena chiuso può ancora mostrare closed: false per alcuni secondi.
CLOB (clob.polymarket.com): trading + order book. Elenca bid/ask migliori, depth del book top-N, trade recenti. Autenticato per gli endpoint di scrittura (inserimento ordini, cancellazione). Sono disponibili canali WebSocket real-time per gli aggiornamenti del book.
Regola pratica: usa Gamma per trovare cosa tradeare; usa CLOB per tradearlo. Un bot che legge i prezzi da Gamma sta usando dati stale — i campi prezzo di Gamma si aggiornano meno frequentemente dell’order book di CLOB. Un bot che legge i metadati del market da CLOB sta facendo più richieste del necessario.
Anatomia dell’endpoint /events
GET /events restituisce dati a livello di event. Un "event" è una pagina di Polymarket; un singolo event può contenere più markets (ad esempio, l’event 2024 Presidential Election ha un market per ciascun candidato).
Campi chiave:
slug: identificatore URL-safe, stabile per tutta la durata dell’event.title,description: visualizzazione umana.endDate(ISO 8601): quando l’event si chiude.active,closed: boolean; combinarli in una query con?active=true&closed=falseper gli event live.volume,volume24hr: totali in USD.tags: array di oggetti tag (vedi la sezione tags sotto).markets: array di oggetti market figli (vedi anatomia di/markets).
Il pattern di discovery più comune in assoluto: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Restituisce i 100 event attualmente live con il volume più alto.
Anatomia dell’endpoint /markets
GET /markets restituisce dati a livello di market. Un market è un contratto Y/N o multi-outcome; vive all’interno di un event.
Campi chiave:
slug: identificatore URL-safe.question: il titolo mostrato nella trading page (ad esempio "Will Trump be president on January 1, 2027?").outcomes: JSON string dei nomi degli outcome, ad esempio'["Yes","No"]'. Sempre due elementi per i binary; di più per i NegRisk.outcomePrices: JSON string dei prezzi correnti come decimali, ad esempio'["0.62","0.38"]'. Entrambi i lati sommano a circa 1.0 meno lo spread.clobTokenIds: JSON string degli ERC-1155 token IDs allineati con gli outcome. Sono i token che compri/vendi davvero.negRisk: boolean; true per i market multi-outcome che sommano a 1. Importante per l’order placement (capitolo 11).
I campi outcomes / outcomePrices / clobTokenIds arrivano come JSON string, non come array già parsati: fai il JSON-decode prima di usarli.
Tags e tag IDs (lista verificata)
I tag sono etichette categoriali (Sports, Crypto, Tennis, NBA, ecc.). I tag ID verificati in produzione per le categorie più usate:
| 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 |
Filtra per tag con ?tag_id=745 per un tag specifico, oppure con ?tag_slug=nba usando lo slug. Il filtering basato sullo slug è più leggibile nel codice ma leggermente più lento; quello basato sull’ID è il default in produzione.
Filtering: active, closed, ordinamento per volume24hr
Le quattro dimensioni di filtering che userai nel 95% dei casi.
active=true|false:trueesclude i market che il team di Polymarket ha nascosto dalla UI.closed=true|false:falseesclude i market resolved. La combinazioneactive=true&closed=falseè il live filter più comune.order=volume24hr,order=volume,order=endDate: chiave di ordinamento. Il più utile èvolume24hrper trovare i market attualmente attivi.ascending=true|false: per la maggior parte degli endpoint il default è true; quasi sempre vuoifalseper gli ordinamenti per volume.
Caveat: il filtering per tag_id combinato con order=volume24hr e ascending=false a volte restituisce una pagina vuota quando il tag ha pochissimi market live. Over-fetch sempre (richiedi più di quanto mostri) e fai post-filter per gestire questo caso.
Pagination e limits
Il parametro limit accetta da 1 a 500 per chiamata. Il default è 100 se non specificato. Sopra 500 il server applica un cap in modo silenzioso: ricevi 500 ma la response non indica che ce ne siano altri.
La pagination è basata su offset: ?limit=500&offset=500 per la seconda pagina. Non esiste pagination basata su cursor, quindi gli inserimenti concorrenti possono spostare i confini tra le pagine da una chiamata all’altra. Per la maggior parte delle esigenze di discovery di un bot questo è accettabile; per gli scrape di archivio, ordina per un campo stabile (endDate o createdAt) e rileva le sovrapposizioni tramite slug.
Pattern pratico per "tutti i market live": fetch con limit=500&order=volume24hr&ascending=false. Copre i top 500 per volume, che sono sostanzialmente tutti i market con attività non banale. Andare oltre la pagina 1 è raramente utile: i market nella coda della distribuzione del volume, per definizione, non sono dove c’è l’azione.
Rate limits e caching
Gamma è dietro Cloudflare e ha soft rate limits per IP. Soglie empiriche osservate sotto carico di produzione:
- Fino a circa 30 req/sec da un singolo IP in modo sostenuto: nessun problema.
- Burst di 100+ req/sec: occasionali 429, i retry hanno successo.
- Circa 500 req/sec sostenuti: pagina di rate-limit o blocco temporaneo (10-60s).
Gli header di response pubblicati includono valori Cache-Control di 30-60 secondi per la maggior parte degli endpoint. Rispettali: non c’è alcun vantaggio nel rifetchare lo stesso event 10 volte in un minuto. Pattern di caching in produzione: LRU + TTL in-process, indicizzato sulla URL completa, TTL di 30s. Riduce il numero di richieste e la latenza.
Per strategie ad alta frequenza, replica i dati di Gamma in uno store locale aggiornato da un singolo fetcher process; fai leggere più consumer da quello store. Un fetcher × molti consumer > molti fetcher × Gamma.
Code: fetch dei market con volume 24h più alto
Fetcher di riferimento in tre linguaggi, che restituisce i primi 50 live market per volume nelle ultime 24 ore.
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'
L’endpoint /events di Polymarket gamma NON supporta un parametro di free-text search: aggiungere ?q=foo o ?search=foo restituisce in modo silenzioso l’ordinamento di default. Filtra invece per slug o tag.











