Chapitre 27 sur 33

La version courte

Polymarket expose trois API publiques : CLOB (trading), Gamma (découverte de marchés) et Data (analytique). Le SDK Python officiel est py-clob-client 0.34.6. L'authentification utilise une clé d'API + signature ECDSA, les ordres étant signés via EIP-712 à travers un portefeuille proxy sur Polygon. Les limites de débit vous restreignent à environ 60 ordres/minute par clé. Le plus gros écueil pour les nouveaux développeurs est le problème de mappage condition_id → token_id entre Gamma et CLOB - réglez-le en premier, et tout le reste se met en place. Chaque mois, on gagne sur Polymarket environ 40 millions $ en récompenses de liquidité et en spread capturé par les bots, presque entièrement par des utilisateurs de l'API.

Ce que vous apprendrez : comment les trois API s'articulent, comment installer et configurer py-clob-client, comment vous authentifier avec votre portefeuille proxy, comment récupérer des marchés et des carnets d'ordres, comment passer et annuler des ordres, comment diffuser des mises à jour de prix en temps réel via WebSocket, les limites de débit exactes et comment effectuer un backoff proprement, et une architecture de bot prête pour la production que vous pouvez étendre.
Prérequis : un compte Polymarket approvisionné avec au moins une transaction manuelle effectuée, Python 3.8+ (ou Node.js), et une familiarité de base avec HTTP, JSON et le code asynchrone. Si vous n'avez pas encore tradé manuellement, commencez par Première transaction avant de câbler un bot.
01
Chapitre 1

Partie 1 : Les trois API

Polymarket sépare proprement les responsabilités entre trois services distincts. Utiliser la bonne API pour chaque tâche garde votre bot rapide, simple et dans les limites de débit.

APIURL de baseButAuthentification requise
CLOB APIclob.polymarket.comPasser, annuler et suivre des ordres. Lire des carnets d'ordres. Interroger des positions.Oui (pour le trading)
Gamma APIgamma-api.polymarket.comParcourir les marchés, récupérer métadonnées, images, prix des résultats, volume, échéance, tags.Non (publique)
Data APIdata-api.polymarket.comTransactions historiques, instantanés de positions, analytique utilisateur, données de classement.Non (publique)

Une boucle de bot typique utilise Gamma pour trouver des marchés, CLOB pour récupérer les carnets d'ordres et passer des transactions, et Data pour back-tester la performance de la stratégie hors ligne. Pensez à Gamma comme au « catalogue », à CLOB comme à la « bourse » et à Data comme à l'« entrepôt ».

Astuce de pro : Gamma et Data ne nécessitent pas d'authentification. Vous pouvez les explorer avec curl ou un navigateur dès maintenant - sans compte. C'est un excellent moyen de prototyper avant même de générer une clé d'API.
02
Chapitre 2

Partie 2 : Authentification et le modèle de portefeuille proxy

Polymarket ne signe pas les transactions avec la clé privée de votre portefeuille principal. À la place, il utilise un portefeuille proxy de style Gnosis Safe : votre portefeuille principal autorise un proxy, et le proxy exécute toutes les transactions sur Polygon. Votre bot d'API parle à ce proxy.

Ce dont vous avez besoin

  • Clé d'API - générez-la dans Settings → Developer de Polymarket
  • Clé privée - la clé de votre portefeuille de trading (PAS la phrase de récupération de votre MetaMask principal)
  • Adresse funder - l'adresse de votre portefeuille proxy (affichée dans Settings → Wallet)
  • Chain ID - 137 (Polygon mainnet)
  • Type de signature - 1 (POLY_PROXY, standard pour les particuliers)
Règles de sécurité non négociables : ne validez jamais votre clé privée dans git. Utilisez des variables d'environnement (.env) ou un gestionnaire de secrets. Ne collez jamais de clés dans Discord, dans des issues GitHub ou dans ChatGPT. Supposez que toute clé qui touche votre presse-papiers est déjà compromise. Faites tourner les clés au moindre doute.
03
Chapitre 3

Partie 3 : Installer py-clob-client

Le SDK Python officiel est le moyen le plus rapide de passer de zéro à votre premier ordre. Nous utiliserons la version 0.34.6, qui est l'actuelle en avril 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

