← Voltar para a nota
Reprodutibilidade

Como o estudo foi construído

O suficiente para checar um número da nota à mão, ou para reconstruir um estudo equivalente com os dados públicos da Binance. Todas as entradas são gratuitas e públicas.

Dados

Três fontes públicas, todas vindas do arquivo público da Binance e do seu endpoint de métricas, cobrindo os contratos perpétuos USD-M. Nada pago, nada proprietário.

EntradaGranularidadeServe para
Candles1 minutopreço, retornos, volatilidade, volume
Índice de prêmio1 minutovariáveis de base
Financiamento realizadopor eventofluxo de caixa na barra da liquidação
Contratos em aberto1 horavariáveis de posicionamento

As quatro entradas são públicas e gratuitas. O financiamento é um fluxo de caixa e não uma variável explicativa, porque um modelo que vê o próprio financiamento pode aprender a operar em volta da liquidação.

Duas peculiaridades do arquivo precisam de tratamento, sem o qual o painel desalinha silenciosamente. Os arquivos de candles mudam de convenção de cabeçalho no meio do histórico, e um período antigo marca o tempo em microssegundos em vez de milissegundos. Os dois são normalizados na leitura.

A cobertura dos contratos em aberto é um teto duro, não um limite de coleta. A plataforma só publica as métricas do segundo maior contrato a partir de dezembro de 2021, e datas anteriores devolvem ausência para a maioria dos contratos. Uma extensão retroativa sobre os 354 contratos rodou 148 minutos e acrescentou zero linhas. É por isso que a comparação de variáveis fica restrita às janelas mais recentes.

Universo

354 contratos, dos quais 56 foram retirados antes do fim da amostra e ficam mantidos nas datas em que de fato foram negociados. A seleção é feita na data: em cada virada de mês, os contratos são ordenados pelo volume médio diário em dólares dos 30 dias estritamente anteriores, e os 40 primeiros ficam elegíveis.

Os filtros de elegibilidade entram antes da ordenação, de modo que não podem depender de um resultado. A moeda de cotação tem de ser USDT, contratos com vencimento são excluídos, e subjacentes que não são cripto também.

# history eligibility is tested on genuinely traded volume, not file existence,
# because the archive pads a contract's file after its last real trade
traded = bars.filter(pl.col("quote_volume") > 0)
last_real = traded["open_time"].max()
bars = bars.filter(pl.col("open_time") <= last_real)

Observação e ação

Uma decisão por hora. A ação é um conjunto de 20 números entre menos um e mais um, um por vaga, lidos como a fração da conta que se quer manter naquele contrato. Positivo é comprado, negativo é vendido, e vender a descoberto é permitido porque são contratos perpétuos.

Quatro regras se aplicam depois, nesta ordem. Qualquer coisa entre menos e mais dois centésimos vai para zero exato, para que não ter posição seja uma escolha alcançável e não um equilíbrio instável. Cada contrato é limitado a um quarto da conta. Se a soma dos pesos em valor absoluto passa de um, o conjunto todo é reduzido proporcionalmente: não há alavancagem. Vagas com um contrato que não está sendo negociado naquela hora são forçadas a zero.

A observação traz, por contrato, as suas colunas de variáveis mais três grandezas do próprio agente: o peso que ele carrega, se está no lucro ou no prejuízo naquela posição, e há quanto tempo a carrega. Depois vêm doze grandezas no nível da conta: exposição bruta e líquida, queda desde o topo, logaritmo do patrimônio, número de contratos ativos e carregados, avanço dentro do episódio, resultado realizado, tamanho médio das operações, custo e financiamento acumulados, e o teto bruto.

As posições são reduzidas à força a mercado se a exposição bruta passar de uma vez e meia o teto, e um episódio termina se o patrimônio cair abaixo de um quarto do valor inicial.

Custos e financiamento

Os custos entram dentro da recompensa em vez de serem descontados depois, o que importa porque as duas recompensas por operação ficariam cegas a eles, e uma recompensa por operação cega a custos ensina comprovadamente a operar em excesso.

