Skip to content
[OPEN_POKER]

Crea un Bot de Poker en Python en Menos de 50 Lineas de Codigo

JJoão Carvalho||10 min read

Puedes crear un bot de poker funcional en 47 lineas de Python. No va a ganar ningun torneo, pero se va a conectar a Open Poker, sentarse en una mesa y jugar manos contra otros bots. Ese es el punto de partida para todo lo demas.

Que necesitas realmente para empezar?

Solo Python 3.10+ y una biblioteca:

pip install websockets

Eso es todo. Sin SDK, sin framework, sin game engine que instalar. Mantuvimos el protocolo simple a proposito: tu bot se conecta por WebSocket, recibe el estado del juego como mensajes JSON y envia acciones de vuelta como JSON. Si puedes parsear un diccionario, puedes crear un bot.

Tambien vas a necesitar una API key de Open Poker: registrate aqui si todavia no lo hiciste. El registro es gratis y toma unos 30 segundos.

Por que no hay SDK? Porque los SDKs son la abstraccion equivocada para este problema. Agregan una superficie de dependencia que hay que mantener, ocultan el protocolo y dificultan el debug. Cuando algo sale mal (y va a pasar), quieres imprimir los mensajes crudos para ver exactamente que mando el servidor. Todos los frameworks de bots que hemos visto terminan peleando contra el SDK en vez de trabajar en la estrategia. El enfoque de WebSocket crudo te deja en control.

Como se ve el bot completo?

import asyncio
import json
import websockets
 
API_KEY = "your-api-key-here"
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",
                    "action": act,
                    "client_action_id": f"a-{msg['turn_token'][:8]}",
                    "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())

Guardalo como bot.py, reemplaza your-api-key-here con tu clave real y ejecuta python bot.py. Deberias ver output en 30 segundos una vez que otro bot entre a la cola.

Que hace realmente este bot?

Es un calling station, y fue nuestro primer bot tambien.

Cuando es tu turno: check si puedes (dinero gratis). Si no puedes hacer check, call. Si no puedes hacer call, fold. Esto pierde fichas lentamente porque estas haciendo call en todas las apuestas sin considerar la fuerza de la mano. Pero juega poker legal, se queda en la mesa y te da un event loop completo para construir encima.

Los cuatro conceptos que vale entender:

set_auto_rebuy le dice al servidor que haga rebuy automatico de 1,500 fichas cuando quiebres. Sin esto, tu bot deja de jugar despues de perder todo su stack. Con esto, el servidor maneja los rebuys (sujeto a cooldown) y tu bot sigue jugando indefinidamente.

join_lobby te pone en la cola de matchmaking. El campo buy_in establece cuantas fichas llevar a la mesa. El rango valido es de 1,000 a 5,000; usamos 2,000 por defecto, que son 100 big blinds en la estructura 10/20. Cuando hay suficientes jugadores en cola, el matchmaker crea una mesa 6-max.

turn_token es un token anti-replay. Cada mensaje your_turn incluye un token nuevo. Tienes que devolverlo en tu accion. Si mandas un token viejo de un turno anterior, la accion se rechaza. Siempre usa el token del your_turn mas reciente. Nunca lo cachees.

client_action_id es para tu propio tracking. El servidor lo devuelve en action_ack para que puedas correlacionar que accion fue aceptada. Usa un ID unico por accion; nosotros simplemente cortamos el turn token para obtener una string unica rapida.

Que mensajes WebSocket recibe tu bot?

Tu bot recibe un flujo continuo de mensajes JSON. La mayoria son informativos; solo necesitas responder a your_turn. Pero entender los otros es como construyes un bot mas inteligente. Aqui esta el conjunto completo que vas a encontrar:

MensajeQue significaRespondes?
connectedAuth exitoso, estas onlineNo
lobby_joinedEstas en la cola de matchmakingNo
table_joinedTe sentaste en una mesaNo
hand_startNueva mano empezando, tu asiento y el dealerNo
hole_cardsTus dos cartas privadas (ej.: ["Ah", "Kd"])No
your_turnTus acciones validas, el pot, el boardSi: envia una accion
player_actionAlguien (quizas tu) actuoNo
community_cardsFlop, turn o river repartidosNo
hand_resultMano termino, quien ganoNo
bustedTe quedaste sin fichasNo (auto-rebuy lo maneja)
table_closedMesa cerroVolver al lobby
season_endedTransicion de seasonVolver al lobby

La referencia completa de mensajes esta en docs.openpoker.ai/api-reference/message-types. Cada campo de cada mensaje esta documentado con ejemplos JSON. Vale la pena guardarlo en favoritos; lo vas a consultar todo el tiempo.

Haciendolo mas inteligente: tres mejoras rapidas

El calling station pierde alrededor de 2-3 big blinds cada 100 manos. Tres cambios lo mejoran inmediatamente, ordenados por impacto.

1. Fold en manos malas pre-flop

La mayoria de las manos iniciales en poker son perdedoras. Fold en el 60% peor antes del flop y ya estas adelante de todos los calling stations de la plataforma. La seleccion de manos iniciales es la mayor mejora que puedes hacer.

def should_play(cards):
    """Return True for top ~40% of starting hands."""
    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 high >= 10: return True              # Any two broadway
    if high >= 9 and suited: return True    # Suited connectors 9+
    if high == 12 and low >= 7: return True # A7+
    return False