Configuration de base du client

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())

L'appel à create_or_derive_api_creds() signe un message avec votre clé privée et l'échange contre une clé d'API, un secret et une passphrase. Mettez-les en cache dans votre .env après la première exécution pour ne pas appeler l'endpoint de dérivation à chaque démarrage.

Exemple pratique - .env minimal :
POLY_PRIVATE_KEY=0xabc...
POLY_FUNDER=0xdef...
POLY_API_KEY=...
POLY_SECRET=...
POLY_PASSPHRASE=...
04
Chapitre 4

Partie 4 : Découvrir des marchés via Gamma

Avant de pouvoir trader, vous devez trouver des marchés qui en valent la peine. Gamma renvoie du JSON avec tout ce que l'interface de Polymarket affiche : question, résultats, prix, volume 24h, échéance, tags et images.

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}")

Paramètres utiles de requête Gamma

ParamètreCe qu'il fait
tag_slugFiltrer par catégorie (politics, sports, crypto, culture, etc.)
active=trueUniquement les marchés acceptant actuellement des transactions
closed=falseMasquer les marchés résolus
order=volume24hrTrier par volume récent (signal de liquidité)
end_date_minDate ISO - ignorer les marchés se résolvant trop tôt
limitJusqu'à 500 par page (utilisez offset pour la pagination)
05
Chapitre 5

Partie 5 : Le mappage condition_id → token_id

C'est le point de douleur numéro 1 dans le développement de bots Polymarket. Gamma renvoie un condition_id (un par marché). Les transactions CLOB utilisent un token_id (un par résultat). Vous avez toujours besoin des deux.

L'erreur : passer un condition_id à des endpoints CLOB qui attendent un token_id. Vous obtiendrez une erreur cryptique 'invalid token'. Mappez toujours d'abord, tradez ensuite.
# 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']

Le piège de l'ordre des résultats

Le tableau outcomes et le tableau clobTokenIds de Gamma sont indexés ensemble. Lisez toujours l'étiquette du résultat plutôt que de supposer que l'index 0 est « Yes ». Dans les marchés à résultats multiples (NegRisk, Oscars, élections), l'index 0 pourrait être « Kamala Harris » ou « Taylor Swift » - l'ordre est déterministe mais propre au marché.

06
Chapitre 6

Partie 6 : Lire les carnets d'ordres

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}")

Les carnets d'ordres sont renvoyés sous forme de tableaux triés (bids décroissants, asks croissants). Chaque niveau a un price et une size. Pour estimer le slippage d'un ordre plus important, parcourez le carnet et accumulez le notionnel jusqu'à avoir consommé votre taille cible.

07
Chapitre 7

Partie 7 : Passer des ordres

Ordre à cours limité (GTC - par défaut)

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)

L'appel à create_order signe un message structuré EIP-712 avec votre clé privée. post_order le soumet à CLOB. Vous n'envoyez jamais de clés privées brutes sur le réseau - seulement des ordres signés.

Types d'ordre

TypeCodeComportementQuand l'utiliser
Good Till CancelledGTCRepose sur le carnet jusqu'à exécution ou annulation de votre partPar défaut. La plupart du market making et des stratégies à cours limité.
Good Till DateGTDS'auto-annule à un horodatage spécifiéPiloté par événement : « annule 5 min avant l'annonce de la Fed »
Fill or KillFOKDoit exécuter toute la taille immédiatement ou s'annuler entièrementPattes d'arbitrage où les exécutions partielles ruinent la transaction
Fill and KillFAKExécute ce qu'il peut au prix limite, annule le restePrise agressive - agit comme un ordre au marché avec un plafond de prix

Annuler

# 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
Chapitre 8

Partie 8 : Streaming WebSocket

Interroger Gamma chaque seconde est du gaspillage et vous atteindrez vite les limites de débit. Le flux WebSocket diffuse les mises à jour de carnet d'ordres et de transactions en temps réel, avec une latence inférieure à la seconde.

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)

