QuantAbundanciaAbundância, quantificada.
·12 min read·QuantAbundancia Research

IBKR Trader Workstation para bots sistemáticos: o mapa operacional que ninguém publica

Os docs da Interactive Brokers cobrem a API, os símbolos, os order types. Não cobrem o que realmente quebra quando você roda um bot real contra uma conta paper às 3 da manhã - janelas de re-login IBC, a armadilha de trusted-IP na porta 4002, o estado unhealthy-but-Up do gateway, o wrapper de rejeição de ordem que você precisa mas não está documentado. Eis o que aprendemos shipando bots live contra a IBKR ao longo de 12 meses.

IBKRIB GatewayTWSalgo tradingtrading sistemáticodockerAPIbots de trading

A Interactive Brokers tem documentação. Cobre as assinaturas de chamada da API, as convenções de símbolo, a matriz de order types, a semântica limit/market/bracket. O que os docs não te dizem é o que realmente quebra quando você roda um bot real contra a conta paper de produção às 3 da manhã horário de Paris numa terça, e depois faz um redeploy de uma mudança de código às 9 da manhã do dia seguinte enquanto a sessão europeia está aberta.

Aprendemos a lacuna do jeito difícil. Este artigo é o mapa operacional que gostaríamos que existisse antes de começarmos - escrito de doze meses shipando bots contra a IBKR, oito desses meses rodando 24/5 contra a conta paper, e um outage silencioso de 38 horas que nos ensinou por que o container estar Up não é a mesma coisa que o bot funcionar.

Se você está avaliando a IBKR como broker para execução sistemática, ou já está operando um e batendo em fricção que você não tem palavras para descrever, isso é para você.

A arquitetura de setup (o que roda onde)

Um stack funcional de trading sistemático com IBKR tem três peças móveis:

  1. IB Gateway (ou TWS) - o software do lado IBKR que segura a sessão de rede com os servidores deles. Gateway é a variante headless; TWS é a versão de UI desktop. Para bots, Gateway vence - não abre janela, não deriva em updates de versão de UI, e a imagem Docker gnzsnz/ib-gateway empacota todas as peças de bootstrap (IBC para login não-interativo, Xvfb para o framebuffer, o loop de restart forçado diário que a IBKR exige).
  2. Seu processo de bot - o processo Python (ou seja lá o que for) que abre uma conexão TCP ao gateway, coloca ordens, escuta fills.
  3. Estado - os arquivos JSON / SQLite que rastreiam posições, equity, métricas de risco, histórico de trades. Esses vivem FORA de ambos os processos, no filesystem do host, bind-mounted dentro do container do bot.

As três peças ficam no mesmo host. Bot conecta no Gateway via rede Docker interna. Estado vive em disco, bind-mounted. Simples em conceito; a fricção está nos detalhes.

A armadilha de trusted-IP da porta 4002

O erro mais comum da primeira semana: apontar seu bot para a porta 4002.

IB Gateway escuta em 127.0.0.1:4002 com uma allowlist hardcoded de trusted-IP de 127.0.0.1. Se seu bot conecta de qualquer outro IP - incluindo um container Docker irmão no mesmo host - o handshake TCP sucede, e então o handshake da API silenciosamente cai. Seu bot espera o timeout completo de 15 segundos do nextValidId, lança, retenta, e espera de novo.

O fix não está nos docs da IBKR. É um forwarder socat dentro do container do gateway: socat TCP-LISTEN:4004,fork TCP:127.0.0.1:4002. Seu bot conecta na porta 4004 externamente; socat encaminha para 4002 com o endereço de origem reescrito para 127.0.0.1; o gateway vê uma fonte de trusted-IP e aceita a sessão de API.

A imagem gnzsnz vem com esse forwarder pré-fiado. Se você builda sua própria imagem de gateway, precisa adicionar a camada socat você mesmo. Vimos isso tropeçar todo time que tenta rolar uma imagem de gateway custom no dia um.

(Também vale saber: a env var TRUSTED_IPS que alguns docs referenciam não está fiada no template jts.ini.tmpl nesta imagem. Não desperdice uma noite configurando isso - o caminho socat é o que funciona.)

IBC re-login = 90 segundos de downtime de API, toda vez

IB Gateway precisa relogar nos servidores IBKR a cada 24 horas - a IBKR força isso. A imagem gnzsnz lida com isso via um restart agendado do IBC (IB Controller). Da perspectiva do seu bot, isso significa que todo restart de container, todo re-login forçado noturno, toda mudança de docker compose que toca o gateway dispara ~90 segundos de downtime de API.

Seu bot precisa de uma política de retry sã. Connect timeout 15 segundos, backoff exponencial (30s / 60s / 120s), desistir depois de 5 tentativas e alertar. Vimos bots escritos sem essa suposição que caem permanentemente no primeiro restart diário e nunca auto-recuperam.

Efeito colateral para saber: docker compose up -d <bot-service> recria serviços dependentes. Porque tradfi-ibkr-bot depends_on ibkr-gateway, tocar o bot também derruba o gateway. Toda mudança de código custa 90 segundos de downtime de API. Planeje deploys de acordo.

