Cada número do artigo, e de onde ele veio
Método suficiente para conferir a conta na mão, ou para reconstruir um estudo equivalente com os mesmos dados públicos e licenciados.
Dados e universo
Dois painéis, ambos em barras de 15 minutos e de uma hora, de janeiro de 2021 a julho de 2026. Cripto é OHLCV de perpétuos da Binance margeados em USDT, com o spread cotado medido por símbolo-mês e todo evento de funding no seu timestamp de liquidação. Ações são barras consolidadas ajustadas por splits, restritas a negócios elegíveis ao NBBO no pregão regular, com odd lots e reportes de negócios fora de bolsa excluídos, chaveadas por um identificador permanente de ativo em vez do ticker e carregando um spread NBBO medido e ponderado no tempo por barra.
O universo foi fixado em 31 de dezembro de 2022 apenas pela liquidez de outubro a dezembro de 2022, tomando os dez nomes mais líquidos de cada mercado. O MATIC para de negociar em setembro de 2024 e fica ausente a partir daí em vez de ser substituído, já que um substituto escolhido depois usaria informação sobre quais contratos sobreviveram.
| Mercado | Instrumentos |
|---|---|
| Cripto | BTCUSDT, ETHUSDT, DOGEUSDT, XRPUSDT, BNBUSDT, SOLUSDT, MATICUSDT, LTCUSDT, CHZUSDT, ETCUSDT |
| Ações | TSLA, AAPL, NVDA, AMZN, MSFT, AMD, META, GOOGL, NFLX, XOM |
Biblioteca de regras
Quatorze famílias, trinta parametrizações cada, para 420 regras. Para cada família o gerador enumera a grade abaixo, descarta configurações inválidas e duplicadas e então toma 30 configurações space-filling com seed 20260804. A biblioteca é serializada de forma canônica e hasheada, e todo runner se recusa a iniciar se o hash for diferente.
| Família | Sinal no fechamento da barra t | Grade |
|---|---|---|
| Seguimento de tendência | Lado de uma tendência móvel, se a força dela superar um limiar | lookback 12, 24, 48, 96; força 0, 0.5, 1 unidades de vol; manutenção 1, 2, 4, 8, 16 |
| Reversão à média | Contra um desvio padronizado de uma média móvel | lookback 12, 24, 48, 96; z de entrada 0.5, 1, 1.5, 2; manutenção 1, 2, 4, 8 |
| Rompimento | Fechamento além do extremo de fechamento móvel anterior | lookback 6 a 96; margem 0, 5, 10 bp; manutenção 1, 2, 4, 8 |
| Momentum | Sinal de um retorno acumulado defasado acima de uma força | lookback 3 a 96; força 0, 0.25, 0.5, 1 unidades de vol; manutenção 1, 2, 4, 8 |
| Expansão de volatilidade | Direção de curto horizonte quando a vol curta supera a vol longa | curta 6, 12; longa 24, 48, 96; razão 1.25, 1.5, 2; direção 1, 3; manutenção 1, 2, 4 |
| Contração de volatilidade | Direção de curto horizonte durante a compressão | curta 6, 12; longa 24, 48, 96; razão 0.4, 0.6, 0.8; direção 1, 3; manutenção 1, 2, 4 |
| Cruzamento de médias móveis | Cruzamento de EMA rápida/lenta em barra completa | rápida 3 a 24; lenta 12 a 96, rápida abaixo da lenta; manutenção 1 a 16 |
| Rompimento de canal | Fechamento além de uma média mais ou menos um canal de ATR | lookback 12 a 96; largura 0.5, 1, 1.5, 2 ATR; manutenção 1, 2, 4, 8 |
| Reversão de RSI | Compra no sobrevendido, venda no sobrecomprado | RSI 6, 14, 28; limites 20/80, 30/70, 40/60; manutenção 1, 2, 4, 8 |
| Reversão de Bollinger | Contra um fechamento fora da banda | lookback 12, 20, 48, 96; largura 1 a 2.5 dp; manutenção 1, 2, 4, 8 |
| Rompimento de Donchian | Fechamento além do canal anterior de máxima/mínima | lookback 12 a 96; manutenção 1 a 16; confirmação opcional de uma barra |
| Confirmação por volume | Momentum só quando o volume normalizado supera uma razão | momentum 3 a 24; lookback de volume 12 a 96; razão 1, 1.5, 2; manutenção 1, 2, 4, 8 |
| Rompimento do range de abertura | Rompimento das primeiras barras do dia de mercado | range 1, 2, 4 barras; margem 0, 5, 10 bp; entrada mais tardia 0.5, 0.75 do dia; manutenção 1, 2, 4 |
| Baseada em horário | Faixa fixa da sessão e direção | fração da sessão 0, 0.25, 0.5, 0.75; comprado ou vendido; máscara de dia da semana; manutenção 1, 2, 4, 8 |
Um sinal é uma transição de entrada: dispara quando uma regra entra pela primeira vez numa condição comprada ou vendida, e barras repetidas na mesma condição não são sinais novos. Dentro de cada janela de treino de 24 meses, uma regra só é descartada se tiver menos de 120 trades concluídos, operar em menos de 5 instrumentos ou produzir exatamente o mesmo conjunto de sinais que uma regra de número menor, e nenhuma estatística de lucratividade é usada para descartar uma regra.
Sete configurações de expansão de volatilidade nunca operam, porque a razão exigida entre a volatilidade curta e a longa fica fora de alcance para esses comprimentos de janela, e a checagem de duplicatas compara sinais sem o período de manutenção, então regras que diferem só em quanto tempo seguram a posição colapsam na de número menor. Em média, 392 a 396 das 420 regras são elegíveis numa dada janela.
Execução
A decisão é tomada depois que a barra t se completa. A posição entra na abertura da barra t+1 e sai no fechamento da h-ésima barra mantida, onde h é o período de manutenção da regra em barras observadas. Não há stops nem alvos, então a ordem entre a máxima e a mínima de uma barra nunca decide uma saída.
Cada par regra-instrumento segura no máximo uma posição candidata, e um sinal que chega enquanto uma está aberta é ignorado; um modelo que pula um trade nunca cria um substituto.
entry = signal_idx + 1 exit = signal_idx + hold # close of the hold-th held bar gross_bps = direction * log(close[exit] / open[entry]) * 1e4 net_bps = gross_bps - spread_bps - fee_bps - slippage_bps + funding_bps
Features
Sessenta e duas features de preço e volume calculadas na barra t dentro do histórico do próprio instrumento: retornos defasados e momentum de 1 a 24 barras, range máxima-mínima, frações de corpo e pavio do candle, gap entre fechamento e abertura, volatilidade, distância da média móvel, posição no range e distância das máximas e mínimas de 6 a 96 barras, além do volume normalizado. Outras sete são adicionadas: força da tendência (distância absoluta da média móvel de 24 barras sobre a volatilidade de 24 barras), posição na sessão e dia da semana como pares de seno e cosseno, barras restantes no dia de mercado e o log do fechamento da barra t.
A regra contribui com sua família como vetor one-hot, seus parâmetros escalados pela posição na grade com flags de parâmetro ausente, a direção e a força do sinal, o período de manutenção pretendido e as barras desde o sinal anterior. O desempenho recente é a média, a soma, as vitórias e as derrotas dos últimos 20 trades concluídos da regra naquele instrumento, junto com a média, as vitórias e as derrotas dos seus últimos 100 trades concluídos entre instrumentos, contando apenas trades que saíram na barra de decisão ou antes dela.
# strategy-level trailing 100: only trades that have already exited count
for p in trades_sorted_by_entry:
while exits[cursor].exit_ts <= p.signal_ts:
ring.push(exits[cursor].net_bps); cursor += 1
p.recent_100_mean = ring.mean()Os dados de execução (a abertura da barra seguinte, toda coluna de custo e o funding) ficam guardados em cada linha e são removidos da matriz do modelo. A posição na sessão e as barras restantes usam a contagem de barras do dia, que num dia com barras faltando reflete o buraco; esses dias carregam entre 0.002% e 0.33% dos trades, dependendo da célula, e descartá-los move o melhor book de +0.748% para +0.761%.
Um trade que entrou dentro da janela de treino mas sai depois dela é excluído tanto do treino quanto do conjunto fora da amostra, então também sai do histórico de 20 trades, o que deixa esse histórico levemente defasado, mas nunca à frente da decisão.
Modelos e busca
Três famílias, cada uma ajustada separadamente para o alvo de retorno líquido e para o alvo de lucro, cada uma com 30 configurações fixas. O alvo de regressão é cortado nos seus quantis de treino de 0.5% e 99.5% e padronizado. Configurações que falham, ficam constantes ou não convergem contam para as 30 e não podem ser escolhidas.
| Família | Implementação | Faixa da grade nas 30 configurações |
|---|---|---|
| Linear | Ridge para L2 puro, elastic net nos demais casos; elastic net logístico para lucro | alpha 0.0001 a 0.03; razão L1 0 a 1 |
| Árvores com boosting | LightGBM, 150 árvores, sem subamostragem de linhas nem de colunas | profundidade 2 a 6; folhas 4 a 31; learning rate 0.0054 a 0.091; min child 104 a 4,645; L2 0.0014 a 68 |
| Rede neural | MLP com GELU, 6 épocas, batch 8,192 | profundidade 1 a 3; largura 16 a 128; learning rate 0.0001 a 0.0028; weight decay 1.5e-7 a 0.0094 |
Dentro de cada janela, as linhas de treino são divididas cronologicamente em 80/20 entre treino interno e validação, com 16 barras de tempo de relógio removidas antes da divisão. Os modelos de retorno líquido são selecionados pelo IC de rank de Spearman na validação e os modelos de lucro pelo ROC AUC na validação, com empates indo para o menor número de configuração. A vencedora é reajustada sobre os 24 meses inteiros, com o pré-processamento ajustado apenas sobre essas linhas.
Walk-forward
Quarenta e três janelas mensais fora da amostra, de janeiro de 2023 a julho de 2026, em cada uma das quatro células mercado-timeframe, para 172 janelas. Cada janela treina exatamente nos 24 meses-calendário anteriores, usando apenas trades cuja entrada e saída caem ambas dentro deles, e depois prevê uma única vez todo trade elegível que entrou no mês-calendário seguinte. Um modelo por mercado, timeframe, família e alvo agrupa todas as regras e instrumentos.
for cell in ["equity_1h", "equity_15m", "crypto_1h", "crypto_15m"]:
for month in months("2023-01", "2026-07"):
is_rows = trades(entry >= month - 24M, exit < month, eligible_rules(month))
oos_rows = trades(month <= entry < month + 1M, eligible_rules(month))
for family in ("linear", "gbt", "mlp"):
for target in ("net_return", "profit"):
best = select(family, target, is_rows, n_configs=30) # 80/20 inner split
model = refit(best, is_rows)
oos_rows[f"pred_{family}_{target}"] = model.predict(oos_rows)Isso dá 1,032 modelos selecionados a partir de 30,960 configurações tentadas, das quais 30,394 foram ajustadas com sucesso, e 239,452,104 previsões fora da amostra sobre 39,908,684 trades candidatos.
Políticas de trading
Todo par regra-instrumento recebe o mesmo peso base, w0 = 1 / (S × 10), com S o número de regras elegíveis na janela, então tomar todos os sinais nunca pode passar de 100% de exposição bruta.
baseline w = w0
simple filter w = w0 if at least 2 of { vol_24, trend_strength_24, vol_norm_24 }
exceed the instrument's median over the 24 training months
ML filter w = w0 if prediction > 0 bp (net return) or > 0.5 (profit)
ML sizing q = rank of prediction in the window's sorted validation predictions
w = w0 * (0.25 + 1.5 * q)
ML ranking at each signal timestamp keep ceil(20%) of the new signals, at least one,
by prediction; w = w0 * min(5, n_candidates / n_kept)As medianas do filtro simples vêm de barras de mercado únicas na janela de treino, e não de linhas de trade, então uma barra com muitos sinais não é contada muitas vezes. Um filtro que não toma nenhum trade num mês deixa aquele mês em caixa.
Custos
| Mercado | Spread | Taxa por execução | Slippage por execução | Funding |
|---|---|---|---|---|
| Cripto | Metade do spread medido na entrada mais metade na saída | 5 bp | 2 bp | Todo evento real da barra de entrada à barra de saída, com sinal |
| Ações | Metade do spread medido por barra na entrada mais metade na saída | 0.5 bp | 0 | Nenhum |
Funding positivo debita comprados e credita vendidos, e os eventos de funding são atribuídos à barra que os contém, então um trade que entra na abertura de uma barra de liquidação paga essa liquidação. O funding é pequeno perto das taxas: tomar todos os sinais de cripto de uma hora dá -0.28% do capital em funding líquido ao longo da rodada, contra 174.59% pagos em taxas. Os custos são idênticos para todas as políticas, e é por isso que a barra de custo por trade no artigo quase não se move enquanto a barra bruta se move.
Inferência e critérios de afirmação
Os resultados econômicos vêm do ledger fora da amostra concatenado e de uma série de retornos diários sem sobreposição, com o P&L lançado na saída de cada trade. O artigo reporta retornos diários somados, já que a composição prende todo book de cripto perto de -100%; o critério registrado de retorno líquido usa a série composta.
Cada contraste é uma política menos seu comparador na série diária. A incerteza vem de um bootstrap pareado que reamostra semanas inteiras, 10,000 réplicas com seed 20260804, e o Benjamini-Hochberg roda sobre todos os 144 contrastes: 4 células, 18 políticas de modelo e 2 comparadores, falhas incluídas.
weeks = daily_delta.groupby(week) # week-clustered resampling
boot = [weeks.sample(n_weeks, replace=True).sum() for _ in range(10_000)]
p = two_sided(boot)
q = benjamini_hochberg(p_all_144)
# rotation null: same timestamps, same instrument, same count, same exposure budget
for r in range(1_000):
shifted = circular_shift(scores, offset=nonzero, within=(cell, month, instrument))
null[r] = net_of_policy(select(shifted))
passes_rotation = policy_net > quantile(null, 0.95)Um contraste é creditado quando os sete critérios valem: retorno líquido acima do comparador, retorno líquido por unidade de exposição bruta média acima do comparador, q abaixo de 0.05, mais da metade dos 43 meses vencidos, reward-to-risk mensal acima de 1, vantagem positiva depois de excluir o melhor mês e resultado acima do percentil 95 do nulo de rotação. Quando uma política vence todos os meses, a razão reward-to-risk fica indefinida e o critério falha; doze contrastes estão nessa situação, seis em barras de 15 minutos de ações e seis em barras de uma hora de cripto.
A afirmação geral exige um resultado creditado nos dois mercados, nos dois timeframes e em pelo menos duas das três famílias de modelo. Os números semanais absolutos citados no artigo para books individuais vêm de um bootstrap separado, com clusters semanais, do P&L semanal de cada book.
Verificações
Antes de existir qualquer número fora da amostra, a bateria no nível do painel confirmou que truncar o futuro deixa todas as features, sinais e trades anteriores inalterados (diferença máxima 0.0), que um vazamento de alvo plantado eleva o IC de validação de 0.017 para 0.9999, que nenhuma coluna de custo ou funding chega à matriz do modelo, que o funding é cronometrado por evento com posições compradas debitadas quando a taxa é positiva, que os splits conhecidos de ações estão ajustados e que os alvos da barra seguinte se alinham com precisão de 1.7e-6 bp. Uma referência em Python bateu com o motor de sinais compilado em 57,648 trades de uma configuração de cada família, sobre 50,000 barras reais de BTCUSDT.
Depois da rodada, cada uma das 39,908,684 linhas candidatas fora da amostra foi conferida contra os painéis de origem: entrada uma barra depois do sinal, saída depois de exatamente o período de manutenção, preço de entrada igual à abertura do painel e preço de saída igual ao fechamento do painel, retorno bruto, spread, taxa, slippage e funding recalculados a partir dos insumos brutos, a identidade do líquido, entrada dentro do mês avaliado e a feature de preço igual ao log do fechamento da barra do sinal. Todo peso de filtro, dimensionamento, ranqueamento e filtro simples foi reconstruído a partir das previsões e medianas de treino guardadas, e os totais agregados de todos os 92 books de política se reconstroem com diferença de até 5.3e-15.
Os spreads de ações são os valores por barra congelados com o estudo. Reprecificar todo trade de ações com uma extração posterior dos mesmos spreads não move nenhuma política em mais de 0.0024 do capital e não muda nenhum sinal. Os p-valores do bootstrap, os q-valores de BH e as excedências do nulo de rotação também se reproduzem exatamente a partir da série diária.
Hashes
| Artefato | SHA-256 |
|---|---|
| Biblioteca de regras | 501f04df5537f881709027e8755eade85d7ca667acb0051d1fcd4b9dc18bb14a |
| Grades de modelo | 6c6d89b6cfd435ce875876820443405f5d383956a5673ea38f5d2d410b490e47 |
| Políticas | df469ad083dde73c7be52ed5d33ad4d434faa684a74e7777c200b6d5b988bf1d |
| Features | eedebd594bfa8aa9c56fb282e7d065eef06c99b63a0d07f974668a526862cc02 |
| Configuração combinada | 6fc808d41d71d9930b17eb81a0b6b0d2189ba9b7e084896e70c61a3020c94f0f |
| Configuração da análise | 1e3af923775cf8fca30f2c28da0ecab7803320454cfafd15e9101a33d53b5735 |
| Implementação da análise | 86f433e42fe14560425f6da690754e5b603509b4b9581bba56d6bd1bd447fb3b |
Todo número que os gráficos do artigo desenham está em um único arquivo JSON. O pipeline completo, da geração de sinais aos ajustes walk-forward e aos scripts de auditoria, está disponível sob pedido em daniel@daru.finance.