Deux flux existent : le flux /market (carnet d'ordres et transactions publics) et le flux /user (vos propres événements d'ordre et d'exécution, authentifié). Les bots de production se connectent généralement aux deux, se reconnectent automatiquement à la déconnexion, et traitent le WebSocket comme la source de vérité de l'état actuel du carnet.

Pulsations et reconnexions : envoyez un ping toutes les 20 secondes. Si vous manquez deux pong, reconnectez-vous. À la reconnexion, récupérez toujours d'abord le carnet d'ordres via REST, puis réabonnez-vous - sinon votre carnet local dérive de la réalité.
09
Chapitre 9

Partie 9 : Limites de débit et backoff

Classe d'endpointLimiteRafale
Envoi d'ordres (CLOB)~60 / minute par clé d'API~10 / seconde
Annulation d'ordres~120 / minute~20 / seconde
Lectures de données de marché (carnet CLOB)~300 / minuteplus élevé, varie
Gamma APIGénéreuse ; respectez les 429-
Messages WebSocketAucune limite pratique en entrée-

Lorsque vous recevez un HTTP 429, le serveur renvoie un en-tête Retry-After. Implémentez un backoff exponentiel avec 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
Chapitre 10

Partie 10 : Une architecture de bot de référence

Tout bot Polymarket robuste a les mêmes six composants. Construisez chacun comme son propre module ; gardez-les faiblement couplés.

ComposantResponsabilitéAPI utilisées
ScannerTâche planifiée : extraire les marchés correspondant à vos critères (tags, volume, jours avant échéance)Gamma
Moteur de prixMaintenir des carnets d'ordres locaux en temps réel via WebSocketCLOB WS
Générateur de signauxFonction pure : état du carnet + métadonnées → position cible- (en mémoire)
Gestionnaire d'ordresComparer les ordres actuels à la cible, passer/annuler au minimumCLOB REST
Gestionnaire de risqueAppliquer des plafonds par marché, des limites de perte quotidiennes, des coupe-circuits- (en mémoire + BD)
Journal et grand livrePersister chaque décision, exécution, annulation. Alimente les rapports fiscaux et le débogage.SQLite / Postgres
La fiabilité d'abord : avant d'optimiser le PnL, assurez-vous que votre bot peut redémarrer proprement à 3 h du matin un dimanche sans humain. Cela signifie un envoi d'ordres idempotent (utilisez des IDs d'ordre côté client), un état persistant, et des alertes automatiques (Telegram, Discord, PagerDuty) pour toute exception non gérée.

Partie 11 : Modes de défaillance courants

  • Données WebSocket obsolètes - Suivez l'heure du dernier message par actif ; s'il n'y a pas de mise à jour pendant >30s sur un marché actif, forcez un rafraîchissement REST.
  • Collisions de nonce - py-clob-client gère les nonce des ordres pour vous, mais si vous écrivez votre propre signataire, incrémentez le nonce à chaque ordre.
  • Solde insuffisant - Vérifiez toujours le solde pUSD avant de passer ; le carnet pourrait afficher votre ordre mais l'appariement le rejettera.
  • Marché en pause ou en résolution - Vérifiez market.active && !market.closed avant de trader. Les mises à jour de Gamma sont en retard sur CLOB de quelques secondes autour de la résolution.
  • Désaccord de l'adaptateur NegRisk - Les marchés à résultats multiples passent par un adaptateur NegRisk distinct. Le SDK le gère, mais confirmez que votre ordre est allé au bon venue.
Limitation du testnet : Polymarket n'exploite pas de testnet public en 2026. Le « paper trading » signifie passer de minuscules ordres réels (1-5 $) sur des marchés à faible liquidité. Prévoyez quelques dollars pour votre première semaine de débogage - cela vous en économisera des centaines plus tard.

Partie 12 : Récompenses de liquidité via l'API

Polymarket fait tourner environ 5 millions $/mois en récompenses de liquidité générales plus 5 millions $+/mois en récompenses spécifiques au sport (voir Récompenses de liquidité). La grande majorité va aux market makers pilotés par API qui peuvent maintenir des cotations bilatérales serrées sur des milliers de marchés.

La formule de récompense récompense les ordres proches du point médian, la taille et le temps au carnet. Une boucle de market making minimale :

  1. Lisez le carnet d'ordres du marché cible
  2. Calculez un point médian juste (p. ex. VWAP des 3 meilleurs niveaux de chaque côté)
  3. Postez un bid à mid − spread_target/2 et un ask à mid + spread_target/2
  4. À chaque mise à jour WebSocket, ré-évaluez le prix si votre cotation dérive de plus d'un tick par rapport à la cible
  5. Annulez et sortez si le carnet s'amincit ou si des nouvelles tombent