"Existing session detected" - escolha um primário

Se suas credenciais paper estão logadas de uma segunda máquina - seu IB Gateway local no Win11, uma instância antiga de VPS, qualquer lugar - o novo gateway bate num diálogo modal: "Existing session detected. Escolha: assumir (primary) ou rodar secondary (read-only)."

Um gateway headless não consegue clicar. Sem a env var certa, ele fica no diálogo para sempre.

Configure EXISTING_SESSION_DETECTED_ACTION=primary na env do gateway. A nova sessão assume em ~30 segundos; a velha é desconectada. Esse é o default certo para um bot de produção - você quer que a instância deployada vença, não o que estiver aberto no seu laptop.

(Também: feche seu Gateway local quando não estiver usando ativamente. Mesmo com primary configurado, o flapping de reconexão desperdiça linhas de log.)

Gerenciamento de estado: posições NÃO estão nos seus arquivos

O maior ajuste de modelo mental: o positions_state.json do seu bot é um cache, não fonte de verdade. A fonte de verdade é o servidor da IBKR. Seu bot reconstrói o cache a partir de reqPositions() em todo cold start.

Por que isso importa: se seu bot crasha no meio de um trade, reinicia, e encontra uma posição em positions_state.json que não combina com o que reqPositions() retorna, confie na IBKR. Já shipamos um padrão de force-reconcile que apaga o estado local e reconstrói de reqPositions() na detecção de qualquer mismatch. É a única política sã.

Cinco arquivos de estado, todos bind-mounted do host dentro do container:

| Arquivo | Propósito | |---|---| | live_status.json | Heartbeat + equity, sobrescrito a cada ciclo. Lido pelo pusher do dashboard. | | risk_state.json | Tracking de drawdown diário, max-equity watermark. Persiste entre restarts. | | trade_vault.db | SQLite de todos os trades (abertos + fechados). Registro permanente. | | analyst_metrics.json | Breakdown de performance por estratégia. | | dynamic_pairs.json | Pares adicionados pelo processo de universe-expansion. |

Armadilha crítica de bind-mount: se o arquivo não existe no host quando docker compose up roda, o Docker cria um diretório lá, e depois se recusa a montar como arquivo. Sempre pré-toque os JSONs (echo '{}' > file.json) antes do primeiro deploy. Pule isso e você ganha erros de mount crípticos que parecem problemas de permissão.

Ordens SL/TP vivem na IBKR - não no seu bot

Isso é o que torna a IBKR genuinamente viável para execução sistemática não-atendida: stop-loss e take-profit são colocados no servidor da IBKR, não segurados na memória do seu bot. Se seu bot crasha, a posição mantém a proteção. Se seu VPS reinicia, a posição mantém a proteção. Se você perde internet por 4 horas, a posição mantém a proteção.

O padrão é: abra a posição como market ou limit; imediatamente submeta o SL e TP como filhos bracket independentes com outsideRTH=true e tif=GTC. Eles ficam na IBKR até preencherem ou você cancelar. Seu bot pode ficar offline por dias e a posição está segura.

Essa é a propriedade operacional que nos deixa rodar não-atendido overnight. Nem todo broker oferece isso - muitas venues cripto exigem que o bot segure ordens SL/TP em memória e as coloque reativamente, o que significa que um crash do bot te expõe. SL/TP do lado do broker da IBKR é uma das razões genuínas pelas quais a preferimos para tradfi.

A armadilha "unhealthy but Up" (38 horas que nunca recuperaremos)

Em maio de 2026 shipamos um postmortem sobre um outage silencioso de 38 horas: o container do gateway mostrava Up em docker ps, o bot estava rodando, mas toda chamada de API retornava not connected. O próprio TWS tinha morrido dentro do container; o PID 1 do container era o supervisor, não o TWS, então o supervisor ficou vivo e o Docker reportou o container como saudável.

A lição: um container estar Up não é a mesma coisa que a aplicação dentro estar saudável. Você precisa de um healthcheck explícito que exercite o caminho da aplicação. Para nosso IBKR gateway:

healthcheck:
  test: ["CMD-SHELL", "nc -z 127.0.0.1 4002 || exit 1"]
  interval: 60s
  timeout: 10s
  retries: 3

Isso pega o caso TWS-morto-sob-supervisor-vivo. Deployamos depois do incidente. Auto-remediation (restart on unhealthy) ainda está no backlog - queremos olhos nos primeiros eventos unhealthy antes de ligar o auto-restart.

Gotchas de roteamento de ordem