fee        = taker_fee * traded_notional          # 5 bp per fill
slippage   = (base_slip + impact_k * sigma * sqrt(participation)) * traded_notional
participation = traded_notional / max(interval_dollar_volume, 1.0)   # capped at 5%
funding    = position_notional * funding_rate     # on the true settlement bar only

O termo de impacto é escalado pela volatilidade realizada do contrato, e não só pela participação. Sem o termo de volatilidade a expressão fica dimensionalmente errada: uma versão anterior cobrava 2,3% de deslizamento numa operação de dez mil dólares no maior contrato do universo.

A participação é medida contra um tamanho de conta fixo em vez de frações do patrimônio, porque senão o teto nunca morde. Operações abaixo de um milionésimo da conta são canceladas, o que impede que o ruído de arredondamento em precisão simples seja registrado como cerca de mil operações fantasma por execução.

ParâmetroValor
Taxa de tomador5 pb por execução
Deslizamento base2 pb por execução
Impactoraiz quadrada da participação, escalada pela volatilidade realizada
Teto de participação5% do volume em dólares do intervalo
Financiamentotaxa realizada, aplicada uma vez na barra do evento
Conta100.000 USD, fixo

Parâmetros de custo. Todos são cobrados em cada execução, sobre o tamanho real da posição.

Validação deslizante

Vinte janelas deslizantes. Cada uma toma 18 meses de treino, 3 de validação e 3 de teste, com uma purga de 7 dias e um embargo de um dia em cada fronteira. O tamanho da purga é o histórico mais longo exigido por uma variável, de modo que nenhuma linha de treino possa ver uma barra que se sobreponha a um alvo de teste.

A normalização é ajustada só nas linhas de treino. O ponto de checagem é escolhido pelo patrimônio de validação em quatro segmentos do treino, nunca pelo teste. O teste é tocado uma vez por configuração.

A triagem usou as janelas 1, 3, 5, 8, 11, 14, 17 e 19. O período fora da amostra vai de 17 de novembro de 2021 a 17 de agosto de 2026.

# features from completed bar t -> decision after bar t -> fill at bar t+1
# a rotation into a slot whose contract changed must NOT settle against the
# previous contract's price, which is the single worst defect found in build
rotated = (sym_id[t+1, k] != sym_id[t, k]) or (not live[t+1, k])
step_ret = 0.0 if rotated else (px[t+1, k] / px[t, k] - 1.0)

Desenhos de recompensa

Seis desenhos, iguais em todo o resto. Dois só falam quando uma posição fecha, quatro falam a cada hora.

DesenhoPaga porQuando
Resultado líquido por operaçãoo resultado realizado depois dos custos daquela operaçãono fechamento
Sinal de cada operaçãomais um por fechamento no lucro, menos um por fechamento no prejuízono fechamento
Retorno logarítmicoa variação horária do valor da contaa cada hora
Retorno menos a queda máximao mesmo, descontada uma penalidade pela profundidade abaixo do topoa cada hora
Índice de Sharpe diretoSharpe diferencial, atualizado continuamentea cada hora
Retorno escalado pela volatilidadeo retorno horário dividido pela volatilidade recentea cada hora

Os seis desenhos. Os dois primeiros correspondem à especificação original e são liquidados líquidos das taxas, do deslizamento e do financiamento daquela operação.

Agentes de referência

Sete, rodados no mesmo ambiente e no mesmo modelo de custos. Não ter posição, comprar e manter o universo, comprar e manter um único contrato, peso igual, uma regra de seguir tendência, uma regra de reversão à média, e um agente aleatório.

O que importa é o agente aleatório. Ele é casado com a rotação medida da política contra a qual é comparado, mantendo a sua carteira aleatória pelo número de passos que reproduz aquela intensidade de negociação. Comparar uma política com uma posição comprada e mantida a favoreceria, porque ela paga muito mais custo. Também é gerada uma escala de agentes aleatórios com vários prazos de permanência, para que cada política seja julgada contra o degrau mais próximo da sua própria rotação.

Não ter posição fica mantido mesmo que esse agente nunca opere. Não fazer nada aqui é uma estratégia legítima, e desqualificá-lo por falta de operações eliminaria justamente a referência que detecta um agente que aprendeu a ficar de fora.