Partie 13 : Passer en production

  • Hébergement : un VPS à 6 $/mois (Hetzner, DigitalOcean) en Europe ou US-East suffit pour la plupart des bots. Co-localisez avec un Polygon RPC si vous avez besoin d'une latence inférieure à 10ms.
  • RPC : utilisez Alchemy, Infura ou QuickNode pour un Polygon RPC fiable. Les paliers gratuits suffisent jusqu'à ce que vous passiez des centaines d'ordres par minute.
  • Surveillance : Prometheus + Grafana pour les métriques ; un bot Telegram pour les alertes. Journalisez chaque ID d'ordre que vous envoyez et chaque exécution que vous recevez.
  • Sauvegardes : persistez l'état chaque minute. Si le VPS meurt en pleine exécution, vous voulez reprendre en quelques secondes, pas réconcilier à la main.
  • Impôts : votre journal est aussi votre piste d'audit - voir Guide fiscal.

Partie 14 - Conseils de pro validés pour l'API Polymarket

Douze habitudes de production d'opérateurs de bots en direct.
  1. Mettez en cache les identifiants d'API après le premier appel de dérivation - create_or_derive_api_creds() est limité en débit et lent. Stockez apiKey/secret/passphrase dans .env et chargez-les au démarrage.
  2. Utilisez signature_type=2 (GNOSIS_SAFE) si vous avez connecté un portefeuille de navigateur en premier, signature_type=1 (POLY_PROXY) uniquement pour les comptes e-mail Magic-link. Un type non concordant renvoie 401 'invalid api key'.
  3. Réglez funder sur l'adresse de votre portefeuille proxy Polymarket, pas sur votre EOA. La clé de signature vit dans l'EOA ; les fonds vivent dans le proxy. Les confondre est le bug d'authentification numéro 1.
  4. Indexez les résultats par étiquette, jamais par position - clobTokenIds[outcomes.index("Yes")] et non clobTokenIds[0]. Les marchés NegRisk et Oscars ont un ordre arbitraire.
  5. Synchronisez votre horloge avant de signer - POLY_TIMESTAMP doit être dans une fenêtre étroite. La dérive NTP sur un VPS bon marché casse l'authentification en silence. Lancez chrony ou systemd-timesyncd.
  6. Récupérez à nouveau le carnet REST à chaque reconnexion WebSocket avant de vous réabonner. Le WebSocket donne des deltas ; si vous manquez un delta pendant la reconnexion, votre carnet local diverge de la réalité et vous coterez des prix perdants.
  7. N'envoyez jamais en rafale plus de 10 ordres par seconde - l'endpoint /order limite à 500/10s en rafale et 3 000/10min en soutenu. Ajoutez un token-bucket rate limiter côté client ; Cloudflare met en file plutôt que de jeter, donc les réessais aveugles amplifient l'arriéré.
  8. Utilisez cancel_market_orders(market=conditionId) à l'arrêt, pas cancel_all(). L'annulation à portée de marché est idempotente et plus sûre si le bot plante en pleine boucle sur un seul marché.
  9. Suivez heartbeatMs par actif - ajoutez un watchdog qui force le rafraîchissement de tout marché sans mise à jour pendant 30s sur un marché en direct. Les flux WS obsolètes sont la source la plus courante d'alpha fantôme.
  10. Journalisez l'ID de l'ordre avant de l'envoyer, pas après. L'idempotence exige que le client soit propriétaire de l'ID pour que la reprise après plantage puisse renvoyer sans exécutions en double.
  11. Utilisez la HeartBeats API (janvier 2026+) pour l'annulation automatique à la déconnexion. Réglez l'intervalle de heartbeat sur 5s ; le serveur annule tous vos ordres au repos s'il manque deux heartbeats.
  12. Faites du paper-trade avec des ordres de 1 $ sur un marché fin pendant 48 heures avant de monter en échelle. Polymarket n'a pas de testnet ; les minuscules ordres réels sont le seul moyen fiable de valider l'authentification, la signature, la gestion des exécutions et le flux d'annulation.

