viés de antecipação backtest como evitar
Viés de antecipação é o vazamento de dados futuros em um backtest. Veja como decisões na mesma barra, sobrevivência e dados revisados inflam resultados, e como testar isso.
Viés de antecipação é o uso, dentro de um backtest, de informações que ninguém poderia ter no momento em que a operação simulada foi colocada. A curva de equity sobe, as estatísticas parecem excelentes, e nada disso sobrevive ao contato com uma ordem real. Esta página define o viés, aborda três mecanismos que o produzem e mede cada um deles em dados reais de mercado.
O que é viés de antecipação
Um backtest é uma afirmação sobre uma decisão: neste timestamp, com esta informação, a regra teria feito isto. A afirmação só é válida quando cada dado lido pela regra já existia, em sua forma final, antes daquele timestamp. Viés de antecipação é qualquer violação dessa condição, e é silencioso. Nada em uma planilha ou script reclama quando uma linha devolve um valor carimbado com uma data posterior à decisão que ele alimenta.
Três violações cobrem a maior parte do que aparece na prática. Uma decisão que lê uma barra de preço na qual também opera. Um universo montado a partir dos nomes que ainda estão listados hoje. Um campo de dados que foi revisado após a data que carrega.
Mecanismo um: decidir em uma barra na qual você também opera
Comece com uma regra que parece inofensiva. Compre na força, ou seja, em sessões onde o fundo fecha acima de onde abriu. Codificado descuidadamente, o teste entra na abertura daquela sessão e sai no fechamento daquela sessão, enquanto a condição que ele filtra é o preço de fechamento da mesma barra. Ninguém sabe o preço de fechamento no sino de abertura.
O painel abaixo executa ambas as versões no SPY, o tracker do S&P 500, ao longo de dez anos civis. A primeira coluna é a impossível. A segunda atrasa a condição idêntica em uma única sessão, que é o mais cedo que uma conta capitalizada poderia agir sobre ela.
O SQL exato por trás de cada número
WITH bars AS (
SELECT date,
toFloat64(open) AS o,
toFloat64(close) AS c,
toFloat64(close) > toFloat64(open) AS up_day
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toDate('2015-12-01')
AND date <= toDate('2025-12-31')
),
lagged AS (
SELECT date, o, c, up_day,
any(up_day) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prior_up
FROM bars
)
SELECT toYear(date) AS year,
countIf(up_day) AS signal_days,
round(100 * avgIf(c / o - 1, up_day), 3) AS same_bar_avg_pct,
round(100 * avgIf(c / o - 1, prior_up), 3) AS lagged_avg_pct,
round(100 * (avgIf(c / o - 1, up_day) - avgIf(c / o - 1, prior_up)), 3) AS gap_pp
FROM lagged
WHERE date >= toDate('2016-01-01')
GROUP BY year
ORDER BY yearA separação não é sutil. Em 2016 a versão da mesma barra teve uma média de 0.447% por sessão qualificada, enquanto a versão atrasada teve uma média de -0.008%, um spread de 0.455 pontos percentuais por dia. Em 2025 as duas leram 0.636% e -0.03%. Com aproximadamente 140 sessões qualificadas em um ano, um spread de meio ponto percentual por sessão se compõe em uma curva de equity que nenhuma conta real jamais imprimiu.
Toda a vantagem é definicional. Selecionar sessões que fecharam acima de sua abertura e, em seguida, medir abertura-fechamento nessas mesmas sessões, mede uma quantidade garantidamente positiva. A regra descobriu seu próprio filtro.
Variantes disso se escondem em dados diários o tempo todo: uma média móvel que inclui o fechamento de hoje e é usada para negociar hoje, um sinal calculado em preços já ajustados por um desdobramento que ainda não havia ocorrido, um stop intradiário colocado em uma máxima da sessão que ainda não havia sido impressa. A forma comum é um timestamp de decisão anterior a um de seus próprios dados de entrada.
Mecanismo dois: um universo extraído dos sobreviventes de hoje
O segundo mecanismo nunca toca na regra. Ele reside na lista de nomes que a regra tem permissão para ver.
Puxe uma lista de tickers de um provedor de dados atual, execute-a por dez anos, e a amostra exclui silenciosamente toda empresa que faliu, foi adquirida ou foi deslistada ao longo do caminho. A regra nunca recebeu os perdedores. O painel mede o tamanho dessa omissão: todo nome listado nos EUA que negociou pelo menos 200 sessões acima de $1 em um determinado ano civil, a parcela desse grupo que ainda imprime preços em julho de 2026, e o retorno mediano do ano civil de todo o grupo ao lado da mediana apenas dos sobreviventes.
O SQL exato por trás de cada número
WITH recent AS (
SELECT DISTINCT ticker
FROM global_markets.stocks_daily_aggs
WHERE date >= toDate('2026-06-15')
AND date <= toDate('2026-07-28')
),
per_name AS (
SELECT toYear(date) AS year,
ticker,
argMin(toFloat64(close), date) AS first_close,
argMax(toFloat64(close), date) AS last_close,
count() AS sessions
FROM global_markets.stocks_daily_aggs
WHERE date >= toDate('2015-01-01')
AND date <= toDate('2024-12-31')
AND close > 1
GROUP BY year, ticker
HAVING sessions >= 200
)
SELECT year,
uniqExact(ticker) AS names_trading,
round(100 * uniqExactIf(ticker, ticker IN (SELECT ticker FROM recent)) / uniqExact(ticker), 1) AS still_listed_pct,
round(100 * quantileDeterministic(0.5)(last_close / first_close - 1, cityHash64(ticker)), 2) AS median_return_all_pct,
round(100 * quantileDeterministicIf(0.5)(last_close / first_close - 1, cityHash64(ticker), ticker IN (SELECT ticker FROM recent)), 2) AS median_return_survivors_pct,
round(100 * (quantileDeterministicIf(0.5)(last_close / first_close - 1, cityHash64(ticker), ticker IN (SELECT ticker FROM recent))
- quantileDeterministic(0.5)(last_close / first_close - 1, cityHash64(ticker))), 2) AS survivor_gap_pp
FROM per_name
GROUP BY year
ORDER BY yearDos 7063 nomes que ultrapassaram a barreira em 2015, 52.5% ainda negociavam em julho de 2026. Para o grupo de 2024 o número é 87.5%, principalmente uma questão de tempo decorrido: um nome de 2024 teve dois anos para desaparecer e um nome de 2015 teve onze.
As colunas de retorno carregam o próprio viés. Em 2017 o nome mediano retornou 7.51% enquanto o sobrevivente mediano retornou 11.32%, uma lacuna de 3.81 pontos percentuais entregues de graça. A lacuna é positiva em cada um dos 10 anos gráficos. Uma estratégia testada em sobreviventes a herda antes de tomar uma única decisão, e as regras que filtram fraqueza herdam mais do que a mediana, já que os nomes que desapareceram estão desproporcionalmente nesse balde.
A correção é um universo point-in-time: a lista de nomes como estava em cada data de rebalanceamento, incluindo deslistagens, com uma posição deslistada fechada em seu último print em vez de removida do registro.
Mecanismo três: dados que foram revisados após seu carimbo de data
Preços são carimbados uma vez. Fundamentos não são. Um número trimestral carrega a data de fim do trimestre, é alterado por um arquivamento posterior, e um banco de dados que armazena apenas a versão atual servirá alegremente o número alterado contra a data original. Uma regra que filtra esse número está lendo uma correção que levou meses para chegar.
O mesmo padrão percorre listas de membros de índices reconstruídas para os constituintes atuais, históricos de estimativas de analistas sobrescritos com o consenso final e ajustes de ações corporativas aplicados retroativamente em toda uma série de preços. Em cada caso, o registro armazenado é um instantâneo no tempo presente vestindo uma data no tempo passado.
Duas práticas o contêm. Use uma fonte que mantenha safras, ou seja, o valor como era conhecido em cada data, em vez do valor como é conhecido agora. Onde safras não estiverem disponíveis, aplique uma defasagem de reporte generosa o suficiente para cobrir a real, e trate a duração dessa defasagem como um parâmetro que vale a pena testar, em vez de um detalhe que vale a pena adivinhar.
Como é a curva quando o futuro vaza
O viés de antecipação tem uma assinatura: um desempenho muito acima do que o mercado subjacente ofereceu. Um ponto de referência útil é o teto da retrospectiva, o crescimento que uma previsão perfeita de um dia à frente teria produzido em um único instrumento.
O SQL exato por trás de cada número
WITH bars AS (
SELECT date,
toFloat64(close) AS c,
any(toFloat64(close)) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_c
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toDate('2015-12-01')
AND date <= toDate('2025-12-31')
),
rets AS (
SELECT toYear(date) AS year,
c / prev_c - 1 AS r
FROM bars
WHERE date >= toDate('2016-01-01')
AND prev_c > 0
)
SELECT year,
count() AS sessions,
round(100 * (exp(sum(log(1 + r))) - 1), 1) AS buy_and_hold_pct,
round(100 * (exp(sumIf(log(1 + r), r < 0.02)) - 1), 1) AS without_big_up_days_pct,
round(exp(sum(log(1 + abs(r)))), 1) AS hindsight_ceiling_multiple
FROM rets
GROUP BY year
ORDER BY yearO teto é enorme. Em 2020, a previsão perfeita de um dia no SPY multiplicou o capital 27.7 vezes ao longo de 253 sessões, contra 16.2% para simplesmente manter o fundo. No ano mais calmo dos dez, 2017, a mesma previsão perfeita retornou 2.2 vezes o capital.
A coluna do meio mostra como esse teto é concentrado. Remova as sessões que ganharam mais de 2%, e 2020 passa de 16.2% para -44.9%. Um vazamento que vale apenas um punhado dessas sessões por ano move um backtest por um longo caminho. Uma curva com drawdowns rasos, uma alta taxa de acerto e seus melhores dias aglomerados nas sessões mais violentas do mercado merece uma auditoria.
A calibração importa mais do que qualquer limite único. Uma regra que reivindica uns suaves 40% ao ano durante uma década está reivindicando uma grande fração do teto da retrospectiva, e a pergunta honesta é qual dado disse a ela o que estava prestes a acontecer.
Como testar um backtest quanto ao viés de antecipação
- Atrase tudo em uma barra. Desloque cada sinal um período completo para frente e execute novamente. Vantagens genuínas decaem um pouco. Vazamentos colapsam, muitas vezes a nada.
- Perturbe o futuro. Pegue os dados após cada timestamp de decisão, substitua por ruído ou uma reembaralhada, e execute novamente a lógica de decisão. Toda decisão deve sair idêntica. Qualquer decisão que se mover leu algo que não poderia saber.
- Trate timestamps como dados. Para cada dado de entrada, armazene o momento em que um valor se tornou disponível ao lado do momento que ele descreve. Uma junção que nunca compara essas duas colunas não pode impor a regra.
- Reconstrua o universo como da data. Inclua nomes deslistados e adquiridos, feche-os em seu último print, e execute a mesma regra em ambos os universos para dimensionar a contribuição da sobrevivência.
- Meça contra o teto. Coloque o retorno da estratégia ao lado de um número de buy and hold e um número de previsão perfeita para a mesma janela. A distância do teto é um contexto que um índice de Sharpe sozinho não fornece.
O dimensionamento de posição está a jusante de tudo isso. Uma taxa de acerto inflada alimenta um tamanho de aposta inflado, que é onde o dimensionamento de posição pelo critério de Kelly transforma um erro contábil em um drawdown. A mesma disciplina se aplica antes de o capital real se mover: paper trading antes do dinheiro real testa a mecânica de ordens, e stacks automatizados carregam o perigo idêntico em velocidade de máquina, coberto em sistemas de negociação com múltiplos agentes de IA. Efeitos que sobrevivem a testes cuidadosos point-in-time, como a anomalia da baixa volatilidade, são interessantes exatamente por esse motivo.
FAQ
O que é viés de antecipação em backtesting?
É o uso de dados em uma operação simulada que não estavam disponíveis quando a operação teria sido colocada. Formas comuns são decidir em uma barra de preço na qual a operação também executa, filtrar um universo de empresas que ainda estão listadas hoje e ler um número financeiro que foi revisado após a data anexada a ele.
Como você pode detectar o viés de antecipação?
Atrase cada sinal em um período completo e execute novamente: um vazamento geralmente colapsa enquanto uma vantagem real decai suavemente. Um teste mais forte substitui todos os dados após cada timestamp de decisão por ruído e confirma que toda decisão sai inalterada.
O viés de sobrevivência é o mesmo que viés de antecipação?
Eles são distintos, mas andam juntos. Viés de sobrevivência é uma amostra construída a partir dos nomes que duraram, e saber quais nomes duraram é, em si, informação do futuro, então um universo apenas de sobreviventes é um vazamento de antecipação localizado nos dados, e não na regra.
Por que os backtests com viés de antecipação parecem tão bons?
O vazamento seleciona resultados em vez de prevê-los. No painel acima, filtrar sessões pelo seu próprio preço de fechamento produziu um ganho médio por sessão cerca de 0.455 pontos percentuais acima da versão atrasada em 2016, uma vantagem que é definicional em vez de conquistada.
O que são dados point-in-time?
Dados point-in-time armazenam cada valor como era conhecido em cada data histórica, incluindo o número original e cada revisão posterior, juntamente com o universo de títulos como estava naquele dia. É a referência que um backtest precisa para mostrar que seus dados de entrada existiam antes de suas decisões.
Cada número acima é uma consulta armazenada e versionada sobre barras diárias reais. Expanda o SQL de qualquer painel ou execute o teste de defasagem em sua própria regra no terminal Strasmore.