Algumas não-óbvias que batemos rodando estratégias reais:

  • Rejeição com erro EtradeOnly not supported: certos order types exigem um wrapper helper (_new_order() no nosso codebase) que tira as flags estilo e-Trade da IBKR. Sem ele, ~10% das ordens rejeitam inexplicavelmente. O fix é uma função wrapper; o bug é em não tê-lo.
  • A linha de log [10349 TIF] é puramente cosmética. A spec da API da IBKR lista 10349 como mensagem informacional, não erro. Suprima no seu filtro de erro ou você vai ser paginado por nada.
  • Drift do universo de pares: se seu bot tem um componente "Hunter" que auto-expande o universo de trading, ele às vezes vai tentar re-adicionar tickers que você baniu via audit. Usamos uma chamada apply_audit_locks(strategies, merged_pairs) pós-Hunter para limpar re-additions. Sem ela, sua blacklist silenciosamente vaza.

Paper para live: o que realmente muda

A tentação depois de 30 paper trades é virar a chave. Não vire.

Nossa política: 30+ paper trades E 3-6 meses de soak antes de qualquer dinheiro real. Os paper trades validam o wiring; o soak valida que nada estranho acontece em torno de earnings, dividendos, gaps de fim de semana, feriados, janelas de desconexão de exchange, timings de IBC re-login durante períodos voláteis. Coisas que não aparecem em 30 trades aparecem em 6 meses.

Quando você virar:

  • TRADING_MODE=paperlive
  • IBKR_PORT=40024001 (gateway live escuta em porta diferente)
  • Troque IBKR_GATEWAY_USER e IBKR_GATEWAY_PASSWORD para credenciais live
  • Compre uma subscription de market data - cerca de $30/mês para US equities em retail, mais se precisar de feeds exchange-específicos. Configure IBKR_MARKET_DATA_TYPE=1 para dado live; 3 é atrasado.
  • Se sua conta é cash sub-account (não margin): mantenha LONG_ONLY=true. O bot não deve tentar shortar. Contas cash mecanicamente não podem.

Aumente tamanho devagar. Usamos um ramp 25% → 50% → 100% em dois meses. O primeiro mês do bot em dinheiro real VAI superfar diferenças do paper - slippage de fill, partial fills, o custo real de market orders na abertura. Melhor descobrir em tamanho 25%.

Tradeoffs honestos

A IBKR é excelente para execução sistemática. Não é turnkey:

  • Você está operando IBC (o controller que lida com login não-interativo do Gateway). Tem sua própria cadência de release, bugs ocasionais, e a imagem gnzsnz fica atrás do upstream em dias-a-semanas.
  • Você está operando Docker num VPS. Se docker builder prune -f não está na sua caixa de ferramentas, esse não é seu stack ainda.
  • Você está lendo as release notes da API da IBKR para mudanças breaking. Acontecem. O ecossistema Python ib_insync ajuda mas não te imuniza.
  • Contas pessoais de não-residentes americanos não podem sacar margin cash. Vale checar seu status de residência contra a matriz da IBKR antes de fundear capital significativo.

O payoff é um dos poucos brokers onde você pode deployar execução sistemática em capital de escala retail, contra um universo global, com uma API real e um ambiente paper que genuinamente combina com live. O tier de venue cripto tem a profundidade de API mas vive offshore. O tier de broker fintech (Robinhood, Public, eToro) tem o UX mas não tem uma API real. A IBKR senta no meio e paga de volta a curva de aprendizado operacional uma vez que você passa.

Como agir concretamente

Se você está seriamente avaliando IBKR para execução sistemática:

  1. Abra uma conta paper primeiro - sem custo, com acesso completo à API desde o dia um. Abra uma conta na Interactive Brokers - foi onde começamos, é onde ainda rodamos paper. Raciocínio completo e nossos tradeoffs honestos estão na nossa página de broker.
  2. Use a imagem Docker gnzsnz/ib-gateway como ponto de partida. Não rode uma imagem de gateway custom até entender exatamente o que IBC + Xvfb + socat estão fazendo.
  3. Leia os docs "Trader Workstation API" da IBKR completos, mesmo as partes chatas sobre subscriptions de market data e violações de pacing. As partes chatas são onde mora a fricção.
  4. Cross-referencie com nossa página de stack + o argumento de acesso ao superciclo de IA para o caso editorial ao lado do operacional.

A curva de aprendizado operacional é real. O payoff também. Depois de doze meses, nossa bot fleet senta confortavelmente nos trilhos da IBKR porque a propriedade que precisávamos - SL/TP do lado do broker que sobrevive a crashes de bot, acesso global a venues de uma conta, uma API Python real, e um ambiente paper que combina com live - existe na IBKR e essencialmente em mais nenhum lugar no varejo.

Disclosure: mantemos uma relação de referral com a Interactive Brokers. Se você abre uma conta via nosso link de referral, ganhamos uma referral fee (e o programa da IBKR atualmente dá à nova conta até $1,000 em ações da IBKR - termos aplicam). Rodamos nossa própria bot fleet na IBKR independentemente do arranjo de referral - veja a página de disclosures para o conflict statement completo.

Related bubbles

Related research

Go deeper

Get the daily digest.

One email a day · alerts + bubble shifts + new research. Free during beta.

No spam. One email per day max. Pro adds Telegram trade alerts and higher AI-assistant limits.