1 de novembro de 2026 · investigação

Como aquecer um backtest sem contar o lookback como desempenho?

Como aquecer um backtest sem contar o lookback como desempenho?

Um Donchian de 20 dias parece inofensivo numa especificação. O agente escreve um máximo móvel de 20 barras, o backtest começa na primeira linha do ficheiro parquet, e nas duas primeiras semanas o «máximo de 20 dias» é apenas o máximo acumulado das barras que existem. No dia quatro é um máximo de quatro dias. A estratégia que se pensava estar a testar não é a que produziu a primeira dúzia de fills.

Tenho um notebook com barras diárias de ETHUSDT em que o Sharpe da amostra completa é 1.4. Corto as primeiras 20 sessões e cai para 0.6. Mantenho essas 20 e deito fora o resto do primeiro ano, e imprime 3.1. Ninguém fez leak do amanhã. A estratégia usou o passado, só que não o suficiente, e o relatório tratou esses trades incompletos como evidência.

1.4Sharpe da amostra completa, janela incompleta incluída
0.6o mesmo código após 20 sessões completas
3.1Sharpe se ficarmos só com os trades de burn-in

Deixar a janela negociar enquanto ainda está a encher

O estrago habitual é min_periods=1. O Pandas calcula uma média móvel numa única barra se o deixarmos. Os agentes fazem isto constantemente, porque um NaN no topo do frame parece um bug, e preenchê-lo faz o unit test ficar verde.

Um alvo de vol realizada de 20 dias com duas observações de retorno é uma explosão de tamanho. A variância de dois números é um cara ou coroa, inverte-se, e a primeira posição é várias vezes o risco pretendido. Um z-score contra um desvio-padrão quase zero faz o mesmo truque com um sinal: a estratégia parece ter uma entrada à navalha que nunca mais aparece quando a janela é honesta.

Os breakouts são piores, porque parecem a regra a sério. Um canal de 20 barras na barra seis é um canal de seis barras. Apanha-se um cacho de trades logo no início, muitas vezes num troço calmo que não teria disparado o indicador completo. Mercados calmos derivam um pouco. Um canal apertado dispara. A curva de equity ganha uma vantagem à partida que nenhum ano posterior repete.

Zero-fill e forward-fill inventam uma mentira diferente. RSI a 0 lê-se como sobrevendido. Um ATR em falta de 0 rebenta o tamanho da unidade, e o backtest, cumpridor, compra um armazém. Prefiro que um NaN mate a ordem a que um 0 invente uma.

Ainda me apanho a plotar a partir da linha 0 porque um mês em branco à esquerda do gráfico parece inacabado. O mês em branco é a parte honesta.

Recortar a curva de equity, manter a posição

Este sobrevive ao code review. Calculam-se as features de 20 dias como deve ser, eliminam-se as primeiras 20 linhas da curva plotada, e publica-se a partir de 21 de janeiro. A posição de 21 de janeiro foi aberta a 14 de janeiro. O high-water do trailing stop, a contagem da pirâmide, o cash depois daqueles burns: tudo isto entrou na amostra «limpa».

O estrago é uma estratégia de paper que não pode ser iniciada na data do artigo. Reinicia-se a flat na data de início reportada e as ordens da primeira semana não coincidem. Às vezes o backtest já está num trade que o sistema de paper não tem razão para entrar. Às vezes o sistema de paper entra porque o lookback está frio, e o backtest fica de fora porque o mês escondido já apanhou o breakout. Dois livros de abertura, uma data de início publicada.

Os folds de walk-forward fazem isto em silêncio. Cada janela de teste tem uma cauda de lookback que não se plota. Se se saltar a simulação dessa cauda, os primeiros trades de teste voltam a ser trades de janela incompleta. Se se simular e reportar só os dias de teste, a posição do dia de teste está condicionada a fills que não se mostram. Essa segunda versão pode ser uma escolha de investigação legítima. Chamar cold start à primeira manhã do fold, enquanto um trailing stop já está vivo a partir da cauda, é assim que dois investigadores tiram dois Sharpes de uma config.

Se reiniciar a flat na data de início publicada muda o P&L, o aquecimento está no track record. Os dados de lookback podem estar presentes. Os trades de lookback não.

Aquecer em dias de calendário quando a feature não é um dia

«Dá-lhe 30 dias» deixa a feature subespecificada. Trinta dias de calendário num Donchian de 5 minutos são milhares de barras para além de um lookback de 20 períodos. Trinta dias numa feature diária que precisa de 20 sessões fica folgado ou curto, conforme fins de semana e buracos.

Um z-score da taxa de funding num dos nossos venues de perps levou um aquecimento de 30 dias porque a especificação dizia 30 períodos e alguém traduziu períodos para calendário. O funding ali imprime de oito em oito horas. Trinta dias são cerca de 90 settlements. Trinta períodos são dez dias. Os dois meses extra de burn-in coincidiram com uma semana de depeg. Tirá-los fez a janela live parecer mais calma do que a história real da estratégia. As pessoas culparam a sensibilidade à data de início. O aquecimento tinha comido o regime.

E cripto versus equity faz o mesmo número mudar de significado sem ninguém editar um parâmetro. Vinte «dias» de ETH incluem sábados. Vinte sessões de equity são quase um mês de calendário. Copia-se um lookback de 20 dias de um notebook de ações para velas horárias de perpétuos e fica-se com um canal de 20 horas com um nome de 20 dias. A primeira barra válida fica então ou 20 horas depois, ou 20 dias depois se alguma função posterior fizer resample, e já vi os dois no mesmo diff do agente.

Fixar o primeiro timestamp negociável

O aquecimento é um requisito de dados, não uma amostra extra. Cada feature indica o número de observações completas de que precisa, nas unidades em que é calculada. O primeiro timestamp negociável é a primeira barra em que todas essas condições são verdadeiras e uma conta a flat teria tido autorização para enviar uma ordem.

FeatureO que a especificação costuma dizerO que realmente tem de existirSubstituto silencioso
Donchian de 20 dias20 máximos diários20 sessões completasMáximo acumulado com min_periods=1
vol realizada de 30 diasjanela de 30 dias30 retornos close-to-closeVariância de dois dias, invertida em tamanho
z-score de funding de 20 prints20 dias20 settlements de funding20 dias de calendário (~90 prints), ou 20 barras do timeframe errado
RSI de 14 períodos em 5m14 períodos14 barras de cinco minutos fechadas14 dias, ou 14 barras com buracos em forward-fill

O P&L antes desse timestamp fica de fora do track record. O estado antes desse timestamp pode ainda precisar de ser simulado, para que um trailing stop ou um cooldown seja real quando o relógio chega à primeira barra negociável, mas esses fills não entram no Sharpe, na contagem de trades, nem na matemática de capacidade. Depois corre-se o teste feio: reiniciar a flat nesse timestamp, com o lookback disponível apenas como dados. Se as ordens mudarem, estavam-se a enviar trades escondidos.

O paper trading começa no mesmo contrato. Cada janela de teste walk-forward também. Se o gráfico parecer estar a faltar um mês, deixe-se em falta.

backtestingengenharia de dadoswalk-forwardagentes de IApaper trading
← Todos os artigos