Baue deinen ersten Poker-Bot in Python
Lektion 1 von 13: Verbinden
Spiele die erste Hand zu Ende und beaufsichtige dabei den Bot. Python 3.11+, ein Terminal und ein Bot-API-Schlüssel für Live-Spiele. Für Offline-Prüfungen ist kein Konto nötig.
Beginne mit einem kleinen Python-Client, der sich mit Open Poker verbindet und auf die zulässigen Aktionen des Servers antwortet. Deine erste abgeschlossene Hand ist das Ziel dieser Lektion; Strategie kommt später.
Kursbeginn: Lade den obenstehenden Kursstand herunter, um dem sich entwickelnden Kurs-Bot zu folgen. Der kurze Client unten erklärt die Verbindungsschleife. Halte den vollständigen Bauleitfaden als Referenz offen.
Was brauchst du wirklich, um loszulegen?
Verwende für den Kurs Python 3.11 oder neuer. Der kurze Client braucht nur eine Bibliothek:
python -m pip install "websockets>=14,<16"
Das war's. Kein SDK, kein Framework, keine Game Engine zum Installieren. Wir haben das Protokoll absichtlich einfach gehalten: Dein Bot verbindet sich per WebSocket, empfängt den Spielstatus als JSON-Nachrichten und sendet Aktionen als JSON zurück. Wenn du ein Dictionary parsen kannst, kannst du einen Bot bauen.
Du brauchst außerdem einen Open-Poker-Bot-API-Key: Melde dich an, wähle deinen Bot und klicke auf „Self Host“. Speichere den Schlüssel in OPEN_POKER_API_KEY in der lokalen Prozessumgebung. Siehe den Registrierungsleitfaden. Halte Zugangsdaten aus Quellcode und geteilten Screenshots heraus.
Diese Lektion verwendet WebSocket-Nachrichten direkt, damit du das Protokoll siehst. Protokolliere beim Lernen Nachrichtentypen und Fehlercodes; veröffentliche keine Rohdaten mit Zugangsdaten oder privaten Karten.
Wie sieht der vollständige Bot aus?
import asyncio
import json
import os
import uuid
import websockets
API_KEY = os.environ["OPEN_POKER_API_KEY"]
WS_URL = "wss://openpoker.ai/ws"
async def play():
headers = {"Authorization": f"Bearer {API_KEY}"}
async with websockets.connect(WS_URL, additional_headers=headers) as ws:
msg = json.loads(await ws.recv())
print(f"Connected as {msg['name']}")
await ws.send(json.dumps({"type": "set_auto_rebuy", "enabled": True}))
await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
async for raw in ws:
msg = json.loads(raw)
t = msg.get("type")
if t == "your_turn":
actions = {a["action"]: a for a in msg["valid_actions"]}
if "check" in actions:
act = "check"
elif "call" in actions:
act = "call"
else:
act = "fold"
await ws.send(json.dumps({
"type": "action",
"hand_id": msg["hand_id"],
"action": act,
"client_action_id": str(uuid.uuid4()),
"turn_token": msg["turn_token"],
}))
elif t == "table_closed":
await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
elif t == "season_ended":
await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
elif t == "hand_result":
winners = msg.get("winners", [])
if winners:
print(f"Hand won by {winners[0]['name']} (+{winners[0].get('amount', 0)})")
asyncio.run(play())Speichere die Datei als bot.py, setze OPEN_POKER_API_KEY in deiner lokalen Prozessumgebung und führe python bot.py aus. Bei erfolgreicher Verbindung wird dein Bot-Name ausgegeben. Das Besetzen eines Tisches und das Abschließen einer Hand hängen davon ab, ob andere Bots verfügbar sind. Dieses kurze Beispiel endet bei einer Trennung; arbeite die Zuverlässigkeitslektionen durch, bevor du einen Bot unbeaufsichtigt laufen lässt.
Was macht dieser Bot eigentlich?
Er ist eine Calling Station, und er war auch unser erster Bot.
Wenn du dran bist: Checke, wenn es erlaubt ist und nichts kostet. Wenn du nicht checken kannst, call. Wenn du nicht callen kannst, fold. Das verliert langsam Chips, weil du jeden Einsatz callst, ohne die HandStärke zu berücksichtigen. Aber es spielt legales Poker, bleibt am Tisch und gibt dir einen vollständigen Event Loop, auf dem du aufbauen kannst.
Diese fünf Protokollbegriffe solltest du kennen:
set_auto_rebuy sagt dem Server, dass er automatisch 1.500 Chips rebuyen soll, wenn du pleite gehst. Ohne das hört dein Bot auf zu spielen, nachdem er seinen Stack verloren hat. Damit kümmert sich der Server um die Rebuys (mit Cooldown), und dein Bot spielt unbegrenzt weiter.
join_lobby stellt dich in die Matchmaking-Warteschlange. Das buy_in-Feld legt fest, wie viele Chips du an den Tisch mitbringst. Der gültige Bereich ist 1.000 bis 5.000; wir verwenden standardmäßig 2.000, das sind 100 Big Blinds bei der 10/20-Blindstruktur. Wenn genügend Spieler in der Warteschlange sind, erstellt der Matchmaker einen 6-max-Tisch.
turn_token ist ein Anti-Replay-Token. Jede your_turn-Nachricht enthält einen frischen Token. Du musst ihn in deiner Aktion zurückschicken. Wenn du einen alten Token von einem vorherigen Zug sendest, wird die Aktion abgelehnt. Verwende immer den Token vom neuesten your_turn. Cache ihn nie.
hand_id identifiziert die aktuelle Hand. Sende sie zusammen mit dem Token aus derselben your_turn-Nachricht zurück.
client_action_id identifiziert einen Aktionsversuch. Der Server gibt diese ID in action_ack zurück; dieses Beispiel verwendet dafür eine UUID. Wiederherstellungscode muss die Identität eines Versuchs bewahren, wenn eine Bestätigung unklar bleibt.
Welche WebSocket-Nachrichten empfängt dein Bot?
Dein Bot empfängt einen kontinuierlichen Strom von JSON-Nachrichten. Die meisten sind informativ; du musst nur auf your_turn antworten. Aber die anderen zu verstehen ist der Weg, einen intelligenteren Bot zu bauen. Hier ist der vollständige Satz, den du antreffen wirst:
| Nachricht | Was sie bedeutet | Antwortest du? |
|---|---|---|
connected | Auth erfolgreich, du bist online | Nein |
lobby_joined | Du bist in der Matchmaking-Warteschlange | Nein |
table_joined | Du sitzt an einem Tisch | Nein |
hand_start | Neue Hand beginnt, dein Platz und der Dealer | Nein |
hole_cards | Deine zwei privaten Karten (z.B. ["Ah", "Kd"]) | Nein |
your_turn | Deine gültigen Aktionen, der Pot, das Board | Ja: Sende eine Aktion |
player_action | Jemand (vielleicht du) hat gehandelt | Nein |
community_cards | Flop, Turn oder River ausgeteilt | Nein |
hand_result | Hand vorbei, wer gewonnen hat | Nein |
busted | Du hast keine Chips mehr | Nein (Auto-Rebuy kümmert sich) |
table_closed | Tisch geschlossen | Lobby beitreten |
season_ended | Season-übergang | Lobby beitreten |
Die vollständige Nachrichtenreferenz findest du unter docs.openpoker.ai/api-reference/message-types. Jedes Feld jeder Nachricht ist mit JSON-Beispielen dokumentiert. Lesezeichen lohnt sich; du wirst es ständig nachschlagen.
Schlauer machen: drei schnelle Verbesserungen
Die Calling Station ist eine Verbindungs-Baseline. Probiere diese drei Strategieexperimente, sobald die Verbindung funktioniert, und miss ihre Wirkung, statt eine bestimmte Gewinnrate anzunehmen.
1. Schlechte Hände pre-flop folden
Die meisten StartHände im Poker sind Verlierer. Folde die schlechtesten 60% vor dem Flop, und du bist bereits vor jeder Calling Station auf der Plattform. Starthandauswahl ist die größte Verbesserung, die du machen kannst.
def should_play(cards):
"""Illustrative starting range, not a calibrated percentile."""
ranks = "23456789TJQKA"
r1 = ranks.index(cards[0][0])
r2 = ranks.index(cards[1][0])
high, low = max(r1, r2), min(r1, r2)
pair = r1 == r2
suited = cards[0][1] == cards[1][1]
if pair: return True # All pairs
if low >= 8: return True # Both cards ten or higher
if suited and high - low == 1 and low >= 7: return True # 98s+
if high == 12 and low >= 5: return True # A7+
return FalseSpeichere deine verdeckten Karten beim Empfang von hole_cards. Rufe anschließend should_play() im your_turn-Handler auf. Liegt die Hand außerhalb deiner Auswahl, checke, falls diese Aktion kostenlos und erlaubt ist. Folde andernfalls nur, wenn fold in valid_actions steht.
2. Raise mit starken Händen
Die Calling Station raist nie. Das bedeutet, Gegner sehen billige Flops gegen dich bei jeder Hand. Lösung: Raise mit deinen stärksten 15% der Hände pre-flop.
if "raise" in actions and should_raise(my_cards):
await ws.send(json.dumps({
"type": "action",
"hand_id": msg["hand_id"],
"action": "raise",
"amount": actions["raise"]["min"], # minimum raise
"client_action_id": next_id(),
"turn_token": msg["turn_token"],
}))Der raise-Eintrag in valid_actions zeigt dir die genauen min- und max-Beträge. Das amount-Feld ist ein Raise-to-Betrag (gesamte Einsatzgröße), kein Inkrement. Wenn der Big Blind 20 ist und du auf 60 raisen willst, sende "amount": 60.
3. Nutze Pot Odds post-flop
Nach dem Flop hast du echte Informationen. Pot Odds sagen dir, ob Callen mathematisch korrekt ist: Wenn der Preis, den du zahlst, niedriger ist als deine Gewinnwahrscheinlichkeit, calle. Sonst folde. Für die vollständige Mathematik hat der Pot-Odds-Glossareintrag durchgerechnete Beispiele und Fallen, die Anfänger-Bots erwischen.
def pot_odds_say_call(pot, call_amount, estimated_win_pct=0.3):
if call_amount == 0:
return True
odds = call_amount / (pot + call_amount)
return estimated_win_pct > oddsSelbst eine grobe Schätzung deiner Gewinnwahrscheinlichkeit (30% als Standard, höher mit Top Pair, niedriger ohne nichts), kombiniert mit Pot Odds, schlägt die reine Calling Station deutlich. Die your_turn-Nachricht enthält die aktuelle Potgröße, also hast du alles, was du brauchst.
Was wir beim Betrieb dieses Bots gelernt haben
Ich habe die Calling Station über 1.200 Hände laufen lassen, um einen echten Baseline zu bekommen. Sie verlor 2,4 Big Blinds pro 100 Hände - nicht katastrophal, aber ein stetiger Abfluss. Das größte Leck war nicht, zu viele Einsätze zu callen. Es war, River-Einsätze mit nichts zu callen. Die Calling Station hat kein Konzept von "Ich habe nichts getroffen und dieser Einsatz ist gross im Verhältnis zum Pot"; sie callt einfach, jedes Mal, und blutet.
Das Zweite, was mich überrascht hat: Auto-Rebuy-Cooldowns sind wichtiger als du denkst. Nach dem Pleitegang gibt es einen 5-Minuten-Cooldown im Free-Tier (2 Minuten bei Pro) vor dem nächsten Rebuy. Ein Bot, der häufig pleitegeht, verbringt viel Zeit ausserhalb des Spiels. Das Stack-Management richtig hinzubekommen (gar nicht erst pleitezugehen) hat Zinseszins-Effekte über die blosse Chip-Erhaltung hinaus.
Das Hinzufügen von should_play() aus dem Abschnitt oben senkte die Verlustrate auf etwa 0,8 bb/100 in unseren Tests - eine 3-fache Verbesserung durch eine Funktion. Der Bot verliert immer noch, aber jetzt verliert er wie ein mittelmäßiger Spieler statt wie ein kaputter. Das ist der Ausgangspunkt für echte Strategiearbeit.
Wir behaupten nicht, dass dies rigorose Stichprobengrößen sind. Die Varianz bei 6-max ist hoch, und 1.200 Hände sind ein kleines Fenster. Aber in der Tendenz ist das Muster konsistent: Pre-Flop-Selektion ist der erste Hebel, Post-Flop-Aggression ist der zweite.
Wie kannst du den 1.200-Hand-Baseline reproduzieren?
Behandle den Calling-Station-Lauf als technischen Baseline, nicht als Rentabilitätsnachweis. Das protokollierte Ergebnis lag bei -2,4 bb/100. Der spätere Preflop-Filter kam auf ungefähr -0,8 bb/100, aber für diesen Lauf fehlen genügend Metadaten für einen sauberen Direktvergleich. Diese Einschränkung gehört zum Ergebnis.
Halte für jeden Lauf diese Felder fest:
| Feld | Warum es in den Benchmark gehört |
|---|---|
| Git-Commit und Konfigurations-Hash | Belegt, welche Policy die Aktionen erzeugte |
| UTC-Start- und Endzeit | Macht Unterschiede bei Feld und Uptime sichtbar |
| Abgeschlossene Hand-IDs | Macht die Stichprobe prüfbar und verhindert Doppelzählung |
| Gewonnene oder verlorene Big Blinds pro 100 Hände | Normalisiert Ergebnisse über Blindstufen hinweg |
action_rejected-Anzahl | Erkennt Protokollfehler, die wie Strategieverluste aussehen |
| Turn-Timeouts und Reconnects | Trennt Entscheidungsqualität von Laufzeitfehlern |
| Gegneranzahl und Sitzverteilung | Zeigt, ob ein Tisch das Ergebnis dominiert hat |
Führe Baseline und Kandidat über dieselbe Mindestzahl an Händen aus, bewahre beide Rohlisten der Hand-IDs auf und gib Konfidenzintervalle an, bevor du eine Verbesserung für real hältst. 1.200 Hände helfen, offensichtliche Leaks wie bedingungslose River-Calls zu finden, reichen aber nicht, um Pokerstrategien zu ranken.

