O contexto
Trader de day trade na B3 opera com setup: uma regra de entrada e saída em Mini Índice ou Mini Dólar. Antes de arriscar dinheiro, ele quer saber como aquela regra teria se comportado no histórico.
Quase todo mundo faz isso mal. Roda no olho, olha o gráfico, lembra dos acertos e esquece dos erros. Ou monta uma planilha que leva minutos para recalcular e desencoraja testar variações.
O problema
Backtest só é útil se for rápido. Não por vaidade técnica: porque validar um setup não é rodar uma simulação, é rodar dezenas — variando stop, alvo, horário, parâmetro do indicador. Se cada rodada demora dez segundos, o usuário testa três e desiste. Se demora um piscar, ele explora de verdade.
A implementação ingênua é um laço for sobre os candles avaliando a regra a cada barra. Em Python isso é lento por natureza, e o custo cresce com o histórico. Com anos de candles de 1 minuto, o laço deixa de ser aceitável muito antes de o produto ficar interessante.
Havia também uma restrição que não é técnica: conteúdo sobre resultado de operação no mercado financeiro está sob a Instrução CVM nº 598/20. Simulação apresentada sem o disclaimer devido é problema regulatório, não detalhe de rodapé.
Decisões técnicas
Backtest vetorizado com vectorbt e NumPy, não laço sobre candles. Essa é a decisão que define o produto. Em vez de iterar barra a barra, a regra vira operação sobre arrays inteiros: sinal, entrada, saída e resultado calculados de uma vez em código compilado por baixo. O laço em Python puro é mais fácil de escrever e de ler — quem lê entende a lógica linha a linha. O vetorizado exige pensar em máscara e deslocamento de série, e é mais difícil de depurar. Vale porque muda a categoria da ferramenta: a simulação sai em menos de 100ms e testar uma variação deixa de ser uma espera. A armadilha conhecida do vetorizado é o viés de antecipação — usar informação de uma barra que ainda não fechou — e é por isso que o deslocamento de sinal é tratado com cuidado explícito, não por acaso.
Django + HTMX em vez de SPA React. A interface é formulário de parâmetros, tabela de resultado e gráfico. Uma SPA exigiria uma API para cada tela, um estado de cliente espelhando o servidor e um segundo lugar onde a lógica de exibição mora. Com HTMX, o servidor devolve o fragmento HTML já renderizado e a página troca só aquele pedaço: interatividade suficiente, com uma stack só. Se um dia entrar gráfico interativo pesado, essa escolha se reavalia.
Redis para cotação e notícia, PostgreSQL para o resto. Cotação em tempo real é dado quente, de curta duração, lido muito e reescrito o tempo todo. Colocar isso em tabela é castigar o Postgres com escrita que não precisa durar. Setup, histórico de simulação e assinatura ficam no PostgreSQL 17, que é onde durabilidade importa.
Login passwordless por link mágico. Menos atrito no cadastro e uma classe inteira de problema que some: sem senha armazenada, não há vazamento, reset nem reuso de senha fraca. O custo é depender da entrega de e-mail.
Disclaimer da CVM gerado junto com o relatório, não colado depois. O PDF sai de xhtml2pdf/reportlab com o disclaimer da Instrução 598/20 como parte do template. Conformidade que depende de alguém lembrar de incluir é conformidade que uma hora falha.
O que ficou pronto
SaaS com engine de backtest vetorizado, setups analíticos implementados (Fibo Trend MTF, Triple MA, Larry Williams 9.1, Didi Agulhada, IFR2 Connors), dimensionamento de lote e gestão de risco por operação, relatórios em PDF conformes, autenticação por link mágico e assinatura em dois planos (Free e Trader Pro). PostgreSQL 17 e Redis em Docker.
O que eu faria diferente hoje
Teria montado antes um conjunto de testes de regressão numérica: cenários com resultado conhecido, conferidos a cada mudança no engine. Otimização vetorizada é fácil de quebrar em silêncio — o número continua saindo, só sai errado.
Interface do Sistema
