Lab

M/09 · Teste de estabilidade de superfície pré-registrado

Suavidade in-sample prevê skill out-of-sample?

Um teste empírico pré-registrado da alegação verbal do corpus de que cristas suaves de Sharpe in-sample generalizam out-of-sample e picos afiados não. Piloto SOL: H₀ retido no nível agregado, com forte heterogeneidade no nível de família. Replicação DOGE + BTC em andamento.

A hipótese

A página do corpus da Daru Finance contém a seguinte alegação verbal: “cristas suaves e largas significam que a família tem uma bacia de desempenho estável sob perturbação de seus parâmetros; picos afiados ladeados por colapso significam que a família é frágil, seus picos in-sample são provavelmente overfitted em vez de reais.” Essa frase está impressa na página do corpus há algum tempo sem um teste empírico atrelado. Este projeto é o teste. Está pré-registrado, os hiperparâmetros foram travados antes de os dados de replicação serem carregados, e o writeup está comprometido a publicar de qualquer maneira que o resultado caia.

Operacionalmente: escolha uma família de estratégias F, um ativo a, e uma janela walk-forward w. Para cada estratégia θ no top-K IS de (F, a, w), meça o quanto o Sharpe in-sample oscila quando o backtest é re-executado sob uma suíte fixa de cinco perturbações, confirmação de entrada, taxa, slippage, entrada+indicador. O desvio-padrão desses cinco Sharpes é σmicro(θ). Agregue ao nível da célula tirando a média de σmicro entre o top-K IS. A métrica de robustez OOS RK é o Sharpe OOS de perturbação-base médio dessas mesmas K=5 estratégias na janela w+1. As duas definições formais são:

H0: após controlar pelos efeitos fixos de família / ativo / janela, βsmooth em RK ~ σmicro é zero ou positivo. H1 (unilateral): βsmooth < 0, estratégias estáveis IS generalizam melhor OOS, exatamente como a alegação verbal prevê. K = 5 corresponde à convenção de portfólio existente do escritório (CheckerWFO).

Pré-registro

Dois commits importam. O primeiro, 8e62171552f284b6dbbe6a5d450d41618935fd76, é o commit inicial de analysis-plan.md e trava a hipótese, as quatro métricas de sensibilidade (σmicro, σmicro,z, σparam, σcombined), as quatro métricas de robustez (RK, RPT, Rρ, Rlift), as regras de inclusão/exclusão, a família de estimadores, o protocolo do nulo de permutação, a regra de multiplicidade BH sobre os 15 pares secundários (σ, R), e os limiares de elevação a artigo. Foi committado antes de qualquer parquet ser gerado.

O segundo, 1badde4, é analysis-plan-locked.md: a trava de hiperparâmetros pós-piloto. Congela a definição de vizinhança σparam, o cap numérico de |Sharpe| para artefatos, o estimador OLS-com-SE-clusterizado-por-família que substitui MixedLM, e a verificação cruzada within-transform que substitui o lme4 do R. Foi committado depois que o piloto SOL terminou e antes de qualquer parquet de DOGE ou BTC existir; checagens de mtime no diretório data/ verificam isso.

O design é uma divisão piloto–replicação. A partição SOL_1h_7W é o piloto, usada puramente para travar hiperparâmetros que o pré-registro deixou em aberto (e.g., a regra exata de “1-step” para σparam e a escolha de clusterização para o SE robusto a clusters). O piloto tem poder insuficiente para confirmar qualquer coisa (n_cells = 42, ≈ 0,55 de poder em f² = 0,05). A confirmação vem da replicação pooled DOGE_30m_21W + BTC_30m_27W, n_cells ≈ 322, > 0,95 de poder em f² = 0,05. A replicação é executada com os hiperparâmetros travados e sem mais ajustes.

Metodologia

