
Um Bug em Bots de Trading que Está Afetando Agentes de IA
Esta não é uma biblioteca que eu construí para resolver um problema teórico.
É uma correção que eu construí porque dinheiro real estava em risco.
O bot de negociação
Eu tenho rodado um bot de momentum QQQ/TQQQ ao vivo na Alpaca Markets. Ele lê barras de 1 minuto, pontua a estrutura do mercado usando VWAP, SMA8, SMA21, SMA34 e sinais de momentum, e então entra em posições alavancadas em TQQQ (bull) ou SQQQ (bear) com base nessa pontuação.
O bot já tem lógica de tentativa embutida. Ele precisa ter — os timeouts de ACK do corretor são reais. Quando você envia uma ordem de mercado e a rede cai antes que a confirmação volte, você não sabe se foi preenchida ou não. Então o bot tenta novamente.
Aqui está o problema: se a primeira ordem realmente foi preenchida, mas a confirmação expirou, a tentativa dispara uma segunda ordem de mercado. Em um ETF alavancado de 3x, isso é uma posição dobrada que você não pretendia. Com dólares reais em jogo.
O bot já tinha um bloqueio de execução manual (EXECUTION_LOCK_SEC=15) e uma máquina de estados JSON para lidar com isso. Eu construí isso manualmente. Funcionou — na maior parte. Mas era frágil, não testado, e não era algo que eu gostaria de entregar a mais ninguém.
# O padrão antigo — tenta até 3 vezes
def place_order_with_retry(symbol, qty, side):
last_err = None
for attempt in range(1, EXIT_RETRY_COUNT + 1):
try:
return place_order(symbol, qty, side) # dispara duas vezes se a primeira expirou mas foi preenchida
except Exception as e:
last_err = e
time.sleep(EXIT_RETRY_SLEEP_SEC)
raise last_err
Aquela chamada place_order não tem memória. Se a tentativa 1 foi preenchida e a tentativa 2 dispara, você agora possui duas vezes a posição. O corretor não sabe que você não quis isso.
O sistema de apostas
Ao mesmo tempo em que eu estava construindo o bot, eu estava projetando PeerPlay — uma exchange de apostas P2P patenteada para torneios de videogame baseados em habilidades (USPTO provisório 63/914,036).
PeerPlay tem um motor de escrow, uma camada de verificação e uma camada de liquidação. A camada de verificação usa IA para confirmar os resultados das partidas. Quando um agente de verificação expira e tenta novamente, a camada de liquidação pode receber dois sinais de confirmação para a mesma partida. Dois sinais → dois pagamentos de prêmio. Um resultado de torneio, duas transferências de vencedores.
A patente protege a arquitetura. Nada na patente protege você de sua própria camada de execução disparando duas vezes.
Mesmo problema. Domínio diferente.
A extração
Eu percebi que o bot de negociação e o PeerPlay tinham modos de falha idênticos:
Agente/bot decide agir
↓
Rede expira
↓
Agente/bot tenta novamente
↓
Efeito colateral dispara duas vezes
A correção em ambos os casos é o mesmo primitivo: antes de executar uma ação irreversível, verifique se ela já foi executada. Se foi, retorne o resultado original. Se não foi, execute-a e armazene o resultado.
Isso é o SafeAgent.
from settlement.settlement_requests import SettlementRequestRegistry
registry = SettlementRequestRegistry()
# Mesmo request_id na tentativa → retorna recibo original, nunca re-executa
receipt = registry.execute(
request_id="trade:TQQQ:buy:2026-04-26T09:47:00",
action="order_buy_TQQQ",
payload={"symbol": "TQQQ", "qty": 10, "side": "buy"},
execute_fn=lambda: place_order("TQQQ", 10, "buy"),
)
A primeira chamada executa a ordem e armazena o recibo. Qualquer tentativa com o mesmo request_id retorna o recibo armazenado — o corretor nunca é chamado novamente.
Por que isso é importante para agentes de IA especificamente
O bot de negociação e o PeerPlay são sistemas determinísticos. Eles têm lógica de tentativa porque as redes são pouco confiáveis. Os agentes de IA têm o mesmo problema, mas pior — eles também têm sinais de conclusão incertos.
Quando Claude ou qualquer agente LLM chama uma ferramenta, pode:
- Receber um timeout e tentar novamente a mesma chamada
- Receber uma resposta ambígua e chamar novamente para confirmar
- Executar em um loop e reativar a mesma ação
- Ser reiniciado no meio da execução e reproduzir a partir do último ponto de verificação
Cada um desses cenários pode produzir efeitos colaterais duplicados. As estruturas de agentes (LangChain, CrewAI, n8n, chamada de função OpenAI) lidam com tentativas na camada de transporte. Nenhuma delas rastreia se o efeito colateral já aconteceu.
Essa lacuna — entre a decisão do agente e a ação irreversível — é onde o SafeAgent vive.
A máquina de estados
SafeAgent não apenas deduplica por request_id. Ele impõe um portão de finalização:
ABERTO → RESOLVIDO → EM_RECONCILIAÇÃO → FINAL → LIQUIDADO
A execução é permitida apenas a partir de FINAL. Se os sinais do agente forem ambíguos — respostas de ferramentas conflitantes, confirmações parciais, resultados incertos...
Empresas brasileiras que utilizam agentes de IA podem enfrentar problemas semelhantes de execução duplicada. A implementação de soluções como SafeAgent pode aumentar a confiabilidade e segurança das operações automatizadas, evitando perdas financeiras.

