Um backtest Python precisa de cadeia verificável: dados, informação disponível naquele momento, pedidos, execuções e registo reconciliado. Guarde identificadores além dos timestamps. Uma curva rápida não revela se usou publicação posterior, vela incompleta ou preço não permitido pelo modelo de execução.

Escolha ambiente pela pergunta

O tester MT5 suporta EAs multimoeda, testes e otimização; Python não é fuga obrigatória de um limite de um par. Python oferece outra organização de dados e cálculos. Compare contratos, informação e execução pretendidos. Quando investigar diferenças, mantenha dataset e regras congelados iguais, antes de atribuir uma divergência à linguagem.

Guarde dados e significado

Registe instrumento e produto, fornecedor, fuso, lado da cotação, intervalo e período descarregado. Confira IDs repetidos, ordem e lacunas. Encerramento do mercado não é automaticamente corrupção; preencher vazio pode inventar observações. Preserve ficheiro original e transformação separada.

MetaTrader5.copy_rates_range devolve time, OHLC, tick_volume, spread e real_volume, não tarifa histórica completa de comissão ou swap. História depende do terminal e definições; pedir intervalo não demonstra recebê-lo inteiro. Argumentos temporais e dados usam UTC. Para sessões portuguesas, converta explicitamente o fuso relevante, sem tratar texto pt-PT como hora de servidor.

pandas e NumPy apoiam cálculos. Backtrader organiza eventos; vectorbt atualiza estado de caixa e ativos e dispõe de modos de ordens, sinais e função personalizada. O rótulo vetorizado não torna todas as execuções independentes do estado anterior. Escolha conjunto mínimo útil, guarde versões, licenças, direitos dos dados e ambiente. Dados e operação posterior podem ter custos separados; nenhuma biblioteca garante rapidez fixa ou realismo automático.

Sem índice, o sinal pode mudar de registo

Modelo original com três preços completos fictícios e IDs únicos: A 100, B 102, C 104. Série de flags em ordem C 1, A 0, B 0. O 1 identifica apenas candidato para modelação posterior, não ordem ou preço de execução. Alinhamento por etiquetas em prices * flags dá A 0, B 0, C 104. Converter ambos em arrays e multiplicar por posição dá [100; 0; 0]; atribuir resultado a A, B, C faz A parecer candidato.

Etiqueta C ou primeira posição?Preços fictícios A:100; B:102; C:104. Flags em ordem C:1; A:0; B:0. Sem custos ou resultado financeiro.EXEMPLO DE CÁLCULOPor etiquetaC →104Por posição sem índicePrimeira linha →100Antes da execuçãoConfirmardisponibilidade
Etiqueta C ou primeira posição?. Preços fictícios A:100; B:102; C:104. Flags em ordem C:1; A:0; B:0. Sem custos ou resultado financeiro.

Igual comprimento não comprova correspondência de registos.

Por etiqueta
C →104 – Flag 1 pertence a C
Por posição sem índice
Primeira linha →100 – A recebe indevidamente a primeira flag
Antes da execução
Confirmar disponibilidade – Alinhamento não prova causalidade ou fill

Confira IDs antes de to_numpy(), não apenas comprimentos. Coincidir etiquetas ainda não prova disponibilidade do sinal a tempo. O exemplo não tem custos ou resultado financeiro; demonstra atribuição de registo. IDs ausentes e duplicados precisam de controlo separado.

Disponibilidade antes de ordem

Uma vela H1 marcada 10:00 pela abertura só tem OHLC completo quando o período acaba. Em resampling pandas, closed define pertença ao intervalo e label a etiqueta da borda. Mudar etiqueta não antecipa disponibilidade. Junte indicadores macro pela publicação da versão disponível, não só pelo mês descrito. merge_asof exige chaves ordenadas; backward escolhe anterior ou igual, nearest pode escolher futuro. Nenhuma opção conhece revisões posteriores; defina tolerância e ordem de eventos com mesmo timestamp.

Teste original UTC: decisão 10:04, publicações guardadas 10:00 com valor 50 e 10:05 com 60. Sem tolerância, backward escolhe 50, quatro minutos antes. Nearest escolhe 60, a um minuto mas no futuro. Tolerância backward inclusiva de dois minutos não encontra valor. Marque ausente; substituir pelo futuro mais próximo muda a informação disponível.

Receita separada de velas completas: primeiras vinte têm máximos 100 a 119, cada Open=High −0.5, Low=High −2 e Close=High −1. Vela 21: abertura 120, máximo 121, mínimo 118 e fecho 120,5; vela 22: abertura 120,6, máximo 122, mínimo 119 e fecho 121. São preços arbitrários, não cotações Forex. O código técnico conserva ponto decimal e nomes de campos:

previous_high = bars["high"].shift(1).rolling(20).max()
signal = bars["close"] > previous_high
next_bar_signal = signal.shift(1, fill_value=False)