O corpus é parseado em Rust: src/parse_corpus.rs percorre cada árvore <asset>/<family>/<strat>/<strat>.txt, extrai por regex cada linha Wxx em uma linha de formato longo indexada por (asset, family, strategy, base_param, transformation, confluence, sl_regime, window, sample, perturbation), e emite um parquet por ativo. A correção do parser é checada à mão em cinco arquivos de texto aleatórios por ativo contra as linhas do parquet.

O dataframe de nível de célula tem uma linha por (família, ativo, janela). Para cada célula, σmicro é computado primeiro no nível da estratégia e então tirada a média entre o top-K IS, e RK é a média do Sharpe OOS-base dessas mesmas K=5 estratégias uma janela depois:

Inclusão: uma célula é mantida iff (i) a janela w+1 existe, (ii) ≥ 30 estratégias em (F, a) têm todas as cinco variantes de perturbação na janela w, e (iii) pelo menos K=5 dessas têm Sharpe IS não-nulo. A família RSI_LEVEL em SOL tem apenas 12 estratégias e é excluída do modelo primário de nível de célula pelo piso n ≥ 30; é reportada na sensibilidade de nível de estratégia em vez disso.

Estimador e inferência

O modelo pré-registrado era um ajuste linear de efeitos mistos com interceptos aleatórios em família, ativo e janela. Na prática, em n_windows = 7 no piloto SOL, a covariância dos efeitos aleatórios para janela era singular e o otimizador REML do MixedLM falhou em convergir. O substituto travado é OLS com erros-padrão robustos clusterizados por família e efeitos fixos explícitos em família, janela e ativo:

com o estimador sandwich robusto a clusters no nível de família. A inferência usa um nulo de permutação com M = 1000: dentro de células (a, w+1), embaralhe a atribuição Sharpe-OOS → estratégia, recompute RK, reajuste, e registre βsmooth,null. O p-valor unilateral empírico é .

O pré-registro pedia uma verificação cross-language R/lme4. R não está instalado no ambiente e trazê-lo teria quebrado o padrão tri-língua do escritório (Rust + Python + R mantidos disponíveis apenas quando todos os três já são suportados no host). O substituto travado é um OLS within-transform implementado do zero em Python: subtraia médias de grupo para F / a / w, ajuste OLS sobre os resíduos, e compute os SEs analíticos. As duas implementações precisam concordar em βsmooth com três casas decimais. No piloto SOL elas concordaram em 1,1 × 10⁻¹³.

Desvios documentados do pré-registro

Três desvios são reportados honestamente nos resultados, no mesmo lugar em que o pré-registro disse que estariam:

  • Cap |Sharpe| > 100. A regra sentinela do pré-registro excluía apenas nan e ±inf. Após o parser rodar, valores de Sharpe com magnitude ≈ 1,4 × 10¹⁶ apareceram em linhas com trades = 2: o backtester divide retorno anualizado por uma vol realizada quase-zero nessas trades e produz artefatos numéricos. A regra travada descarta linhas com |Sharpe| > 100. Esse é um desvio exploratório documentado.
  • OLS + SEs clusterizados por família substituindo MixedLM. Covariância singular dos efeitos aleatórios em n_windows = 7 quebrou o REML. O estimador travado preserva a intenção robusto-a-clusters (clusters em família) e reproduz a mesma estrutura de efeitos fixos do modelo do pré-registro.
  • OLS within-transform substituindo a verificação cruzada R / lme4. R indisponível; a demeaning analítica foi implementada em Python em vez disso. A concordância Δβ < 1e-13 no piloto SOL é a verificação.

Resultados do piloto SOL

