28 de outubro de 2026 · opções

O sinal estava certo. O nosso backtest de opções comprou a expiração errada.

O sinal estava certo. O nosso backtest de opções comprou a expiração errada.

Às 10:07 de uma terça-feira, o nosso agente de investigação assinalou uma configuração de curto prazo em alta num ETF de índice. O sinal subjacente era corrente: o preço tinha recuperado a média de 20 barras, a volatilidade realizada estava a diminuir e estava prevista uma divulgação macroeconómica para a sessão seguinte. A operação proposta era um call spread com cerca de duas semanas até à expiração.

O backtest gostou da operação. A estratégia em paper não a colocou. Quando comparámos as ordens, as marcas temporais dos sinais coincidiam e os preços do ativo subjacente diferiam apenas alguns cêntimos. Os contratos eram diferentes: o backtest tinha comprado a expiração de sexta-feira que parecia melhor na cadeia histórica; o processo em paper selecionou a expiração seguinte cotada, uma semana mais tarde.

A discrepância vinha de uma associação de calendários. Tratámos os “dias até à expiração” como uma propriedade de uma data e, em seguida, selecionámos o contrato cuja expiração ficava mais perto do objetivo. Nos dados históricos, o calendário de expirações incluía uma cotação semanal que tinha sido adicionada depois da data que estávamos a testar. O backtest tinha usado um contrato do futuro de uma forma que parecia uma conveniência inofensiva.

Suspeitámos primeiro de um erro de fuso horário. As datas de expiração de opções são especialmente propensas a isso: a sessão de mercado termina em Nova Iorque, as marcas temporais das bolsas podem estar guardadas em UTC e uma data à meia-noite pode mudar quando um pipeline a converte sem cuidado. Verificámos. As marcas temporais estavam corretas. Simplesmente, o contrato não existia no universo histórico naquela terça-feira.

Essa foi a primeira lição: uma cadeia histórica de opções precisa de um universo de listagens point-in-time. A data de expiração de um contrato indica quando termina. Não indica quando foi cotado, quando ficou disponível para negociação ou se o sistema o poderia ter selecionado na altura.

Reconstruímos a etapa de seleção com base na informação disponível no momento da decisão. Para cada contrato candidato, exigimos uma marca temporal de cotação não posterior à decisão, uma cotação válida com idade inferior ao nosso limite de frescura e uma sessão de mercado em que a estratégia pudesse enviar uma ordem. Também registámos o conjunto de candidatos antes de os ordenar. Este último ponto foi importante porque o antigo backtest guardava apenas o vencedor; não conseguíamos saber se tinha comparado cinco contratos elegíveis ou escolhido discretamente num calendário que ainda não existia.

10:07hora da decisão do sinal
1 semanadiscrepância na expiração
0listagens históricas elegíveis para o contrato escolhido

A seguir, analisámos a cotação usada para avaliar o spread. O backtest tinha recolhido a cotação mais recente de cada perna de forma independente. O ask da call era das 10:06:58; o bid da call curta era das 10:04:11. Ambas eram tecnicamente recentes segundo a política geral de dados, mas o mercado tinha-se movido entre as duas. Um preço médio de spread calculado com pernas assíncronas pode descrever um mercado que nunca existiu.

Alterámos a regra das cotações para exigir que as marcas temporais de ambas as pernas estivessem separadas por um máximo de dois segundos e para rejeitar mercados cruzados ou sem volume. Isso reduziu o número de observações históricas utilizáveis. Também tornou mais credíveis as avaliações restantes. Quando não existia uma cotação sincronizada, marcávamos o candidato como indisponível em vez de preencher a lacuna com um preço desatualizado.

Depois veio a regra de ordenação. O agente tinha escolhido a expiração com o menor custo cotado do spread. Parece sensato, até o spread ter apenas um contrato de profundidade e a cotação estar desatualizada. Tornámos explícito o objetivo: maximizar o retorno esperado por unidade de risco definido entre os contratos que passam as verificações mínimas de dimensão da cotação, frescura e listagem. Neste exemplo, a expiração elegível mais próxima tinha uma amplitude cotada de $0.42 entre as duas pernas, enquanto a expiração posterior tinha uma amplitude de $0.31. A opção que parecia mais barata também tinha apenas um contrato visível na perna curta.

CandidatoExpiração disponível na altura?Idade da cotaçãoDimensão visível da perna curtaDecisão
Sexta-feira semanalNãoNão aplicávelNão aplicávelExcluir
Sexta-feira seguinteSim1.4 segundos18 contratosElegível
Terceira sexta-feiraSim9.8 segundos1 contratoExcluir por desatualização e pouca liquidez

Reproduzimos o incidente com estas regras. O backtest passou a escolher a mesma expiração que o processo em paper e registou o motivo da rejeição dos outros contratos. A entrada no spread resultante foi pior do que a execução histórica original em $0.11. Isso não significava que a estratégia não tivesse valor; significava que o antigo valor de desempenho incluía uma seleção de operação que o processo em produção não conseguia reproduzir.

Um pequeno incómodo: os formatos dos símbolos das bolsas fazem com que os erros de expiração pareçam problemas de qualidade dos dados. Encontrámos um código semanal de um fornecedor que diferia do código mensal por um carácter. Continuo a guardar o símbolo original junto à chave de contrato normalizada nos registos de auditoria. Não é elegante, mas já nos salvou de confiar demasiado depressa numa associação bem arrumada.

Se estiver a construir um backtest de opções, guarde o conjunto completo de candidatos em cada decisão, juntamente com o estado de listagem, as marcas temporais e dimensões das cotações e o motivo de rejeição de cada contrato. Depois, torne a seleção de contratos uma função determinística desse instantâneo. A escolha da expiração faz parte da estratégia. Se o backtest consegue ver um contrato que o processo em paper não podia ver, a comparação dos sinais começa depois de a resposta já ter mudado.

backtesting de opçõesseleção da expiraçãodados point-in-timemodelação da execução
← Todos os artigos