← O artigo
Reprodutibilidade

Cada número do artigo, e de onde ele veio

Método suficiente para conferir a aritmética na mão, ou para reconstruir um estudo equivalente a partir das mesmas fontes públicas, incluindo as regras que governam um contrato que para de negociar e os hashes sob os quais a execução está congelada.

Venue, universo e datas

Futuros perpétuos da Binance margens em USDT. A data de seleção é 31 de dezembro de 2022 e nada posterior a ela informa o ranking. Um contrato é elegível se for cotado e margeado em USDT, tiver ao menos 24 meses de histórico genuíno de volume negociado até a data de seleção, medido como um primeiro dia com volume negociado positivo em ou antes de 31 de dezembro de 2020, tiver negociado durante outubro a dezembro de 2022, e não for uma reivindicação duplicada sobre a mesma exposição subjacente. A enumeração percorre todos os 986 contratos já listados na venue e deixa 78 elegíveis, ranqueados pelo notional diário mediano negociado entre outubro e dezembro de 2022. Nenhum contrato elegível é uma denominação de mil unidades ou uma segunda denominação de cotação de outro, então a regra de duplicidade não remove nada e o ranking é o ranking bruto de notional.

O universo congelado é o rank 1 ao 30. Faixas e degraus da escada são duas partições determinísticas desse único ranking, fixadas antes de qualquer coisa rodar.

FaixaMercadosNotional diário mediano
T1, ranks 1-6BTC, ETH, DOGE, XRP, BNB, SOLUS$ 6,978M a US$ 433M
T2, ranks 7-14MATIC, LTC, ETC, LINK, ADA, NEAR, DOT, EOSUS$ 347M a US$ 128M
T3, ranks 15-22AVAX, SUSHI, CRV, AXS, ATOM, FIL, FTM, BCHUS$ 127M a US$ 72M
T4, ranks 23-30TRX, UNI, WAVES, ALGO, AAVE, BAND, RSR, XMRUS$ 58M a US$ 34M

Os ranks 1 a 6 reproduzem exatamente os seis mercados do estudo herdado. O eixo de rank cobre um fator de 205 em notional negociado.

Os degraus da escada são os universos top-N aninhados para N em {6, 10, 15, 20, 25, 30}, dando 36, 60, 90, 120, 150 e 180 sleeves, com cada degrau alocando o mesmo capital fixo em peso igual por sleeve. Fora da amostra vai de 1 de janeiro de 2023 até 30 de junho de 2026, catorze trimestres completos e não sobrepostos. Os dados foram puxados até 30 de junho de 2026 exclusive, então a sensibilidade registrada de janela parcial para julho de 2026 não se aplica.

Dados

Klines horárias UTC desde o lançamento de cada contrato, klines de um minuto desde 1 de novembro de 2021 para reconstrução do caminho intrabar, eventos históricos de funding em seus timestamps reais com o intervalo de liquidação publicado, e aberturas horárias de mark price para os fluxos de funding. As barras de um minuto são consumidas e descartadas; o que persiste por hora é a informação de caminho derivada de que o engine precisa, ou seja, o timestamp da máxima e da mínima da barra, sua ordem, a contagem de minutos e as flags de reparo.

Os painéis são construídos numa grade horária UTC comum por mercado, sem forward fill. Volume negociado positivo é o teste tanto do histórico de um contrato quanto de seu fim. Isso importa: o painel local de contratos deslistados preenche contratos mortos com barras de volume zero bem depois da liquidação, 11,510 linhas preenchidas para um contrato e 16,527 para outro, ambos indo até 2026-04-30 apesar de terem liquidado em janeiro de 2025 e junho de 2024. Ler a extensão do arquivo em vez do volume negociado teria mantido dois contratos mortos negociando a preços velhos por mais de um ano do período fora da amostra.

Para os seis mercados incumbentes o painel congelado do estudo anterior é reutilizado byte a byte, para que a verificação de aninhamento possa ser exata. Painéis locais são checagens cruzadas sobre o pull fresco, não fontes, e qualquer discordância no nível de barra foi resolvida contra a exchange antes do congelamento.

Morte de contrato e liquidação compulsória