O piloto rodou em SOL_1h_7W, a partição walk-forward de 7 janelas do escritório em barras SOL/USDT 1h. Após o piso de n ≥ 30 estratégias-por-célula, n_cells = 42 em 7 famílias × 6 transições (RSI_LEVEL excluído). O ajuste primário é:

  • βsmooth = +0,115micro padronizado)
  • SE = 0,121, t = +0,95
  • punilateral (H1: β < 0) = 0,829
  • pperm (M = 1000) = 0,843
  • f² = 0,038 (logo abaixo do piso de 0,04 para elevação a artigo)
  • Implementação cruzada: βwithin = +0,115, Δ = 1,1 × 10⁻¹³

No nível agregado, o sinal de βsmooth é oposto ao que H1prevê: em SOL_1h_7W, as células IS-mais-pontiagudas, em média, performam ligeiramente melhor do que as células IS-mais-suaves na próxima janela. Isso está longe de ser significativo, o nulo de permutação está centrado em −0,004 com desvio-padrão 0,118, e o +0,115 observado fica confortavelmente dentro dele (pperm = 0,843). H0 é retido no nível agregado no piloto.

Fig. 1:Piloto SOL_1h_7W. Cada ponto é uma célula (família, janela): x = σ_micro médio entre o top-K IS, y = R_K (Sharpe OOS-base médio na janela w+1). Cor por família. A linha de regressão within-cluster tem β_smooth = +0,115, inclinação positiva, oposta à H₁ direcional. Células ATR (escuras) e RSI (laranja) formam uma sub-inclinação negativa clara; EMA, STOCHK e MACD puxam o agregado para o outro lado.
Fig. 2:Nulo de permutação (M = 1000) para β_smooth no piloto SOL. Média do nulo −0,004, std do nulo 0,118; quantis q05 = −0,20, q95 = +0,19. β_smooth observado = +0,115 fica no 84º percentil do nulo. O p_perm unilateral contra H₁ é 0,843. O nulo é bem-calibrado: sob construção-por-embaralhamento, a taxa de Erro Tipo I empírica em α = 0,05, 0,01 reproduz os níveis nominais.

Detalhamento por família

Agregar obscurece heterogeneidade real. Dividir por família e fazer correção BH entre as oito famílias dá um quadro mais nítido:

  • ATR: β = −0,33, pBH < 0,0001. Apoia fortemente a hipótese, dentro de ATR, células IS-mais-suaves batem células IS-mais-pontiagudas out-of-sample por uma ampla margem.
  • RSI: β = −0,38, pBH = 0,28. Sinal certo, magnitude grande, mas n_cells dentro de RSI é pequeno o suficiente para que BH não rejeite.
  • PPO, SMA: β fracamente negativo, nenhum próximo da significância BH.
  • EMA, STOCHK, MACD: β positivo. EMA e STOCHK são as duas famílias que dirigem a inversão de sinal agregada. Ambas são famílias estilo momentum com superfícies de Sharpe IS mais rasas; a região σmicro = 0 dentro delas parece coincidir com uma região plana de RK em vez de uma crista de RK alta.

Leia o piloto honestamente: no nível populacional, suavidade não prevê skill OOS em SOL. No nível de família, prevê dentro de ATR (e provavelmente RSI, dadas mais células), e não prevê dentro das famílias de momentum. A alegação verbal do corpus é, com base nessa evidência, família-condicional em vez de universal.

As próprias superfícies

Números resolvem a questão empírica; as superfícies mostram o que estamos chamando de suave e pontiagudo. Abaixo: a paisagem de Sharpe IS para cada família, computada na janela walk-forward média (W = 4) em SOL/USDT 1H, exibida sobre a grade de parâmetros (transformação × confluência). Cada painel é anotado com σL (uma métrica de suavidade Laplaciana discreta, menor é geometricamente mais suave) e o βsmooth por família do pool de replicação (negativo apoia a hipótese). Ordenado suave → pontiagudo.

PPO
β = +0.16
σL = 0.952n = 223
ATR
β = -0.85
σL = 1.120n = 223
STOCHK
β = +0.42
σL = 1.289n = 223
RSI
β = -0.09
σL = 1.328n = 223
MACD
β = +0.63
σL = 1.647n = 220
EMA
β = +0.32
σL = 1.675n = 223
SMA
β = +0.01
σL = 1.899n = 223

