Pular para o conteúdo
[OPEN_POKER]

Construa seu primeiro bot de pôquer em Python

JJoão Carvalho||Atualizado |13 min de leitura

Aula 1 de 13: Conectar

Complete a primeira mão acompanhando a execução do bot. Python 3.11 ou superior, um terminal e uma chave de API do bot para jogar online. Os testes locais não exigem conta.

Comece com um cliente Python pequeno que se conecta ao Open Poker e responde às ações legais enviadas pelo servidor. Completar sua primeira mão é o objetivo desta lição; a estratégia vem depois.

Início do curso: baixe o checkpoint da lição acima para acompanhar a evolução do bot do curso. O cliente curto abaixo explica o loop de conexão. Mantenha o guia completo de construção aberto como referência.

O que você realmente precisa para começar?

Use Python 3.11 ou superior no curso. O cliente curto abaixo precisa de uma biblioteca:

python -m pip install "websockets>=14,<16"

É só isso. Você não precisa instalar SDK, framework ou mecanismo de jogo. Mantivemos o protocolo deliberadamente simples: seu bot se conecta por WebSocket, recebe o estado do jogo como mensagens JSON e envia as ações de volta como JSON. Se você consegue interpretar um dicionário, consegue construir um bot.

Você também precisará de uma chave da API de bots do Open Poker: entre, selecione seu bot e escolha Self Host. Armazene a chave em OPEN_POKER_API_KEY como variável de ambiente. Consulte o guia de registro. Mantenha as credenciais fora do código-fonte e de capturas de tela compartilhadas.

Esta lição usa mensagens WebSocket diretamente para que você possa ver o protocolo. Durante o aprendizado, registre os tipos de mensagem e os códigos de erro; evite publicar payloads brutos que contenham credenciais ou cartas privadas.

Como é o bot completo?

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

Salve-o como bot.py, defina OPEN_POKER_API_KEY como variável de ambiente e execute python bot.py. Uma conexão bem-sucedida imprime o nome do seu bot. Sentar-se e concluir uma mão depende da disponibilidade de outros bots. Este exemplo curto para quando ocorre uma desconexão; consulte as lições de confiabilidade antes de deixar um bot sem supervisão.

O que este bot realmente faz?

Ele é uma calling station, e também foi nosso primeiro bot.

Quando chega sua vez: dê check se puder (dinheiro grátis). Se não puder dar check, pague. Se não puder pagar, desista. Isso perde fichas lentamente porque você paga todas as apostas sem considerar a força da mão. Ainda assim, ele joga pôquer legalmente, permanece na mesa e oferece um loop completo de eventos sobre o qual você pode construir.

Os quatro conceitos que vale entender:

set_auto_rebuy diz ao servidor para recomprar automaticamente 1.500 fichas quando você quebrar. Sem isso, seu bot para de jogar depois de perder seu stack. Com isso, o servidor cuida das recompras (sujeitas a um intervalo) e seu bot continua indefinidamente.

join_lobby coloca você na fila de matchmaking. O campo buy_in define quantas fichas levar para a mesa. O intervalo válido é de 1.000 a 5.000; usamos 2.000 por padrão, que equivalem a 100 big blinds na estrutura de blinds 10/20. Quando há jogadores suficientes na fila, o matchmaking cria uma mesa 6-max.

turn_token é um token antirrepetição. Cada mensagem your_turn inclui um token novo. Você precisa devolvê-lo na ação. Se enviar um token antigo de um turno anterior, a ação será rejeitada. Use sempre o token do your_turn mais recente. Nunca o armazene em cache.

hand_id identifica a mão atual. Devolva-o junto com o token da mesma mensagem your_turn.

client_action_id identifica uma tentativa de ação. O servidor o devolve em action_ack; este exemplo usa um UUID. O código de recuperação precisa preservar a identidade da tentativa ao resolver uma confirmação incerta.

Quais mensagens WebSocket seu bot trata?

Seu bot recebe um fluxo contínuo de mensagens JSON. A maioria é informativa; você só precisa responder a your_turn. Mas entender as outras é o que permite construir um bot mais inteligente. Este é o conjunto completo que você encontrará:

MensagemO que significaVocê responde?
connectedAutenticação bem-sucedida; você está onlineNão
lobby_joinedVocê está na fila de matchmakingNão
table_joinedVocê está sentado em uma mesaNão
hand_startUma nova mão começa; aqui estão seu assento e o dealerNão
hole_cardsSuas duas cartas privadas (por exemplo, ["Ah", "Kd"])Não
your_turnSuas ações válidas, o pote e a mesaSim: envie uma ação
player_actionAlguém (talvez você) agiuNão
community_cardsFlop, turn ou river distribuídoNão
hand_resultA mão terminou; aqui está quem venceuNão
bustedVocê ficou sem fichasNão (a recompra automática cuida disso)
table_closedA mesa foi encerradaVolte ao lobby
season_endedTransição de temporadaVolte ao lobby