Quatro dos vinte e quatro contratos adicionados pararam de negociar dentro do período fora da amostra. A Binance liquidou compulsoriamente os quatro às 09:00 UTC, e a última hora com volume negociado positivo coincide com a liquidação anunciada em todos os casos. Cada anúncio é guardado com sua URL, timestamp de coleta e SHA-256 num manifesto de morte que o gate de dados lê.

RankContratoLiquidação anunciada, UTCÚltima hora com volume positivo
7MATICUSDT2024-09-04 09:002024-09-04 08:00
14EOSUSDT2025-05-21 09:002025-05-21 08:00
21FTMUSDT2025-01-06 09:002025-01-06 09:00
25WAVESUSDT2024-06-11 09:002024-06-11 08:00

A regra primária é não fazer stitching. Um sleeve termina quando seu contrato para de negociar, qualquer posição aberta fecha na última abertura observada, e a partir da barra seguinte o sleeve fica em caixa pelo resto do estudo. Sleeves sobreviventes nunca são renormalizados para absorver o capital liberado. Essa é a descrição literal do que a exchange fez, e não apenas a escolha conservadora: as posições foram fechadas e liquidadas, e nenhuma posição sucessora foi criada.

A sensibilidade registrada de stitching identifica um sucessor pelo token nomeado no próprio anúncio de swap da exchange, definido antes de qualquer comparação de preço, porque semelhança de ticker escolhe o contrato errado aqui. Dois tickers parecidos com Sonic negociam simultaneamente nesta venue e apenas um deles é o token no qual o FTM foi convertido. Um sucessor só é aceito quando sua primeira abertura observada e o último fechamento negociado do antecessor concordam dentro de 5% depois da razão anunciada.

AntecessorSucessorIntervalo sem contratoVariação ajustada pela razãoTolerância de 5%
MATICUSDTPOLUSDT9 dias e 4 horas+6.03%falha, não stitchado
EOSUSDTAUSDT7 dias e 0 horas+0.23%passa
FTMUSDTSUSDT10 dias e 1 hora+3.87%passa

Com os dois mercados stitchados substituídos, o contraste primário vai de -1.046 para -1.124, com intervalo de 95% de -3.081 a +0.856. O veredicto não depende de como as migrações são tratadas.

A tolerância foi escrita para pegar uma razão de conversão errada e não consegue separar isso de um movimento real de mercado num intervalo desse tamanho. Ainda assim ela ficou como estava, porque o caso que falha já estava visível quando a fraqueza foi notada, e retargetar um teste sabendo qual contrato ele exclui é exatamente o padrão que o pré-registro existe para prevenir. A consequência fica registrada no lugar.

Estratégias e grades de configuração

Seis famílias estruturais com sua semântica de eventos de sinal herdada sem mudanças: tendência por EMA, breakout de Donchian, momentum de série temporal, reversão por RSI, fade de bandas de Bollinger e breakout por compressão de volatilidade. Cada uma carrega uma lista canônica de 64 configurações numéricas, gerada uma única vez por um gerador de hipercubo latino discreto com seed 20260809, reutilizada em cada mercado e cada janela e travada por hash. Nenhum mercado jamais recebe uma busca mais ampla que outro.

Uma posição por sleeve. Sinais na mesma direção são ignorados, um sinal oposto reverte na próxima abertura observada e cobra dois fills, stop e alvo são fixados por Wilder ATR(14) conhecido na entrada, e um hold máximo sai na abertura após H barras completas em posição. A ordenação de eventos no mesmo timestamp é funding, barreiras por gap, reversão, hold máximo, nova entrada e então barreiras intrabar. A execução intrabar reconstrói a hora como abertura, primeiro extremo registrado, segundo extremo registrado, fechamento, a partir de barras de um minuto; um gap através do stop preenche na primeira abertura disponível e um gap através do alvo preenche não melhor que o alvo; quando a ordem dos extremos não é resolvida, o stop executa primeiro.

Walk-forward e seleção

for window in quarterly_windows(oos_start="2023-01-01", oos_end="2026-07-01"):
    param_block = window.is_slice[:9]        # nine months, scored
    axis_block  = window.is_slice[9:]        # three months, retained unused
    attempts = [score(cfg, param_block) for cfg in family_grid]    # all 64, persisted

    eligible = [a for a in attempts
                if a.closed_trades >= 24 and a.distinct_weeks >= 6]
    if not eligible:
        cash_sleeve(window)                  # recorded, never dropped
        continue

    winner = max(eligible, key=lambda a: (a.net_return, -a.turnover, -a.canonical_index))
    apply(winner, window.oos_slice)          # OOS starts flat