Each panel: IS Sharpe surface over the (transformation × confluence) grid for one family on SOL/USDT 1H, mid walk-forward window, median over base-parameter and SL-regime slices. Camera orbits 360° in 20 s. σL = discrete-Laplacian smoothness (lower = smoother). β = per-family OLS slope of RK on σmicro from the replication pool (negative = hypothesis-supporting; positive = anti-hypothesis). Videos are lazy-played: decoding pauses when the section scrolls offscreen. Sorted smoothest → spikiest by σL.

As superfícies mais suaves por σL são PPO (0,95) e ATR (1,12); as mais pontiagudas são EMA (1,68) e SMA (1,90). Se a alegação verbal do corpus fosse uma lei linear limpa, esses rankings de σLdeveriam acompanhar o β por família. Não acompanham, exatamente. ATR, a mais suave das famílias com um β negativo grande, está do lado hipotetizado; MACD e EMA, as famílias com os maiores βs positivos, são visivelmente mais pontiagudas, também do lado hipotetizado. Mas PPO é a superfície mais suave e ainda assim carrega β = +0,16, e SMA é a mais pontiaguda mas carrega β ≈ 0. A relação entre suavidade geométrica em uma janela e suavidade preditiva em todas as transições é real mas parcial. Essa parcialidade é exatamente o que o resultado agregado com H0 retido reflete.

Fig. 3:Small-multiple por família de σ_micro vs R_K no piloto SOL. ATR (canto superior esquerdo, β = −0,33***) é o caso mais limpo dentro da família apoiando a hipótese. RSI mostra o mesmo sinal com células insuficientes para rejeitar BH. EMA, STOCHK e MACD mostram inclinações positivas dentro da família, as células IS-pontiagudas nessas famílias não pagam um custo OOS em SOL. O β agregado = +0,115 é uma mistura ponderada pela população desses três regimes.

Replicação em DOGE + BTC

A replicação parseia DOGE_30m_21W (Δt = 30m, 21 janelas walk-forward) e BTC_30m_27W (30m, 27 janelas) e os pooled. Os hiperparâmetros travados de 1badde4 aplicam inalterados: mesma suíte de cinco perturbações, mesmo K = 5, mesmo piso n ≥ 30, mesmo descarte |Sharpe| > 100, mesmo OLS + SEs clusterizados por família, mesmo nulo de permutação M = 1000. n_cells pooled ≈ 322; a triangulação por ativo separa SOL, DOGE e BTC separadamente.

Pooling DOGE (ncells = 140) e BTC (ncells = 182) resulta em βsmooth = −0,058 com SE robusto a clusters 0,126, pperm unilateral = 0,272 (M = 1000) e tamanho de efeito f² = 0,0002. O sinal agora bate com a hipótese, pela primeira vez entre as três estimativas rodadas neste corpus, mas a magnitude é pequena relativa à variância residual entre células e o resultado fica confortavelmente dentro do nulo. A verificação cruzada entre OLS e o within-transform diverge para |Δβ| = 0,016 na amostra maior (vs 1×10−13 no piloto); o gap é dirigido pela codificação de contrastes no design desbalanceado de ativo / janela, e ambos os estimadores concordam em sinal e ordem de magnitude.

A triangulação por ativo é onde o quadro fica inequívoco. SOL β = +0,115 (n = 42); DOGE β = +0,163 (n = 140); BTC β = −0,210 (n = 182). O sinal inverte entre DOGE e BTC, e nenhum é significativo por si só. Não há relação coerente em nível populacional aqui. O β pooled < 0 é a média algébrica ponderada de uma aposta positiva e uma aposta negativa; não é evidência para a hipótese.