A referência completa de mensagens está em docs.openpoker.ai/api-reference/message-types. Cada campo de cada mensagem é documentado com exemplos JSON. Vale salvar nos favoritos; você consultará essa página o tempo todo.

Como deixá-lo mais inteligente: três ganhos rápidos

A calling station é uma linha de base de conectividade. Quando a conexão funcionar, experimente estas três estratégias e meça os efeitos em vez de presumir uma taxa de vitória específica.

1. Adicione um filtro pré-flop simples

A maioria das mãos iniciais do pôquer perde. Um filtro pré-flop simples que desiste dos 60% inferiores antes do flop coloca você à frente de qualquer calling station da plataforma. A seleção de mãos iniciais é a maior melhoria isolada que você pode fazer.

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

Armazene suas cartas fechadas ao receber hole_cards e depois verifique should_play() no manipulador de your_turn. Com uma mão excluída, veja se essa ação é gratuita e legal; caso contrário, desista somente quando fold estiver em valid_actions.

2. Aumente com suas mãos fortes

A calling station nunca aumenta. Isso permite que os adversários vejam flops baratos contra você em todas as mãos. A correção: aumente com os 15% mais fortes das mãos pré-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"],
    }))

A entrada raise em valid_actions informa exatamente os valores min e max. O campo amount é um valor raise-to (tamanho total da aposta), e não um incremento. Se o big blind for 20 e você quiser aumentar para 60, envie "amount": 60.

3. Use pot odds no pós-flop

Depois do flop, você tem informação real. As pot odds dizem se pagar é matematicamente correto: se o preço que você paga for menor que sua probabilidade de vencer, pague. Caso contrário, desista. Para a matemática completa, a entrada do glossário sobre pot odds traz exemplos resolvidos e armadilhas que confundem bots iniciantes.

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

Até uma estimativa aproximada da sua probabilidade de vitória (30% por padrão, mais alta com top pair e mais baixa sem nada), combinada com pot odds, supera a calling station pura por uma margem ampla. A mensagem your_turn inclui o tamanho atual do pote, então você tem tudo de que precisa.

O que aprendemos executando este bot

Executei a calling station por mais de 1.200 mãos para obter uma linha de base real. Ela perdeu 2,4 big blinds a cada 100 mãos: não é catastrófico, mas é uma drenagem constante. O maior vazamento não era pagar apostas demais. Era pagar apostas no river sem nada. A calling station não entende “errei tudo e esta aposta é grande em relação ao pote”; ela simplesmente paga, sempre, e vai sangrando fichas.

A segunda coisa que me surpreendeu: os intervalos das recompras automáticas importam mais do que você imagina. Depois de quebrar, há um intervalo de 5 minutos no plano gratuito (2 minutos no Pro) antes da próxima recompra. Um bot que quebra com frequência passa muito tempo ausente. Acertar o gerenciamento do stack (não quebrar em primeiro lugar) traz retornos cumulativos além de simplesmente conservar fichas.

Adicionar should_play() da seção acima reduziu a taxa de perda para cerca de 0,8 bb/100 nos nossos testes, uma melhoria de 3 vezes com uma única função. O bot ainda perde, mas agora perde como um jogador medíocre, em vez de como um jogador quebrado. Esse é o ponto de partida para um trabalho de estratégia de verdade.

Não estamos afirmando que estas são amostras rigorosas. A variância em 6-max é alta, e 1.200 mãos representam uma janela pequena. Mas, direcionalmente, o padrão é consistente: a seleção pré-flop é a primeira alavanca; a agressividade pós-flop é a segunda.

Como reproduzir a linha de base de 1.200 mãos?

Trate a execução de 1.200 mãos da calling station como uma linha de base de engenharia, não como um indicador de lucratividade. O resultado registrado foi de -2,4 bb/100. O resultado posterior com filtro pré-flop ficou em cerca de -0,8 bb/100, mas essa execução não preservou metadados suficientes para uma comparação direta limpa. Publicamos essa limitação porque um número sem seu método é marketing, não evidência.

Para uma comparação reproduzível, fixe a revisão do bot e registre estes campos em cada execução:

CampoPor que pertence ao benchmark
Commit do Git e hash da configuraçãoComprova qual política produziu as ações
Horário UTC de início e fimExpõe diferenças de campo e disponibilidade
IDs das mãos concluídasTorna a amostra auditável e evita contagem dupla
Big blinds ganhados ou perdidos por 100 mãosNormaliza resultados entre níveis de blinds
Contagem de action_rejectedDetecta erros de protocolo disfarçados de perdas de estratégia
Timeouts de turno e reconexõesSepara qualidade das decisões de falhas de execução
Número de adversários e distribuição dos assentosMostra se uma mesa dominou o resultado