Doze meses dentro da amostra divididos em um bloco de parâmetros de nove meses e um bloco de seleção de eixo de três meses, três meses fora da amostra, avançando três meses, catorze janelas completas. O bloco de seleção de eixo não tem papel de seleção aqui porque este estudo não tem picker; ele é mantido sem uso para que os limites de janela, o comportamento de purge e os blocos pontuados fiquem bit a bit idênticos ao estudo herdado e a verificação de aninhamento possa ser exata.

A elegibilidade exige ao menos 24 trades fechados em ao menos seis semanas calendário distintas no bloco de parâmetros, decidida dentro da amostra para que nenhuma informação fora da amostra selecione quais sleeves ficam vivos. Um sleeve-janela sem configuração elegível contribui com caixa e é registrado, o que importa porque contratos finos falham essa barra com mais frequência e abortar nisso teria transformado o estudo num filtro de sobrevivência sobre atividade. Ao longo da execução, 54 das 2,520 decisões de seleção não encontraram configuração elegível. Empates são resolvidos por menor giro e depois por menor índice canônico.

Custos e funding

O modelo primário cobra 5 pontos-base de taxa taker e 2 de slippage em cada fill, em cada mercado do rank 1 ao 30, aplicados ao notional absoluto preenchido com construção adversa do fill e contabilização separada do slippage. Mantê-lo plano é o que torna o degrau de seis mercados bit a bit idêntico ao estudo herdado e mantém o contraste de rank como uma medida de qualidade de sinal em vez de uma medida de um modelo de custo que este estudo inventou.

Isso é otimista na ponta fina, então uma sensibilidade adversa obrigatória cobra slippage por faixa e deixa a taxa inalterada. Ela resseleciona cada configuração sob o custo escalado, porque um encargo maior por fill muda quais parâmetros vencem o bloco e manter a seleção fixa superestimaria o efeito.

FaixaSlippage por fill, primárioSlippage por fill, adverso
T12 bp2 bp
T22 bp4 bp
T32 bp6 bp
T42 bp8 bp

A escada é declarada e não calibrada, e é rotulada assim em todo lugar.

A especificação registrou dois ramos para essa escada: um calibrado a partir de um estimador de spread Abdi-Ranaldo em barras dentro da amostra, ou, se a validação falhasse, a escada declarada acima como teste de estresse não calibrado. O ramo calibrado falhou por dois motivos independentes, ambos estabelecidos antes de qualquer valor fora da amostra ser lido. O termo médio do estimador é negativo para todos os trinta contratos em barras horárias dentro da amostra, então ele corta em zero e devolve uma escada plana que afirmaria falsamente que o custo de execução não sobe com o rank; agregar para barras diárias não resolve, e onde o termo fica positivo ele implica 62 e 106 pontos-base contra spreads reais de perpétuos bem abaixo de um. Separadamente, a única fonte de validação do inventário começa em 2023-04-01, dentro do período fora da amostra, então rotear a escada por ela teria deixado informação fora da amostra escolher um parâmetro de custo. O fallback registrado foi tomado em vez de substituir por um estimador escolhido depois de ver o primeiro falhar.

O funding usa eventos observados em seus timestamps reais, com funding positivo debitando comprados e creditando vendidos, avaliado sobre a posição mantida imediatamente antes do timestamp de liquidação, e nunca é uma feature. Os intervalos de liquidação são lidos por contrato do histórico de funding publicado pela exchange em vez de assumidos em oito horas, porque vários contratos de altcoins passaram a funding de quatro horas dentro desta amostra. Uma observação de funding esperada e ausente é uma falha de dados, não um zero.

net_pnl = gross_pnl - fee - slippage - funding_cost
assert abs(net_pnl - ledger.net_pnl).max() < 1e-9      # measured: exactly 0.0

Inferência

Bootstrap pareado agrupado por semana sobre séries diárias, 10,000 réplicas, seed 20260810, intervalos percentis. Dentro de cada janela fixa fora da amostra o bootstrap reamostra clusters de semana calendário de segunda a domingo UTC. Um limite de trimestre corta uma semana calendário, então seus dias de cada lado formam fragmentos separados. Cada mercado, família, faixa e degrau dentro de um fragmento amostrado viaja junto, o que preserva a dependência transversal sem mudar a contagem de clusters de uma janela.