Na vela 21, máximo anterior 119 e fecho 120,5 tornam condição verdadeira. Incluir High atual torna limiar 121 e condição falsa. A última linha coloca o sinal observado na vela 22, sem fornecer fill, aceitação de ordem ou saída. Use apenas entradas completas e defina separadamente volume, ordem e sequência de eventos.

Sinal, execução, spread e encargos

No modelo padrão documentado Backtrader, Market submetida depois de processar a vela usa abertura da próxima disponível. Outras definições alteram comportamento. Se stop e alvo estão dentro da mesma vela, OHLC não revela qual ocorreu primeiro. Registe explicitamente a hipótese, em vez de escolher sempre a saída favorável.

Modelo original: compra 10000 EUR ao Ask atribuído 1,1002, com Bid 1,1000; venda posterior integral ao Bid 1,1012, Ask 1,1014. Pip 0,0001 USD por EUR. Diferença de fills de dez pips vale 10 USD. Comissão de 1 USD em cada lado deixa 8 USD. Financiamento e slippage adicional são zero neste exercício. Deduzir outra vez dois pips de spread à entrada daria 6 USD, contando diferença já incorporada nos preços.

Contraprova própria EUR: suponha conversão fixa atribuída 1,10 USD/EUR nos dois momentos, sem taxa adicional. Os 8 USD líquidos equivalem a 8/1,10≈7,27 EUR, não 8 EUR. Se, num cenário alternativo, a comissão for 1 EUR por lado, os 10 USD brutos dão 10/1,10−2≈7,09 EUR líquidos. A moeda da comissão faz diferença mesmo com fills iguais. Estes cenários não descrevem tarifas ou conversão reais.

Especifique financiamento, conversões, contrato, margem e pedidos rejeitados do produto. Em várias posições, modele caixa partilhada, margem disponível e ordem dos pedidos simultâneos. Somar curvas independentes pode incluir posições impossíveis de financiar em conjunto. Slippage aleatório também exige distribuição, semente e versão.

Registo contabilístico e estado de posição

Exemplo original com mesmo valor monetário de R: quarenta ganhos +2 R e sessenta perdas −1 R dão 80 R positivos, 60 R negativos, 20 R líquidos, PF 80/60≈1,33 e média 0,2 R. Custo 0,1 R em todas as cem operações muda resultados para quarenta +1,9 R e sessenta −1,1 R: ganhos 76 R, perdas 66 R, total 10 R, PF 76/66≈1,15, média 0,1 R. É aritmética atribuída, não backtest real.

Contraprova original de reentrada: condições em cinco velas são verdadeiro, verdadeiro, verdadeiro, falso, verdadeiro. Ambas as políticas entram na 1; stop encerra na 2 antes da avaliação de entrada, sem outras saídas posteriores. «Entrar sempre que sem posição e verdadeiro» reentra na 2. «Exigir novo falso para rearmar» espera nas 2 e 3, rearma na 4 e entra na 5. Ambas contam duas entradas, em momentos diferentes. Esta máquina de estados é nossa, não comportamento padrão atribuído a uma biblioteca.

Preserve equity de posições abertas e resultados encerrados. Inclua capital inicial nos picos de drawdown; separe depósitos e levantamentos do retorno. Não acrescente Sharpe ou outra estatística que não consiga reconstruir de registo e série datados.

Seleção e dados reservados são evidências distintas

Fixe janelas cronológicas de desenvolvimento e teste antes de escolher regras. Guarde instrumentos, filtros, parâmetros e divisões tentados, incluindo rejeitados. Poucos parâmetros não significam poucas hipóteses. O estudo de Bailey e coautores aborda seleção repetida e overfitting; não calculamos PBO destes modelos fictícios.

Noutro conjunto atribuído de cem operações, 75 ganhos +0,2 R e 25 perdas −1 R têm 75% de acerto e perdem 10 R antes de custos: 15 R positivos, 25 R negativos, PF 0,6. Acerto alto não diagnostica um bug. Examine causalidade, observações, dependência, execução, custos e sensibilidade, sem limiares universais para declarar look-ahead ou overfitting.

Três ações num projeto sem ordens reais

  1. Crie projeto isolado, dados originais com IDs, fonte, UTC, lado e versões. Este exercício offline não exige credenciais reais nem envio de ordem.
  2. Reproduza poucos registos, anotando quando o sinal ficou disponível, evento executável e tratamento de revisão ou ausência. Declare reentrada, acumulação e rearmamento; confira IDs esperados.
  3. Reconcilie cada fill e custo antes de produzir métricas. Conserve variantes, janelas reservadas e limitações. Compare pressupostos alternativos no mesmo conjunto congelado e continue em walk-forward, sem atribuir causa a uma queda percentual fixa.