Um Donchian de 20 dias parece inofensivo numa spec. O agente escreve um máximo móvel de 20 barras, o backtest começa na primeira linha do arquivo parquet, e nas duas primeiras semanas a "máxima de 20 dias" é só o máximo acumulado das barras que existirem. No dia quatro, é uma máxima de quatro dias. A estratégia que você achava que estava testando não é a que produziu a primeira dúzia de fills.
Tenho um notebook em barras diárias de ETHUSDT em que o Sharpe da amostra completa é 1.4. Corte as primeiras 20 sessões e ele cai para 0.6. Mantenha essas 20 e jogue fora o resto do primeiro ano, e ele imprime 3.1. Ninguém vazou o amanhã. A estratégia usou o passado, só que não o suficiente, e o relatório tratou aqueles trades pela metade como evidência.
Deixe a janela operar enquanto ainda está se preenchendo
O estrago usual é min_periods=1. O Pandas calcula uma média móvel numa barra só se você deixar. Agentes fazem isso o tempo todo, porque um NaN no topo do frame parece um bug, e preenchê-lo deixa o teste unitário verde.
Um alvo de vol realizada de 20 dias com duas observações de retorno é uma explosão de size. A variância de dois números é cara ou coroa, você inverte, e a primeira posição fica 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 afiada que nunca mais aparece quando a janela está honesta.
Breakouts são piores, porque parecem a regra de verdade. Um canal de 20 barras na barra seis é um canal de seis barras. Você ganha um agrupamento de trades bem no começo, muitas vezes num trecho quieto que não teria disparado o indicador pronto. Mercados quietos derivam um pouco. Um canal apertado dispara. A curva de equity ganha uma vantagem inicial que nenhum ano posterior repete.
Zero-fill e forward-fill inventam uma mentira diferente. RSI em 0 lê como sobrevendido. Um ATR ausente de 0 estoura o unit size, e o backtest, diligente, compra um galpão. Prefiro que um NaN mate a ordem a que um 0 invente uma.
Ainda me pego plotando 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.
Recorte a curva de equity, mantenha a posição
Esse sobrevive ao code review. Você calcula as features de 20 dias direito, descarta as primeiras 20 linhas da curva plotada e publica a partir de 21 de janeiro. A posição em 21 de janeiro foi aberta em 14 de janeiro. O high-water do trailing stop, a contagem da pirâmide, o caixa depois daqueles burns: tudo isso entrou na amostra "limpa".
O estrago é uma estratégia em paper que não dá para começar na data do texto. Reinicie do flat no início reportado e as ordens da primeira semana não batem. Às vezes o backtest já está num trade que o sistema de paper não tem motivo para entrar. Às vezes o sistema de paper entra porque o lookback está frio, e o backtest está de fora porque o mês escondido já pegou o breakout. Dois livros de abertura, uma data de início publicada.
Folds de walk-forward fazem isso em silêncio. Cada janela de teste tem uma cauda de lookback que você não plota. Pule a simulação dessa cauda e os primeiros trades de teste voltam a ser trades de janela inacabada. Simule e reporte só os dias de teste, e a posição do dia de teste fica condicionada a fills que você não está mostrando. Essa segunda versão pode ser uma escolha legítima de pesquisa. Chamar a primeira manhã do fold de cold start, enquanto um trailing stop já está vivo desde a cauda, é como dois pesquisadores tiram dois Sharpes de uma config.
Aqueça em dias de calendário quando a feature não é um dia
"Dê 30 dias" deixa a feature subespecificada. Trinta dias de calendário num Donchian de 5 minutos são milhares de barras além de um lookback de 20 períodos. Trinta dias numa feature diária que precisa de 20 sessões fica gordo ou magro, dependendo de fins de semana e buracos.
Um z-score de funding rate numa das nossas venues de perp ganhou um warmup de 30 dias porque a spec dizia 30 períodos e alguém traduziu períodos para calendário. O funding ali imprime a cada oito horas. Trinta dias são cerca de 90 settlements. Trinta períodos são dez dias. Os dois meses extras de burn-in coincidiram de incluir uma semana de depeg. Tirar isso 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 warmup tinha comido o regime.
E cripto versus ações faz o mesmo número mudar de sentido sem ninguém editar um parâmetro. Vinte "dias" de ETH incluem sábados. Vinte sessões de ações são quase um mês de calendário. Copie um lookback de 20 dias de um notebook de ações para candles horários de perpetual e você tem um canal de 20 horas com nome de 20 dias. A primeira barra válida fica então ou 20 horas adentro, ou 20 dias adentro se alguma função posterior faz resample, e eu já vi os dois no mesmo diff do agente.
Fixe o primeiro timestamp negociável
O warmup é um requisito de dados, não uma amostra bônus. Toda feature declara o número de observações concluídas 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 flat teria sido autorizada a enviar uma ordem.
| Feature | O que a spec costuma dizer | O que de fato precisa existir | Substituto silencioso |
|---|---|---|---|
| Donchian de 20 dias | 20 máximas diárias | 20 sessões concluídas | Máximo acumulado com min_periods=1 |
| vol realizada de 30 dias | janela de 30 dias | 30 retornos close-to-close | Variância de dois dias, invertida em size |
| z-score de funding de 20 prints | 20 dias | 20 settlements de funding | 20 dias de calendário (~90 prints), ou 20 barras do timeframe errado |
| RSI de 14 períodos em 5m | 14 períodos | 14 barras de cinco minutos fechadas | 14 dias, ou 14 barras com gaps em forward-fill |
O P&L anterior a esse timestamp fica fora do track record. O estado anterior a esse timestamp ainda pode precisar ser simulado, para que um trailing stop ou um cooldown seja real quando o relógio chega na primeira barra negociável, mas esses fills não entram no Sharpe, na contagem de trades nem na conta de capacidade. Depois rode a checagem feia: reinicie do flat nesse timestamp, com o lookback disponível só como dado. Se as ordens mudarem, você estava entregando trades escondidos.
O paper trading começa no mesmo contrato. Cada janela de teste walk-forward também. Se o gráfico parece estar faltando um mês, deixe faltar.
← Todos os artigos