frag   = df.groupby(["window", pd.Grouper(key="ts", freq="W-MON")])
blocks = [g for _, g in frag]                    # whole week-fragments move together

def stat(sample):                                # the primary estimand
    return (sample.loc[sample.group == "added",     "net_bp"].mean()
          - sample.loc[sample.group == "incumbent", "net_bp"].mean())

draws  = [stat(pd.concat(rng.choice(blocks, len(blocks)))) for _ in range(10_000)]
lo, hi = np.percentile(draws, [2.5, 97.5])

A medida é a expectativa líquida por sleeve dos 144 sleeves adicionados menos os 36 sleeves incumbentes, em pontos-base de capital do sleeve por sleeve-dia vivo. Um sleeve-dia vivo é um dia em que o contrato estava negociando, então dias após a morte de um contrato saem inteiramente do denominador.

Cada p-valor secundário é o dobro da menor probabilidade de cauda do bootstrap com a correção de réplicas finitas (count + 1) / (B + 1), limitada a um, antes de os quatro entrarem no Benjamini-Hochberg a 5%. O único contraste primário não é corrigido, e nenhuma outra comparação do estudo pode virar manchete substituta.

O poder foi medido antes do congelamento a partir do painel fora da amostra do estudo herdado: o erro padrão agrupado por semana da média do grupo incumbente é de 1.00 ponto-base por dia, 0.98 vez o cálculo de dias independentes porque os retornos de sleeve carregam quase nenhuma dependência serial, e o erro padrão projetado da diferença é 1.21, dando uma meia-largura de 95% de cerca de 2.4. A oscilação que levaria o book de 180 sleeves a um Sharpe de zero é mais que o dobro dessa meia-largura, então o desenho resolve um efeito com menos da metade do tamanho que importaria, e não consegue resolver diferenças abaixo de aproximadamente 2 pontos-base por dia.

Disciplina de Sharpe

Aqui o Sharpe é uma medida registrada e não um diagnóstico, então seus modos de abuso são fechados explicitamente. Sharpe nunca seleciona uma configuração, um mercado, uma faixa ou um degrau. Todo Sharpe é calculado sobre o book diário agregado e não sobreposto ao longo das catorze janelas; Sharpes por janela nunca são promediados e a contagem de janelas nunca é multiplicada por uma contagem de estratégias. Todo Sharpe é reportado ao lado do retorno líquido acumulado do mesmo book, e nenhum degrau com retorno acumulado negativo pode ser chamado de melhor com base apenas no seu Sharpe. A autocorrelação de primeira ordem dos books diários vai de -0.026 a +0.006, então o piso de ruído de cerca de 0.52 não precisa de inflação material.

A verificação do modelo de amplitude

mult   = np.sqrt(n_cells / (1 + (n_cells - 1) * rho_measured))
sr_hat = per_sleeve_sharpe.mean() * mult        # both measured inside the replicate
gap    = sr_realized - sr_hat                   # carries its own bootstrap interval

rho_measured é a correlação média realizada entre pares dos retornos líquidos diários dos sleeves daquele degrau. A leitura registrada, fixada de antemão: um intervalo contendo zero em todo degrau significa que a amplitude entregou exatamente o multiplicador que a estrutura de correlação medida implica e nada além dele, enquanto um intervalo excluindo zero em qualquer degrau significa que o modelo é incompleto e a direção do erro é reportada.

O estimador foi validado antes de tocar dados reais, num corpus sintético com Sharpe por sleeve conhecido e correlação constante conhecida entre pares, para rho em {0, 0.05, 0.2, 0.5} e contagens de sleeves em {36, 180}, 24 casos dentro da tolerância.

Um viés declarado, encontrado durante a conferência e aceito em vez de corrigido: a correlação é calculada sobre séries diárias de sleeve que são exatamente zero em cerca de três quartos dos sleeve-dias, porque um sleeve fica parado a maior parte do tempo. Esses zeros deprimem mecanicamente a correlação, o que eleva o multiplicador e torna o Sharpe previsto mais negativo. Todas as seis estimativas pontuais da diferença são positivas, então o viés corre na mesma direção da conclusão de que o realizado acompanha o previsto. Trocar o estimador depois de ver o resultado não estava disponível.