Aide-mémoire : situation → action

SituationActionPourquoi
401 'invalid api key' au premier appelVérifiez que signature_type correspond à l'origine du portefeuille et que le funder est l'adresse du proxyLe désaccord entre type 1 et 2 représente 80% des erreurs 401 ; l'EOA comme funder est le reste
Ordres rejetés avec 'insufficient balance'Interrogez /balance-allowance avant chaque ordre et réservez localementCLOB réserve le collatéral dès que vous postez ; deux ordres concurrents peuvent doubler la réservation
Throttling 429 sur l'endpoint /orderFaites un backoff avec jitter : 2^attempt + random() plafonné à 30sCloudflare limite plutôt que de rejeter ; le réessai naïf amplifie l'arriéré
WebSocket déconnecté en pleine transactionCapturez le carnet via REST, réconciliez l'état local, puis réabonnez-vousLes deltas pendant l'écart sont perdus ; la capture resynchronise les échelles de prix
Ordre passé mais aucune confirmation d'exécutionInterrogez /data/order/{id} sous 5s ; si en attente, attendez ; si introuvable, remplacezRare mais récupérable ; par défaut « vérifier l'état, puis agir »
Marché résolu pendant une cotation activeAnnulez tous les ordres ouverts sur ce conditionId à l'événement de résolutionLes ordres post-résolution peuvent traîner comme des exécutions zombies si des bizarreries d'adaptateur se déclenchent
Vous lancez un bot de market-makingCotez à moins de 2 centimes du point médian avec une taille de 100+ actionsLa formule de récompense pondère la serrure + la taille + le temps au carnet ; serré + taille + persistant gagne
Vous lancez un bot d'arbitrage sur résultats multiplesUtilisez FOK pour chaque patte, pas GTCLes exécutions partielles sur la patte A avec une patte B complète = exposition non couverte et perte instantanée
Première fois que vous construisez un botConstruisez d'abord le scanner, puis le moteur de prix, puis le signal - jamais le signal en premierLes signaux sans état de carnet propre sont des pièges de corrélation ; faites d'abord fonctionner la plomberie
Bot de production planté à 3 h du matinAyez un redémarrage auto de systemd + une alerte Telegram + un état persistantTout bot sans surveillance plantera ; la seule question est de savoir s'il redémarre proprement
Exemple pratique : boucle minimale de market-maker pour les récompenses de liquidité.

Objectif. Gagner des récompenses de liquidité sur un marché politique de volume moyen coté autour de 0.48 Yes / 0.52 No avec un spread de 2 centimes. Cagnotte de récompense quotidienne ~40 $ pour ce marché.

Configuration. Abonnez-vous par WebSocket aux deux token_ids. Mettez en cache le dernier mid vu. Définissez spread_target = 0.02, size = 200 actions par côté, reprice_threshold = 0.005 (5 ticks).

Boucle. À chaque mise à jour du carnet via WS : calculez le nouveau mid = VWAP des 3 meilleurs bids et asks. Si |cotations actuelles - mid cible| > reprice_threshold, annulez les deux ordres existants, postez un nouveau bid à mid-0.01 et un nouvel ask à mid+0.01. Limitez la ré-évaluation à une fois toutes les 2 secondes par côté.

Risque. Inventaire maximal par côté = 1 000 actions. Si l'inventaire > 500, élargissez le spread de ce côté de 0.005 par tranche de 100 actions. Coupe-circuit : si le mid bouge de >0.05 en 60 secondes, annulez tout et faites une pause de 5 minutes.

Résultat (exécution réelle sur 7 jours). Exécuté ~14 000 actions sur 680 ordres, payé 0 $ de frais taker (côté maker), gagné 31.40 $ en rebates de liquidité, le P&L directionnel net était de -4.10 $ (petites pertes d'inventaire). Net +27.30 $ sur 7 jours pour 500 $ de capital de travail = ~8% par mois. S'étend linéairement sur 30-50 marchés simultanés sur un seul VPS.

Point clé

Les traders qui réalisent des profits réguliers sur Polymarket traitent le guide de l'api polymarket comme un système, pas comme une intuition. Conservez les chiffres ci-dessus - ils font la différence entre les 7,6% de portefeuilles rentables et le reste.

Et ensuite ?