Fig. 4:Triangulação por ativo de β_smooth com intervalos de confiança 95% robustos a clusters na especificação primária. Piloto SOL β = +0,115 (n = 42); DOGE β = +0,163 (n = 140); BTC β = −0,210 (n = 182). A inversão de sinal entre partições de ativo é o resumo de uma linha mais forte do resultado: sob a definição operacional de σ_micro que o pré-registro especifica, a sensibilidade a perturbação não prevê o Sharpe OOS da próxima janela de uma forma que sobreviva à mudança de ativo.

O detalhamento por família no pool de replicação (correção BH dentro da família dos sete testes secundários; RSI_LEVEL é excluído pelo piso n ≥ 30) conta uma história mais nuançada. ATR β = −0,850 (p não corrigido = 0,044, pBH = 0,310), a maior única inclinação negativa dentro de família em todo o estudo, e a única família com um sinal replicando entre piloto e replicação. RSI β = −0,090 (pBH = 0,888); EMA, MACD, PPO, SMA, STOCHK todos positivos (β entre +0,011 e +0,631; todos pBH = 0,888). Após correção BH nada cruza α = 0,05, mas o achado estrutural, ATR (e fracamente RSI) comporta-se como a alegação verbal prevê; famílias de momentum comportam-se de forma oposta, é consistente entre piloto e replicação.

Critério de elevação a artigo (travado, avaliado)

O pré-registro exigia os três:

  • replicação pperm < 0,01, obteve 0,272. Falha.
  • βsmooth com sinal consistente < 0 entre SOL / DOGE / BTC, obteve +0,115, +0,163, −0,210. Falha.
  • f² ≥ 0,04, obteve 0,0002. Falha.

O critério é falhado nos três limiares simultaneamente. O resultado não eleva a artigo; a frase da página do corpus é reescrita conforme o ramo 3 do pré-registro abaixo.

O que isso significa para a alegação do corpus

Três ramos foram pré-especificados, com o plano de reescrita para /corpus committado antecipadamente:

  • Apoio forte (replicação pperm < 0,01, β < 0, f² ≥ 0,04). A frase do corpus mantém sua forma atual e ganha uma nota de rodapé linkando aqui. Um artigo autônomo sobre a estrutura família-condicional (ATR/RSI vs famílias de momentum) é publicado.
  • Apoio fraco (replicação pperm < 0,05, sinal consistente, f² < 0,04 ou um dos três critérios falha). A frase do corpus é reescrita para: “dentro de famílias de mean-reversion, cristas suaves in-sample mostram evidência fraca de generalizar melhor OOS do que picos afiados; famílias de momentum não mostram esse padrão, e a alegação no nível populacional não é apoiada.” Apenas página de lab; sem artigo separado.
  • Nulo / sinal-invertido (replicação NS ou positivo com sinal consistente). A frase do corpus perde sua redação absolutista e é substituída por: “suavidade in-sample sob perturbação microestrutural não é um preditor de nível populacional de skill out-of-sample no corpus que testamos. Análise no nível de família é necessária.” A página de lab reporta o nulo de forma limpa e aponta o leitor para a figura de heterogeneidade por família.

O piloto já dá razão para esperar que o writeup caia em algum lugar entre o segundo e o terceiro ramo. ATR é real; a alegação no nível populacional provavelmente não é. O trabalho da replicação é dizer qual dos dois é a manchete.

Demos ao vivo

A superfície 3D, ao vivo

Os MP4s acima são visualizações pré-renderizadas de sete superfícies específicas do corpus. O demo abaixo permite que você molde uma superfície você mesmo: gire o slider de suavidade em direção a 1 para obter um sino largo (a “cara de ATR”), arraste-o em direção a 0 para obter um pico estreito afiado cercado por colapso (a “cara de MACD”). O slider de ruído de perturbação adiciona jitter de alta frequência, o análogo empírico de σmicro. O readout de σL atualiza em tempo real. A malha é intencionalmente low-poly (32×32 = 1.024 vértices, material único, uma única passagem de wireframe) para que mesmo um celular fraco possa rotacioná-la a 60 fps sem dificuldade.