Execute a linha de base e o candidato com a mesma quantidade mínima de mãos, mantenha as duas listas brutas de IDs de mão e informe intervalos de confiança antes de afirmar que houve uma melhoria real. Com 1.200 mãos, o resultado é útil para encontrar vazamentos óbvios, como pagar apostas no river sem avaliar a situação. Não é suficiente para classificar estratégias de pôquer.

Painel do agente Open Poker mostrando lucro líquido, uma mesa atual e resultados mão a mão

Captura de tela do produto de primeira parte feita em 10 de março de 2026. Esta é a interface de auditoria de resultados, não a execução de 1.200 mãos da calling station. IDs de mão e resultados por mão são a trilha de evidências que um benchmark deve conservar.

O que esperar da tabela de classificação

A calling station básica é um teste de conectividade, não uma estratégia competitiva. Adicionar as três melhorias remove vazamentos óbvios, mas nenhuma posição específica na tabela de classificação resulta delas. O campo muda a cada temporada e amostras curtas são ruidosas. Para continuar melhorando, adicione avaliação de mãos, modelagem de adversários, gerenciamento de stack e consciência de posição; depois meça cada alteração contra uma linha de base fixada.

Seu bot precisa de pelo menos 10 mãos para aparecer na tabela de classificação. O tempo necessário depende da disponibilidade das mesas e da velocidade de jogo.

A documentação completa da plataforma está em docs.openpoker.ai. O guia de ações e estratégia detalha a semântica de raise, tokens de turno e comportamento de timeout. A documentação da biblioteca websockets vale a leitura se você quiser lidar com conexões assíncronas além do básico mostrado aqui.

Perguntas frequentes

Meu bot se conecta, mas nunca consegue um assento. O matchmaking precisa de 2 ou mais jogadores na fila. Se ninguém mais estiver jogando, seu bot espera. Consulte a tabela de classificação para ver se há outros ativos; não registre agentes de produção independentes extras só para preencher um segundo assento.

Recebo erros action_rejected. Verifique o código de rejeição e confirme que hand_id e turn_token vêm da mesma mensagem your_turn atual. Não reutilize a autoridade de um turno antigo.

Meu bot se desconectou e perdeu o assento. Você tem 120 segundos para se reconectar. Se voltar a tempo, seu assento é preservado. Depois de 120 segundos, seu stack retorna ao saldo e você precisará entrar novamente no lobby.

Posso executar este bot 24 horas por dia, 7 dias por semana? O exemplo curto serve para uma primeira sessão supervisionada. Jogar sem supervisão exige reconexão, recuperação de estado, tratamento de prazos e acompanhamento de confirmações. Continue até a etapa de confiabilidade antes de tentar.

Quanto devo colocar na mesa? O intervalo válido é de 1.000 a 5.000 fichas. Usamos 2.000 nos exemplos (100 big blinds em blinds 10/20), um valor inicial padrão para stacks profundos. Entrar com menos (1.000) reduz a variância, mas também limita quanto você pode ganhar em uma única mão. Entrar com mais (5.000) é aceitável quando seu bot já tiver uma estratégia básica de desistir e aumentar; não faça isso com uma calling station pura.


Depois que seu bot completar uma mão, continue para a próxima lição abaixo. Se o lobby estiver esperando, mantenha a sessão aberta para os adversários e use o checkpoint offline para verificar seu cliente enquanto isso.

Confira o resultado da aula 1

O que muda
Conecte um cliente e envie uma ação permitida.
Saída esperada
completed_hands: 1
Confira se funcionou
Espere uma mão real terminar. Um teste com dados simulados não conta como uma partida online.

Extraia o arquivo da aula, abra a pasta em um terminal e execute:

python -m pip install -r requirements.txt
python bot.py --lesson 1 --self-test
python bot.py --lesson 1 --hands 3 --report run.json

O teste usa dados simulados, sem conexão, e exibe checkpoint: passed. Para jogar online, você precisa de OPEN_POKER_API_KEY no ambiente de execução e de adversários disponíveis. Consulte o README incluído para configurar o bot e entender os limites de recuperação.

Todas as aulas do curso
  1. 1. Crie um bot de pôquer em Python
  2. 2. Arquitetura básica de um bot de pôquer
  3. 3. Como depurar erros de WebSocket no bot
  4. 4. Por que o bot fica sem tempo para agir
  5. 5. Matemática do pôquer para bots
  6. 6. Ranges por posição para bots de pôquer
  7. 7. Estratégia de apostas para bots de pôquer
  8. 8. Tutorial de PokerKit
  9. 9. Calculadora de equidade por Monte Carlo
  10. 10. Modelagem de adversários
  11. 11. Arquitetura avançada de um bot de pôquer
  12. 12. Como funciona a pontuação da classificação
  13. 13. Arquitetura profissional de um bot de pôquer

Continue Lendo