Polymarket Bot Tutorial · Kapitel 7 von 32
Polymarket Gamma API Deep Dive: /events- und /markets-Endpunkte, Pagination, Tag-IDs (864 Tennis, 745 NBA, etc.), Filtering nach 24h-Volumen, Rate Limits und Python- und Node-Codebeispiele.
Was dieses Kapitel abdeckt
Gamma ist Polymarkets Catalog API - sie listet jedes Event, jeden Market, Tag, jedes Image und jedes resolved outcome, das das Front-end anzeigt. Die CLOB API handelt; Gamma beschreibt, was handelbar ist. Die meisten Bot-Bugs auf der Discovery-Ebene entstehen dadurch, dass die beiden verwechselt werden oder der Pagination-Contract übersehen wird. Dieses Kapitel ist die Field Reference für die wichtigsten Gamma-Endpunkte mit dem genauen Parameterverhalten, auf das sich unsere Produktions-Fetcher stützen.
- Gamma vs CLOB: wann welches verwenden
- /events-Endpunkt-Anatomie
- /markets-Endpunkt-Anatomie
- Tags und Tag-IDs (verifizierte Liste)
- Filtering: active, closed, volume24hr-Ordering
- Pagination und Limits
- Rate Limits und Caching
- Code: Top-Markets nach 24h-Volumen abrufen
Gamma vs CLOB: wann welches verwenden
Zwei verschiedene Services für zwei verschiedene Aufgaben.
Gamma (gamma-api.polymarket.com): Catalog. Listet Events, Markets, Tags, Beschreibungen, Images, resolved outcomes, 24-Stunden-Volumen und Gesamtvolumen, Enddaten. Read-only HTTP. Für die meisten Reads keine Authentifizierung erforderlich. Kontinuierlich aktualisiert, aber eventually consistent - ein gerade geschlossenes Market kann für ein paar Sekunden noch closed: false anzeigen.
CLOB (clob.polymarket.com): Trading + Order Book. Listet aktuellen best bid/ask, Top-N-Book-Depth und recente Trades. Für Write-Endpunkte authentifiziert (Order-Platzierung, Cancellation). Real-time WebSocket-Channels für Book-Updates verfügbar.
Faustregel: Gamma verwenden, um zu finden, was gehandelt werden soll; CLOB verwenden, um es zu handeln. Ein Bot, der Preise aus Gamma liest, verwendet veraltete Daten - Gamma-Preisfelder aktualisieren sich seltener als das CLOB Order Book. Ein Bot, der Market-Metadaten aus CLOB liest, macht mehr Requests als nötig.
/events-Endpunkt-Anatomie
GET /events liefert Event-Level-Daten zurück. Ein "Event" ist eine Polymarket-Seite; ein einzelnes Event kann mehrere Markets enthalten (z. B. hat das 2024 Presidential Election-Event ein Market pro Kandidat).
Wichtige Felder:
slug: URL-sicherer Identifier, für die Lebensdauer des Events stabil.title,description: zur Anzeige für Menschen.endDate(ISO 8601): wann das Event schließt.active,closed: Booleans; in einer Query mit?active=true&closed=falsefür Live-Events kombinieren.volume,volume24hr: USD-Gesamtwerte.tags: Array von Tag-Objekten (siehe Tag-Abschnitt unten).markets: Array von untergeordneten Market-Objekten (siehe/markets-Anatomie).
Das mit Abstand häufigste Discovery-Muster: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Gibt die 100 aktuell live Events mit dem höchsten Volumen zurück.
/markets-Endpunkt-Anatomie
GET /markets liefert Market-Level-Daten zurück. Ein Market ist ein einzelner Y/N- oder Multi-Outcome-Contract; er befindet sich innerhalb eines Events.
Wichtige Felder:
slug: URL-sicherer Identifier.question: der auf der Trading-Seite angezeigte Titel (z. B. "Will Trump be president on January 1, 2027?").outcomes: JSON-String der Outcome-Namen, z. B.'["Yes","No"]'. Bei binary Markets immer zwei Elemente; bei NegRisk mehr.outcomePrices: JSON-String der aktuellen Preise als Dezimalwerte, z. B.'["0.62","0.38"]'. Beide Seiten summieren sich auf ~1.0 minus Spread.clobTokenIds: JSON-String von ERC-1155 Token IDs, ausgerichtet auf die Outcomes. Das sind die Tokens, die du tatsächlich kaufst/verkaufst.negRisk: Boolean;truefür Multi-Outcome-Sum-to-1-Markets. Wichtig für die Order-Platzierung (Kapitel 11).
Die Felder outcomes / outcomePrices / clobTokenIds kommen als JSON-Strings an, nicht als geparste Arrays - vor der Verwendung JSON-decodieren.
Tags und Tag-IDs (verifizierte Liste)
Tags sind kategoriale Labels (Sports, Crypto, Tennis, NBA, etc.). Die verifizierten Production-Tag-IDs für die am häufigsten verwendeten Kategorien:
| 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 |
Nach Tag filtern mit ?tag_id=745 für einen bestimmten Tag oder mit dem Slug ?tag_slug=nba. Slug-basiertes Filtern ist im Code lesbarer, aber etwas langsamer; ID-basiert ist der Production-Standard.
Filtering: active, closed, volume24hr-Ordering
Die vier Filterdimensionen, die du in 95% der Fälle verwenden wirst.
active=true|false:trueschließt Markets aus, die das Polymarket-Team aus der UI ausgeblendet hat.closed=true|false:falseschließt resolved Markets aus. Die Kombinationactive=true&closed=falseist der häufigste Live-Filter.order=volume24hr,order=volume,order=endDate: Sortierschlüssel. Am nützlichsten istvolume24hr, um aktuell aktive Markets zu finden.ascending=true|false: Standard ist bei den meisten Endpunktentrue; für Volume-Orderings willst du fast immerfalse.
Hinweis: Das Filtern nach tag_id in Kombination mit order=volume24hr und ascending=false liefert manchmal eine leere Seite, wenn der Tag sehr wenige live Markets hat. Immer über-abfragen (mehr anfordern, als du anzeigst) und anschließend post-filtern, um das abzufangen.
Pagination und Limits
Der Parameter limit akzeptiert 1-500 pro Call. Standard ist 100, wenn nicht angegeben. Über 500 begrenzt der Server stillschweigend - du erhältst 500, aber die Response enthält keinen Hinweis auf mehr.
Pagination ist offset-basiert: ?limit=500&offset=500 für die zweite Seite. Es gibt keine cursor-basierte Pagination, daher können gleichzeitige Inserts die Seiten-Grenzen zwischen den Calls verschieben. Für die meisten Bot-Discovery-Zwecke ist das akzeptabel; für Archive-Scrapes nach einem stabilen Feld sortieren (endDate oder createdAt) und Overlap per Slug erkennen.
Praktisches Muster für "alle live Markets": limit=500&order=volume24hr&ascending=false abrufen. Das deckt die Top 500 nach Volumen ab, also praktisch jedes Market mit nennenswerter Aktivität. Über Seite 1 hinauszugehen ist selten sinnvoll - Markets im Tail der Volumenverteilung sind per Definition nicht dort, wo die Aktion stattfindet.
Rate Limits und Caching
Gamma wird über Cloudflare ausgeliefert und hat weiche Rate Limits pro IP. Empirische Schwellenwerte unter Production-Last:
- Bis zu ~30 req/sec von einer IP dauerhaft: in Ordnung.
- Bursts von 100+ req/sec: gelegentlich 429s, Retries funktionieren.
- ~500 req/sec dauerhaft: Rate-Limit-Seite oder temporäre Blockierung (10-60s).
Die veröffentlichten Response-Header enthalten bei den meisten Endpunkten Cache-Control-Werte von 30-60 Sekunden. Halte dich daran - es bringt keinen Vorteil, dasselbe Event 10 Mal pro Minute neu abzurufen. Production-Caching-Muster: in-process LRU + TTL, keyed auf die vollständige URL, 30s TTL. Spart Request-Count und reduziert Latenz.
Für High-Frequency-Strategien Gamma-Daten in einen lokalen Store spiegeln, der von einem einzelnen Fetcher-Prozess aktualisiert wird; mehrere Consumer sollen aus diesem Store lesen. Ein Fetcher × viele Consumer > viele Fetcher × Gamma.
Code: Top-Märkte nach 24h-Volumen abrufen
Referenz-Fetcher in drei Sprachen, der die Top 50 live Markets nach 24-Stunden-Volumen zurückgibt.
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'
Der Polymarket Gamma /events-Endpunkt unterstützt keinen Free-Text-Search-Parameter - wenn du ?q=foo oder ?search=foo hinzufügst, wird stillschweigend die Standard-Sortierung zurückgegeben. Stattdessen nach Slug oder Tag filtern.