O contrafactual registrado segura cada sleeve adicionado na média e na volatilidade por sleeve dos incumbentes mantendo a estrutura de correlação realizada dos 180 sleeves, o que divide a diferença de Sharpe num componente de amplitude e num componente de expectativa, com um resíduo que precisa ser zero dentro da tolerância numérica. Medido: -1.1876 e +0.1221 contra um resíduo de exatamente 0.0000.

Verificações de vazamento, integridade e credibilidade

VerificaçãoResultado
Aninhamento, saídas do engine nos 36 sleeves incumbentesidênticas quadro a quadro
Aninhamento, configurações selecionadas504 linhas idênticas, 0 divergências
Aninhamento, série diária do portfóliodiferença absoluta máxima de 3.47e-18 contra tolerância de 1e-12
Referência em Python contra o engine em Rust120 casos, 41,309 trades, exato em timing, direção e razão de saída, 1.94e-16 em preços
Sem lookahead sob truncamento do futuro427,080 trades anteriores bit a bit idênticos
Nulo de random walk, GBM sem drift, 30 seedsnenhum intervalo de família acima de zero
Limites de janelazero trades cruzam um limite em todas as 10,080 combinações sleeve-bloco
Integridade de dados, 30 mercadoszero padding, zero horas intrabar faltando, zero proxies no período primário
Datas de morte contra anúncios da exchange4 de 4 dentro da hora de liquidação
Cobertura, apenas blocos dentro da amostra97.86% de preenchimento, sem ressalvas
Identidade do ledger sobre o ledger selecionado completoresíduo exatamente 0.0

Quatro gates carregam cada um um defeito plantado provando que podem falhar; cada um sai com código diferente de zero e nomeia o defeito. Trinta testes passam e o backtest-guard reporta zero falhas automatizadas.

O avaliador. O strategy-evaluator, fixado no mesmo commit que o estudo herdado usou, rodou seus estágios de integridade, procedimento e inputs. Os custos reconciliam a 5.55e-17 em 183,842 linhas, a checagem de lookahead encontra a correlação da mesma barra mais fraca que a da barra seguinte, e sua checagem de reportado contra recomputado confirma os números publicados contra valores que ele mesmo deriva. Seu veredicto geral coloca o conjunto de estratégias dentro do nulo empírico, um Sharpe máximo observado de -0.595 contra um máximo nulo esperado de 1.116, o que para um book em que todo braço perde é concordância e não contradição. Sua flag no_purge é a herdada: o bloco de parâmetros termina no instante em que o bloco fora da amostra começa e o engine faz purge no nível do trade em vez de por intervalo de calendário, o que foi verificado diretamente e reverificado de forma independente.

A reconferência a partir do código. A implementação foi reconferida a partir do código-fonte, sem recorrer ao texto escrito. Essa passagem devolveu um bloqueador, seis achados maiores e seis menores. Trabalhando a partir do parquet persistido, reproduziu a medida primária, sua decomposição, as quatro faixas, os seis degraus e os quatro testes secundários bit a bit, recomputou cada decisão de seleção com zero divergências, verificou cada combinação de limite sleeve-bloco, e confirmou tanto que nenhum trade ocorre depois da morte de um contrato quanto que os 108 sleeves em caixa contribuem exatamente zero sleeve-dias vivos.

O bloqueador era que a sensibilidade obrigatória com slippage escalado por rank nunca tinha de fato sido rodada, enquanto um rascunho a descrevia como se tivesse. Rodá-la mudou o veredicto registrado sob aquele modelo de custo, e é por isso que o artigo reporta as duas leituras lado a lado. Dois outros achados ficam registrados em vez de corrigidos: o engine descarta em vez de fechar compulsoriamente uma posição aberta quando um contrato para de negociar, seis trades contra 91,277, e um contraste bruto não registrado tinha sido promovido a manchete num rascunho e está retirado.

