ADR-001: CPCV em vez de Walk-Forward simples¶
Status: ✅ Accepted (2026-04)
Contexto¶
Na época da v1.x usávamos Walk-Forward sequencial (WF):
[train 1500 bars][gap 10][val 300 bars] → fold 1
[train 1500 bars][gap 10][val 300 bars] → fold 2
...
Total: 5 folds → 5 estimativas de AUC por modelo.
Problemas:
- Variância alta em 5 pontos não permite calcular percentil confiável
- Overfit ao último fold (mais recente, viés temporal)
- Underutilização dos dados (cada barra é vista em 1 train, 1 val)
- Não captura distribuição de performance sob diferentes ordens
Decisão¶
Adotar CPCV — Combinatorial Purged Cross-Validation (Lopez de Prado, AFML 2018, cap. 12).
# configs/model.yaml
walk_forward:
use_cpcv: true
cpcv_n_splits: 6 # divide série em 6 grupos
cpcv_n_test: 2 # 2 grupos viram teste em cada combinação
Com 6 splits e 2 grupos de teste:
$$ \binom{6}{2} = 15 \text{ combinações de paths} $$
Cada modelo tem 15 estimativas AUC/PF em vez de 5. Permite:
- AUC mediana + AUC p5 (5º percentil) — robust statistics
- Purge automático entre train e test (evita lookahead)
- Embargo após cada bloco (evita autocorrelation contamination)
Gate na promoção¶
promotion:
min_auc: 0.58 # mediana das 15 paths
min_auc_p5: 0.55 # 5º percentil das 15 paths (robusto)
Um modelo só passa se a mediana for forte E o pior caso for aceitável.
Alternativas consideradas¶
A. Walk-Forward com mais folds (10+)¶
Por que não: sequencial = ainda 1 estimativa por fold = mesmo problema. Mais folds só dispersa dados.
B. K-Fold tradicional shuffled¶
Por que não: quebra série temporal. Look-ahead severo.
C. Time Series Split (sklearn)¶
Por que não: equivalente a WF sequencial. Mesmas limitações.
D. CPCV completo (Lopez de Prado original)¶
Considerei cpcv_n_splits: 10 com cpcv_n_test: 4 → 210 paths. Trade-off:
- Pros: estatística super-robusta
- Cons: treino 14× mais lento (210/15)
Escolhi balance: 15 paths é bom e treina em tempo razoável (~4h para 56 modelos).
Consequências¶
Positivas¶
- 71/72 modelos aprovados com gates de v2.27 (98.6%)
- Distribuição de AUC visível (média 0.61, p5 0.57)
- Auto-rollback CUSUM funciona melhor com baseline rico
- Permite ECE percentil também
Negativas¶
- Treino mais lento (3x walk-forward simples)
- Implementação mais complexa em
app/models/cv.py - Memory footprint maior durante CV (mantém 15 estados)
Mitigações¶
- Paralelização: cada combinação em thread separada
- Cache de features (computadas 1× e reusadas)
- LightGBM
early_stopping_rounds: 50corta CV cedo se overfit
Referências¶
- Lopez de Prado, Advances in Financial Machine Learning, 2018 — cap. 12 (CV em finanças) e cap. 7 (Cross-Validation Frameworks)
- Implementação em
app/models/cv.py - Hyperparams em
app/models/optuna_cpcv.py