Guarda tus hole cards cuando recibas hole_cards, luego verifica should_play() en tu handler de your_turn. Fold en todo lo demas pre-flop.

2. Raise en tus manos fuertes

El calling station nunca hace raise. Esto significa que los oponentes ven flops baratos contra ti en cada mano. Solucion: raise con tu 15% mas fuerte de manos pre-flop.

if "raise" in actions and should_raise(my_cards):
    await ws.send(json.dumps({
        "type": "action",
        "action": "raise",
        "amount": actions["raise"]["min"],  # minimum raise
        "client_action_id": next_id(),
        "turn_token": msg["turn_token"],
    }))

La entrada raise en valid_actions te dice los montos exactos de min y max. El campo amount es un monto de raise-to (tamano total de la apuesta), no un incremento. Si el big blind es 20 y quieres hacer raise a 60, envia "amount": 60.

3. Usa pot odds post-flop

Despues del flop, tienes informacion real. Las pot odds te dicen si hacer call es matematicamente correcto: si el precio que estas pagando es menor que tu probabilidad de ganar, call. Si no, fold. Para la matematica completa, la entrada del glosario de pot odds tiene ejemplos resueltos y trampas que atrapan a bots principiantes.

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

Incluso una estimacion aproximada de tu probabilidad de ganar (30% por defecto, mas alta con top pair, mas baja sin nada) combinada con pot odds le gana al calling station puro por un margen amplio. El mensaje your_turn incluye el tamano actual del pot, asi que tienes todo lo que necesitas.

Que aprendimos corriendo este bot

Corri el calling station por mas de 1,200 manos para obtener un baseline real. Perdio 2.4 big blinds cada 100 manos — no catastrofico pero un drenaje constante. La fuga mas grande no era hacer call en demasiadas apuestas. Era hacer call en apuestas del river sin nada. El calling station no tiene el concepto de "no le pegue a nada y esta apuesta es grande en relacion al pot"; simplemente hace call, cada vez, y sangra.

Lo segundo que me sorprendio: los cooldowns de auto-rebuy importan mas de lo que piensas. Despues de quebrar, hay un cooldown de 5 minutos en el plan gratuito (2 minutos en Pro) antes del siguiente rebuy. Un bot que quiebra frecuentemente pasa mucho tiempo sentado afuera. Acertar el manejo del stack (no quebrar en primer lugar) tiene retornos compuestos mas alla de solo conservar fichas.

Agregar should_play() de la seccion anterior bajo la tasa de perdida a alrededor de 0.8 bb/100 en nuestras pruebas — una mejora de 3x con una sola funcion. El bot sigue perdiendo, pero ahora pierde como un jugador mediocre en vez de uno roto. Ese es el punto de partida para el trabajo real de estrategia.

No estamos diciendo que estos son tamanos de muestra rigurosos. La varianza en 6-max es alta, y 1,200 manos es una ventana pequena. Pero direccionalmente, el patron es consistente: la seleccion pre-flop es la primera palanca, la agresividad post-flop es la segunda.

Que esperar en el leaderboard

Con el calling station base, vas a terminar al fondo del leaderboard. Agrega las tres mejoras de arriba y te ubicaras en el medio. Para llegar arriba, vas a necesitar evaluacion de manos, modelado de oponentes, manejo de stack y conciencia posicional. El camino completo esta documentado en el plan de 7 dias para el leaderboard.

Tu bot necesita al menos 10 manos para aparecer en el leaderboard. Con juego continuo y auto-rebuy activado, llegas ahi en pocos minutos.

La documentacion completa de la plataforma esta en docs.openpoker.ai. La guia de acciones y estrategia cubre semantica de raise, turn tokens y comportamiento de timeout en detalle. La documentacion de la biblioteca websockets vale la pena leerla si quieres manejo de conexion async mas alla de lo basico mostrado aqui.

FAQ

Mi bot se conecta pero nunca se sienta en una mesa. El matchmaker necesita 2+ jugadores en la cola. Si nadie mas esta jugando, tu bot espera. Corre dos bots con API keys diferentes, o revisa el leaderboard para ver si otros estan activos.

Recibo errores action_rejected. Verifica que estes incluyendo turn_token del mensaje your_turn mas reciente. Tokens viejos son la causa #1 de rechazos. No cachees el token entre turnos.

Mi bot se desconecto y perdio su asiento. Tienes 120 segundos para reconectar. Si reconectas a tiempo, tu asiento se preserva. Despues de 120 segundos, tu stack vuelve a tu saldo y necesitas volver al lobby.

Puedo correr este bot 24/7? Si. Activa auto-rebuy y maneja table_closed + season_ended volviendo al lobby. El bot de este post hace ambas cosas. Lo hemos corrido por periodos de varios dias sin ninguna intervencion.

Cuanto deberia comprar de buy-in? El rango valido es de 1,000 a 5,000 fichas. Usamos 2,000 en los ejemplos (100 big blinds con blinds 10/20), que es un monto estandar de deep-stack. Comprar menos (1,000) reduce varianza pero tambien limita cuanto puedes ganar en una sola mano. Comprar mas (5,000) esta bien cuando tu bot tiene una estrategia basica de fold/raise; no lo hagas con un calling station puro.


Listo para correr tu primer bot? Registrate para una API key y estaras jugando manos en cinco minutos. El calling station es un buen punto de partida; todos los bots competitivos del leaderboard empezaron de manera similar.

Seguir Leyendo