Escala. 180 sleeves sobre 56 blocos cada, 645,120 pontuações candidatas de configuração-bloco, e 2,520 decisões de seleção por política de custo. Ao longo das políticas de custo o ledger selecionado guarda 527,013 linhas, das quais 91,277 são trades rolantes fora da amostra, produzidos em 358 segundos de tempo de engine com quatro workers para 15 GB. A análise foi paralelizada em 16 workers e verificada bit a bit idêntica ao caminho serial.

O que o adendo faz, e como

Nenhum engine foi rerodado. O custo de cada fill é reconstruído a partir do ledger por trade persistido do estudo, e essa decomposição reconstrói as colunas guardadas de taxa e slippage a 4.3e-19 e exatamente zero, então a reprecificação é uma transformação de artefatos e não uma nova simulação.

FillTipo de ordemTaxaSlippage
Entrada na abertura seguintemercado, taker5 bp2 bp
Saída no stop, inclusive gap através do stopmercado, taker5 bp2 bp
Reversão, as duas pernasmercado, taker5 bp2 bp
Saída por hold máximo na aberturamercado, taker5 bp2 bp
Saída no alvolimitada em repouso, maker2 bp0 bp

Taxas publicadas do VIP0 de USD-M da Binance. Nenhum nível de fee tier e nenhum rebate são assumidos, então a economia reportada é um piso.

A resseleção é obrigatória e não opcional, porque o bloco de parâmetros é pontuado por retorno líquido e o retorno líquido depende do modelo de custo. Cada modelo portanto roda a seleção registrada completa, 64 tentativas por família por mercado por janela, e o artigo reporta tanto a cifra reprecificada com seleções fixas quanto a resselecionada, para que a diferença entre elas fique visível.

O resultado bruto e o funding ficam bit a bit idênticos depois da reprecificação, a identidade do ledger se mantém em exatamente zero, e das 156,661 linhas materialmente alteradas nenhuma é uma saída fora do alvo. O controle que importa: a seleção sob o modelo all-taker herdado reproduz as 2,520 seleções deste estudo exatamente, zero divergências. Sem isso, qualquer diferença poderia ser o modelo de custo ou poderia ser um bug, sem meio de saber qual.

Os fills são concedidos no toque, então uma ordem limitada em repouso que é apenas tocada conta como executada. Esse é o ramo otimista sobre probabilidade de execução, o que só reforça a conclusão. As entradas seguem taker o tempo todo, porque deixá-las em repouso mudaria quais trades acontecem em vez de apenas quanto custam.

O adendo também registra, de antemão, o encargo de fechamento compulsório que o estudo original teve de deixar sem correção. Uma posição aberta quando um contrato para de negociar deveria pagar um fill completo de saída taker, e exatamente 6 sleeve-janelas selecionadas fora da amostra carregam um. O engine sinaliza o descarte sem emitir o preço do trade, então o encargo não pode ser aplicado retroativamente; seu limite superior é 0.0023 ponto percentual por sleeve.

Hashes congelados

Especificação, universo e cada lista de configuração foram travados por hash antes de qualquer bloco fora da amostra ser lido, e o registro de congelamento foi reverificado entre a execução e a análise. O runner se recusa a ler uma barra fora da amostra ou a escrever um artefato fora da amostra até que todos os hashes registrados concordem.

ArtefatoSHA-256
Manifesto do universo60ce3d29574a5c7a0d9befecc5cb1ea9f00a82528cf7eb80b0a7ec85ae450149
Manifesto de dados, 30 mercadose3129b4b1d711adec2cd905a4ce246b2b3ad7938c9614f31af6aca5d44daff03
Manifesto de blocos do estudo325d3873324433b73979ace8c7450a1df901b46d6d6b6852553aab7dd0c26fbb
Registro de congelamento38741abd0e08a1cdab605cd62bad15ce733b66799761fb421ec132c665014e3c
Manifesto da execução do engineeb954b0d820c0f1e5e1745824c82d484cc006ac68ab6ac40729fb81cecdb3eac
Resultadosef56d329aacd262d00d5b23679963514fb12055ff26a5b0f573e72d156f8e06d

Pedindo o pipeline completo

Esta página é suficiente para conferir cada número do artigo na mão, ou para reconstruir um estudo equivalente a partir das mesmas fontes públicas de dados. Os scripts de produção, ou seja, o pull de dados, a construção dos painéis, o engine em Rust, o runner do experimento e a análise, não são publicados aqui. Escreva para daniel@daru.finance e eu envio.