smoothness (1 = wide bell · 0 = sharp peak)
0.85
perturbation noise (high-freq jitter)
0.020
σL (Laplacian energy)
0.0125
Lower σL = geometrically smoother; the corpus values ranged 0.95 (PPO, smoothest) to 1.90 (SMA, spikiest).
presets
Drag the surface to rotate freely; wheel / pinch to zoom. Auto-rotate stops once you interact.
INITIALIZING WEBGL…

Synthetic IS Sharpe surface, 32×32 mesh, vertex-coloured by height. The smoothness slider interpolates between a wide low bell (smooth basin under perturbation, hypothesised to generalise OOS) and a narrow tall spike with flat collapse around it (brittle peak, hypothesised to overfit). The perturbation noise slider adds high-frequency jitter that approximates what σmicro measures empirically. σL in the panel updates live so you can see how the geometry and the smoothness metric move together.

O scatter (σ, R), ao vivo

Lente diferente, mesmo projeto. Este segundo demo permite que você passe pela relação simulada entre σmicro e RK para uma única família sob um β subjacente e tamanho de amostra ajustáveis. Não é um ajuste ao corpus, o resultado do corpus está nas figuras acima e no parquet de replicação, mas constrói intuição do que βsmooth = ±0,3 realmente parece como scatter, e o quão fácil é ser enganado por 42 células ruidosas.

true β (population)
β = -0.30
n cells
n = 42
residual noise σ
σ_ε = 0.60
fitted slope
H₀ retained (β̂ = -0.09, p = 0.732)
try the per-family β observed on the corpus
-1.0-0.50.00.51.00.51.01.5σ_microR_Kfitted: β̂ = -0.09true: β = -0.30

Synthetic. The dashed grey line is the true β; the amber line is the fitted slope on this sample. Resample to see how often the sign flips at small n. The pre-registered article criterion was f² ≥ 0.04, try setting β = −0.3 with n = 42 vs n = 322 and watch how visibility-of-effect changes. The corpus pilot was n = 42; the replication pool was n = 322.

Reprodutibilidade

DaruFinance / quant-surface-stability

Python · implementação de referência open-source

Invocação mínima

# Reproduce: pre-reg locked at 8e62171; hyperparameter lock at 1badde4
git clone https://github.com/DaruFinance/quant-surface-stability.git
cd quant-surface-stability

# 1. Parse strategy text dumps -> parquet (Rust, ~1m per asset)
cargo run --release --bin parse_corpus -- --asset SOL_1h_7W

# 2. Build cell-level (family x asset x window) metrics
python scripts/compute_metrics.py --asset SOL_1h_7W

# 3. Primary fit: sigma_micro x R_K, OLS + family-clustered SEs,
#    permutation null with M=1000, within-transform cross-check.
python scripts/fit.py --asset SOL_1h_7W --primary
# beta_smooth = +0.115   p_perm = 0.843   f^2 = 0.038
# cross-impl. delta = 1.1e-13   --> H_0 retained at aggregate level

Referências

  1. [1]Bailey, D. H. & López de Prado, M. (2014). The probability of backtest overfitting. Journal of Computational Finance 20(4), 39–69.
  2. [2]Harvey, C. R. & Liu, Y. (2014). Backtesting. Journal of Portfolio Management 42(1), 13–28.
  3. [3]Carrasco, M. & Maciel, L. (2020). Robustness of in-sample optimisation in trading rule selection: a parameter-stability perspective. Quantitative Finance 20(11), 1799–1816.
  4. [4]Benjamini, Y. & Hochberg, Y. (1995). Controlling the false discovery rate: a practical and powerful approach to multiple testing. Journal of the Royal Statistical Society B 57(1), 289–300.