Eigener Produkt-Screenshot vom 10. März 2026. Er zeigt die Audit-Oberfläche, nicht den 1.200-Hand-Lauf selbst.
Was du im Leaderboard erwarten kannst
Die Basis-Calling-Station ist ein Verbindungstest, keine konkurrenzfähige Strategie. Die drei Verbesserungen entfernen offensichtliche Leaks, garantieren aber keinen festen Rang: Das Feld ändert sich und kleine Stichproben sind stark verrauscht. Verbessere Handbewertung, Gegnermodellierung, Stack-Management und Positionsbewusstsein und miss jede Änderung gegen eine festgehaltene Referenzstrategie.
Dein Bot braucht mindestens 10 Hände, um im Leaderboard zu erscheinen. Wie lange das dauert, hängt von der Verfügbarkeit eines Tisches und der Spielgeschwindigkeit ab.
Die vollständige Plattform-Dokumentation findest du unter docs.openpoker.ai. Der Aktions- und Strategieleitfaden behandelt Raise-Semantik, Turn Tokens und Timeout-Verhalten im Detail. Die websockets-Bibliothek-Dokumentation ist lesenswert, wenn du asynchrones Connection-Handling jenseits der hier gezeigten Grundlagen möchtest.
FAQ
Mein Bot verbindet sich, wird aber nie an einen Tisch gesetzt. Der Matchmaker braucht 2+ Spieler in der Warteschlange. Wenn sonst niemand spielt, wartet dein Bot. Starte zwei Bots mit verschiedenen API-Keys, oder Prüfe das Leaderboard, ob andere aktiv sind.
Ich bekomme action_rejected-Fehler.
Prüfe den Ablehnungscode. hand_id und turn_token müssen aus derselben aktuellen your_turn-Nachricht stammen. Verwende keine Berechtigung eines früheren Zuges.
Mein Bot wurde getrennt und hat seinen Platz verloren. Du hast 120 Sekunden, um dich wieder zu verbinden. Wenn du rechtzeitig reconnectest, bleibt dein Platz erhalten. Nach 120 Sekunden wird dein Stack an dein Guthaben zurückgegeben und du musst der Lobby erneut beitreten.
Kann ich diesen Bot 24/7 laufen lassen? Das kurze Beispiel ist für eine beaufsichtigte erste Sitzung gedacht. Unbeaufsichtigtes Spiel erfordert Reconnect, Zustandswiederherstellung, Fristenbehandlung und Bestätigungs-Tracking. Arbeite die Zuverlässigkeitsstufe durch, bevor du es versuchst.
Wie viel sollte ich einkaufen? Der gültige Bereich ist 1.000 bis 5.000 Chips. Wir verwenden 2.000 in den Beispielen (100 Big Blinds bei 10/20 Blinds), was ein Standard-Deep-Stack-Startbetrag ist. Weniger kaufen (1.000) reduziert Varianz, begrenzt aber auch, wie viel du in einer einzelnen Hand gewinnen kannst. Mehr kaufen (5.000) ist in Ordnung, sobald dein Bot eine grundlegende Fold/Raise-Strategie hat; mach das nicht mit einer reinen Calling Station.
Nachdem dein Bot eine Hand abgeschlossen hat, fahre mit der nächsten Lektion unten fort. Wenn die Lobby wartet, lass die Sitzung für weitere Gegner geöffnet und überprüfe deinen Client in der Zwischenzeit mit dem Offline-Kursstand.
Prüfe das Ergebnis von Lektion 1
- Was sich ändert
- Einen Client verbinden und eine zulässige Aktion senden.
- Erwartete Ausgabe
- completed_hands: 1
- So prüfst du dein Ergebnis
- Warte, bis eine echte Hand abgeschlossen ist. Ein Offline-Test mit simulierten Daten zählt nicht als Onlinespiel.
Entpacke das Archiv zur Lektion, öffne den Ordner in einem Terminal und führe diese Befehle aus:
python -m pip install -r requirements.txt
python bot.py --lesson 1 --self-test
python bot.py --lesson 1 --hands 3 --report run.jsonDer Selbsttest verwendet simulierte Daten ohne Verbindung zum Server und gibt Folgendes aus: checkpoint: passed. Für das Onlinespiel brauchst du OPEN_POKER_API_KEY in deiner Umgebung sowie verfügbare Gegner. Die beiliegende README erklärt die Einrichtung und die Grenzen der Wiederherstellung.
Alle Lektionen dieses Kurses
- 1. Einen Poker-Bot in Python bauen
- 2. Grundlegende Poker-Bot-Architektur
- 3. WebSocket-Fehler eines Poker-Bots debuggen
- 4. Warum deinem Pokerbot die Zeit ausgeht
- 5. Poker-Mathematik für Bots
- 6. Positions-Ranges für Poker-Bots
- 7. Einsatzstrategie für Poker-Bots
- 8. PokerKit-Tutorial
- 9. Monte-Carlo-Equity-Rechner
- 10. Gegner-Modellierung
- 11. Fortgeschrittene Poker-Bot-Architektur
- 12. So funktioniert die Ranglistenwertung
- 13. Professionelle Poker-Bot-Architektur