Polymarket Bot Tutorial · Chapitre 7 sur 32
Analyse approfondie de l'API Gamma de Polymarket : endpoints /events et /markets, pagination, tag IDs (864 Tennis, 745 NBA, etc.), filtrage par volume sur 24h, rate limits, et exemples de code Python et Node.
Ce que couvre ce chapitre
Gamma est l'API de catalogue de Polymarket - elle répertorie chaque event, chaque market, tag, image et outcome résolu que le front-end affiche. L'API CLOB sert à trader ; Gamma décrit ce qui est tradable. La plupart des bugs de bot au niveau de la découverte viennent d'une confusion entre les deux, ou d'un contrat de pagination mal géré. Ce chapitre est la référence de terrain pour les principaux endpoints de Gamma, avec le comportement exact des paramètres sur lequel reposent nos fetchers en production.
- Gamma vs CLOB : quand utiliser lequel
- Anatomie de l'endpoint /events
- Anatomie de l'endpoint /markets
- Tags et tag IDs (liste vérifiée)
- Filtrage : active, closed, tri par volume24hr
- Pagination et limites
- Rate limits et caching
- Code : fetch des markets avec le plus gros volume sur 24h
Gamma vs CLOB : quand utiliser lequel
Deux services différents pour deux tâches différentes.
Gamma (gamma-api.polymarket.com) : catalogue. Liste les events, markets, tags, descriptions, images, outcomes résolus, volume sur 24 heures, volume total, dates de fin. HTTP en lecture seule. Aucune authentification requise pour la plupart des lectures. Mis à jour en continu, mais avec eventual consistency - un market qui vient de se fermer peut encore afficher closed: false pendant quelques secondes.
CLOB (clob.polymarket.com) : trading + order book. Liste le meilleur bid/ask actuel, la profondeur du book top-N, les trades récents. Authentifié pour les endpoints d'écriture (placement d'ordres, annulation). Canaux WebSocket temps réel disponibles pour les mises à jour du book.
Règle générale : utilisez Gamma pour trouver quoi trader ; utilisez CLOB pour trader. Un bot qui lit les prix depuis Gamma utilise des données périmées - les champs de prix de Gamma se mettent à jour moins fréquemment que l'order book de CLOB. Un bot qui lit les métadonnées de market depuis CLOB fait plus de requêtes que nécessaire.
Anatomie de l'endpoint /events
GET /events retourne des données au niveau de l'event. Un "event" est une page Polymarket ; un seul event peut contenir plusieurs markets (par exemple, l'event 2024 Presidential Election contient un market par candidat).
Champs clés :
slug: identifiant compatible URL, stable pendant toute la durée de vie de l'event.title,description: affichage humain.endDate(ISO 8601) : date de clôture de l'event.active,closed: booléens ; combinez-les dans une requête avec?active=true&closed=falsepour les events en cours.volume,volume24hr: totaux en USD.tags: tableau d'objets tag (voir la section tags ci-dessous).markets: tableau d'objets market enfants (voir l'anatomie de/markets).
Le pattern de découverte le plus courant : GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Retourne les 100 events actuellement actifs avec le plus gros volume.
Anatomie de l'endpoint /markets
GET /markets retourne des données au niveau du market. Un market est un contrat Yes/No ou multi-outcome ; il vit à l'intérieur d'un event.
Champs clés :
slug: identifiant compatible URL.question: le titre affiché sur la page de trading (par ex. "Will Trump be president on January 1, 2027?").outcomes: chaîne JSON des noms d'outcomes, par ex.'["Yes","No"]'. Toujours deux éléments pour un binary ; davantage pour NegRisk.outcomePrices: chaîne JSON des prix actuels en décimales, par ex.'["0.62","0.38"]'. Les deux côtés s'additionnent à ~1.0 moins le spread.clobTokenIds: chaîne JSON des ERC-1155 token IDs alignés sur les outcomes. Ce sont les tokens que vous achetez/vendez réellement.negRisk: booléen ; true pour les markets multi-outcome dont la somme fait 1. Important pour le placement d'ordres (chapitre 11).
Les champs outcomes / outcomePrices / clobTokenIds arrivent sous forme de chaînes JSON, et non de tableaux parsés - faites un JSON-decode avant utilisation.
Tags et tag IDs (liste vérifiée)
Les tags sont des labels catégoriels (Sports, Crypto, Tennis, NBA, etc.). Voici les tag IDs de production vérifiés pour les catégories les plus utilisées :
| 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 |
Filtrez par tag avec ?tag_id=745 pour un tag spécifique, ou ?tag_slug=nba en utilisant le slug. Le filtrage basé sur le slug est plus lisible dans le code, mais légèrement plus lent ; le filtrage par ID est le défaut en production.
Filtrage : active, closed, tri par volume24hr
Les quatre dimensions de filtrage que vous utiliserez 95 % du temps.
active=true|false:trueexclut les markets que l'équipe Polymarket a masqués de l'UI.closed=true|false:falseexclut les markets résolus. La combinaisonactive=true&closed=falseest le filtre live le plus courant.order=volume24hr,order=volume,order=endDate: clé de tri. Le plus utile estvolume24hrpour trouver les markets actuellement actifs.ascending=true|false: la valeur par défaut est true sur la plupart des endpoints ; vous voudrez presque toujoursfalsepour les tris par volume.
Attention : le filtrage par tag_id combiné à order=volume24hr et ascending=false renvoie parfois une page vide lorsque le tag a très peu de markets actifs. Faites toujours du over-fetch (demandez plus que ce que vous affichez) puis post-filtrez pour gérer ce cas.
Pagination et limites
Le paramètre limit accepte de 1 à 500 par appel. La valeur par défaut est 100 si rien n'est précisé. Au-delà de 500, le serveur plafonne silencieusement - vous recevez 500, mais la réponse n'indique pas qu'il y en a davantage.
La pagination est basée sur un offset : ?limit=500&offset=500 pour la deuxième page. Il n'y a pas de pagination basée sur cursor, donc des insertions simultanées peuvent faire bouger les frontières de page entre deux appels. Pour la plupart des besoins de découverte d'un bot, c'est acceptable ; pour des scrapes d'archive, triez sur un champ stable (endDate ou createdAt) et détectez les chevauchements par slug.
Pattern pratique pour "tous les markets actifs" : fetch limit=500&order=volume24hr&ascending=false. Cela couvre les 500 premiers par volume, ce qui correspond en pratique à presque tous les markets ayant une activité non triviale. Aller au-delà de la page 1 est rarement utile - les markets en queue de distribution de volume ne sont, par définition, pas ceux où il se passe quelque chose.
Rate limits et caching
Gamma est protégé par Cloudflare et applique des soft rate limits par IP. Seuils empiriques observés en charge de production :
- Jusqu'à ~30 req/sec soutenues depuis une IP : aucun problème.
- Rafales de 100+ req/sec : parfois des 429, les retries réussissent.
- ~500 req/sec soutenues : page de rate-limit ou blocage temporaire (10-60s).
Les en-têtes de réponse publiés incluent des valeurs Cache-Control de 30 à 60 secondes pour la plupart des endpoints. Respectez-les - il n'y a aucun intérêt à refetch le même event 10 fois par minute. Pattern de caching en production : LRU en mémoire + TTL basé sur l'URL complète, TTL de 30s. Cela réduit le nombre de requêtes et la latence.
Pour les stratégies à haute fréquence, répliquez les données Gamma dans un store local mis à jour par un seul process fetcher ; faites lire ce store par plusieurs consumers. Un fetcher × plusieurs consumers > plusieurs fetchers × Gamma.
Code : fetch des markets avec le plus gros volume sur 24h
Fetcher de référence en trois langages, renvoyant les 50 live markets ayant le plus gros volume sur 24 heures.
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 de Polymarket gamma ne prend PAS en charge de paramètre de recherche en texte libre - ajouter ?q=foo ou ?search=foo renvoie silencieusement le tri par défaut. Filtrez plutôt par slug ou par tag.