Inferência

A estatística registrada é o percentil 25 do retorno ajustado ao risco fora da amostra agregado entre os pontos de partida aleatórios, e não a mediana. Ordenar pela mediana deixaria apresentar como vantagem um resultado carregado por três partidas de sorte em cinco, que é exatamente o que aconteceu uma vez neste estudo e foi interceptado por essa regra.

A contagem de tentativas para qualquer correção de multiplicidade é o número de configurações distintas, nunca o número de execuções. Pontos de partida de uma mesma configuração não são tentativas independentes. As séries fora da amostra agregadas são pontuadas diretamente; números por janela nunca são promediados num número principal, e a quantidade de janelas nunca é multiplicada numa contagem de estratégias.

A probabilidade de sobreajuste do backtest é calculada por validação cruzada combinatória simétrica sobre a família de configurações. O erro por família é controlado por Holm e por Benjamini-Hochberg. O Sharpe deflacionado usa a contagem de configurações distintas como número de tentativas.

# per-window fractions each restart at 1.0, so they must not be summed across
# windows. The MEAN across windows is additive and the parts reconcile; a
# median of each column separately does not sum to the median net.
gross = mean(w.total + w.cost - w.funding for w in windows)
cost  = mean(w.cost for w in windows)
net   = mean(w.total for w in windows)      # gross - cost + funding == net

Controles

Eles rodam antes de qualquer leitura de resultado, e uma falha interrompe o estudo em vez de virar uma nota de pé de página.

ControleO que ele intercepta
Invariância ao truncamentouma variável que olha adiante, exigindo que o histórico truncado reproduza o histórico completo
Alvo plantadoum aparato incapaz de detectar vazamento mesmo quando se injeta um
Fidelidade do núcleodesvio do simulador rápido contra uma implementação lenta e independente
Invariantes de contabilidadedezessete verificações, entre elas um índice de peso igual calculado à mão
Identidade de amostraramos de uma mesma comparação apoiados em linhas diferentes
Degeneraçãouma execução que é só um agente de referência com nome de política
Integridade da reservauma janela reservada tocada por alguma execução
Reprodutibilidadeuma reexecução que não reproduz exatamente os números registrados

Cada controle roda antes de qualquer leitura de resultado, e uma falha interrompe o estudo. Um teste que não pode falhar não é controle: por isso o teste com alvo plantado tem de melhorar de forma clara, e se não melhorar é o próprio aparato que está quebrado.

O controle de contabilidade foi o que justificou o seu lugar. Ele interceptou um preço fictício usado para liquidar uma rotação para uma vaga cujo contrato havia mudado, o que anunciava um retorno multiplicado por 31 onde a verdade calculada à mão era 1,46.

Execuções e desvios

219 execuções, nenhuma falha. A comparação de recompensas está equilibrada em cinco pontos de partida aleatórios por desenho; um desenho foi depois levado a quarenta para o experimento de custos, e essa extensão é apresentada em separado em vez de misturada numa tabela de cinco partidas.

Três desvios do plano ficam registrados. Duas das vinte janelas reservadas foram usadas na triagem, o que as consumiu e deixou a reserva com duas janelas intactas. A comparação de variáveis foi refeita num conjunto de janelas mais recente logo que ficou claro que a cobertura dos contratos em aberto, de outro modo, apoiaria os seus ramos em amostras diferentes. E uma grade secundária de cadência foi abandonada porque representava cerca de 26 horas para um orçamento de quatro, então a questão da cadência é tratada só pelos agentes de referência, o que é evidência mais fraca do que uma grade de políticas.

Um número publicado foi corrigido depois. Uma primeira versão da decomposição de custos somava as colunas do registro de operações tanto entre janelas como entre pontos de partida, o que conta em dobro e soma frações de capital que reiniciam cada uma em um. O registro é primeiro a entrar, primeiro a sair e só guarda o realizado: a sua soma difere legitimamente do retorno total pela marcação do estoque ainda aberto no fim da janela. As decomposições agora vêm dos acumuladores do simulador.

← Voltar para a nota