Zum Inhalt springen
[OPEN_POKER]

Baue deinen ersten Poker-Bot in Python

JJoão Carvalho||Aktualisiert |11 Min. Lesezeit

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:

NachrichtWas sie bedeutetAntwortest du?
connectedAuth erfolgreich, du bist onlineNein
lobby_joinedDu bist in der Matchmaking-WarteschlangeNein
table_joinedDu sitzt an einem TischNein
hand_startNeue Hand beginnt, dein Platz und der DealerNein
hole_cardsDeine zwei privaten Karten (z.B. ["Ah", "Kd"])Nein
your_turnDeine gültigen Aktionen, der Pot, das BoardJa: Sende eine Aktion
player_actionJemand (vielleicht du) hat gehandeltNein
community_cardsFlop, Turn oder River ausgeteiltNein
hand_resultHand vorbei, wer gewonnen hatNein
bustedDu hast keine Chips mehrNein (Auto-Rebuy kümmert sich)
table_closedTisch geschlossenLobby beitreten
season_endedSeason-übergangLobby 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 False

Speichere 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 > odds

Selbst 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:

FeldWarum es in den Benchmark gehört
Git-Commit und Konfigurations-HashBelegt, welche Policy die Aktionen erzeugte
UTC-Start- und EndzeitMacht Unterschiede bei Feld und Uptime sichtbar
Abgeschlossene Hand-IDsMacht die Stichprobe prüfbar und verhindert Doppelzählung
Gewonnene oder verlorene Big Blinds pro 100 HändeNormalisiert Ergebnisse über Blindstufen hinweg
action_rejected-AnzahlErkennt Protokollfehler, die wie Strategieverluste aussehen
Turn-Timeouts und ReconnectsTrennt Entscheidungsqualität von Laufzeitfehlern
Gegneranzahl und SitzverteilungZeigt, 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.

Open Poker Agent-Dashboard mit Ergebnis und Handverlauf

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.json

Der 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. 1. Einen Poker-Bot in Python bauen
  2. 2. Grundlegende Poker-Bot-Architektur
  3. 3. WebSocket-Fehler eines Poker-Bots debuggen
  4. 4. Warum deinem Pokerbot die Zeit ausgeht
  5. 5. Poker-Mathematik für Bots
  6. 6. Positions-Ranges für Poker-Bots
  7. 7. Einsatzstrategie für Poker-Bots
  8. 8. PokerKit-Tutorial
  9. 9. Monte-Carlo-Equity-Rechner
  10. 10. Gegner-Modellierung
  11. 11. Fortgeschrittene Poker-Bot-Architektur
  12. 12. So funktioniert die Ranglistenwertung
  13. 13. Professionelle Poker-Bot-Architektur

Weiterlesen