| name | quant-validation |
| description | Metodología de validación para estrategias cuantitativas en cripto perpetuos. Úsala al diseñar splits de validación, al evaluar métricas de un backtest o modelo, o al auditar resultados. Cubre leakage temporal, deflación por multiple testing, costes y mecánica de perpetuos, calidad de datos y cobertura de régimen. |
Validación quant — cripto perpetuos
Aplica lo que corresponda al caso concreto; no todo aplica siempre. El criterio
es el horizonte del label, el apalancamiento y el tipo de estrategia.
1. Leakage temporal
- Con labels de horizonte > 1 barra: purged K-Fold con embargo, o CPCV
(Combinatorial Purged CV).
KFold(shuffle=True), train_test_split
aleatorio o cross_val_score estándar sobre series temporales = leakage.
- Purge ≥ horizonte máximo del label; embargo adicional para romper la
correlación serial entre el final del test y el siguiente train.
- La barra de cierre NO existe en su timestamp de apertura. Verificar que cada
feature usa solo información disponible en el momento de la decisión.
- Walk-forward (anchored o rolling) es complemento del purged CV, no sustituto.
2. Deflación por multiple testing
- Registrar N = número de configuraciones probadas en total (feature sets,
hiperparámetros, variantes de reglas). Sin N no hay evaluación seria.
- Deflated Sharpe Ratio calculado con ese N. Gate: DSR > 0.95.
- Probability of Backtest Overfitting vía CSCV. Gate: PBO < 0.2
(entre 0.2 y 0.5 solo con reservas explícitas).
- t-stat > 3.0 para señales nuevas (Harvey-Liu-Zhu), no el 2.0 clásico.
- Minimum Backtest Length: con poco histórico el presupuesto de ensayos es
pequeño (orden de magnitud: ~45 configuraciones con 5 años de datos para un
objetivo de Sharpe 1). No excederlo; si se excedió, reportarlo.
3. Costes y mecánica de perpetuos
- Funding en el PnL, con la frecuencia del exchange (8h en Binance/Bybit/OKX,
1h en Hyperliquid). Un backtest de posiciones multi-hora sin funding es
inválido.
- Mark price para PnL y liquidación; index price para funding; last price solo
informativo. Usar el precio equivocado hace el backtest irreproducible.
- Con apalancamiento: modelar la liquidación contra mark price (y ADL en
escenarios de estrés). Un backtest apalancado que nunca liquida no informa.
- Comisiones maker/taker reales del tier + slippage (regla square-root como
modelo base: impacto ∝ σ·√(tamaño/volumen)).
- Capacidad estimada con profundidad de libro real, no con volumen reportado
(el volumen de muchos exchanges está inflado por wash trading).
4. Datos y régimen
- Universo point-in-time: incluye tokens delistados y exchanges caídos. El
universo de hoy tiene survivorship bias.
- Cobertura multi-régimen (alcista, colapso, lateral). Un backtest que solo ve
un régimen es una anécdota — p. ej. empezar en 2021 o en 2023.
- Las klines de exchange pueden revisarse retroactivamente: registrar el
timestamp de captura de los datos y tratar huecos explícitamente.
5. Patrones de detección en código (auditoría)
Ocho violaciones concretas y cómo encontrarlas leyendo el código. Adaptadas a
cripto perpetuos. Un solo hallazgo de 1–6 invalida las métricas reportadas.
V1 — Normalización con muestra completa. z-score o scaler ajustado sobre
toda la serie y aplicado a todo el histórico.
Buscar: x.mean() / x.std() sin .rolling()/.expanding();
StandardScaler().fit(X) sobre el dataset completo; (x - x.mean())/x.std().
Correcto: rolling/expanding window, o fit solo en train de cada split.
V2 — Cuantiles/ranks con muestra completa. Agrupar por quintiles o rankear
usando umbrales calculados con datos futuros.
Buscar: pd.qcut(factor, q=...) sobre la serie entera; df.quantile() global;
rank(pct=True) sobre toda la columna en vez de por fecha/sección cruzada.
Correcto: cuantiles por sección cruzada de cada timestamp, o expanding.
V3 — Cierre de T usado para decidir en T. La señal de la barra t usa el
close de t, y el backtest ejecuta al close de t.
Buscar: signal[t] calculada con close[t] y fill al mismo close[t];
features e índice de ejecución compartiendo el mismo timestamp.
Correcto: señal con información ≤ t-1 (o al cierre de t), ejecución en la
apertura/primer trade de t+1, con slippage.
V4 — Leakage en ML. Splits que mezclan futuro con pasado.
Buscar: train_test_split(..., shuffle=True) o KFold estándar sobre series;
scaler/encoder ajustado antes del split; train con fechas posteriores al test;
ausencia de purge/embargo con labels de horizonte > 1 barra.
Correcto: TimeSeriesSplit o purged K-Fold/CPCV con embargo ≥ horizonte del label.
V5 — Selección de factores con estadísticos de muestra completa. Calcular
IC/ICIR sobre todo el histórico, elegir los "buenos" factores, y recién después
backtestear con ellos: la selección ya vio el futuro.
Buscar: factor.corr(forward_return) global antes del loop de backtest;
filtrado de features por importancia calculada sobre todo el dataset.
Correcto: la selección vive dentro del loop, con IC rolling hasta t.
V6 — Survivorship en el universo. Construir el universo con información
futura: excluir desde el inicio lo que después fue delistado o el exchange que
después quebró.
Buscar: lista fija de símbolos "actuales" aplicada a todo el histórico;
filtros por volumen/market cap calculados con datos de hoy.
Correcto: universo re-evaluado en cada fecha con el estado conocido entonces.
V7 — Restricciones de ejecución de perps ignoradas. El backtest opera como
si el exchange no existiera.
Buscar: tamaños de orden sin redondear a stepSize/minQty/min notional;
apalancamiento fijo que ignora los tiers de margen por tamaño; PnL sin funding;
liquidación contra last price (o sin liquidación); fills durante ventanas de
downtime o cascadas donde en la práctica la API no respondía.
Correcto: filtros de exchange aplicados, funding en el PnL, liquidación contra
mark price, y fills penalizados o excluidos en percentiles extremos de estrés.
V8 — Timestamps incoherentes. Mezclar exchange time con hora local, o
re-descargar klines que el exchange revisó y asumir que son las mismas.
Buscar: datetime.now() en pipelines de features; datos sin timezone explícito;
ausencia de timestamp de captura en los datasets.
Correcto: todo en UTC del exchange, timestamp de captura registrado en la
data card, y diffs verificados al re-descargar.
6. Robustez y atribución
- Estabilidad de parámetros: la performance debe sostenerse en el VECINDARIO
del parámetro elegido, no solo en el pico. Si lookback=20 da Sharpe 1.8 pero
15 y 25 dan 0.3, es un artefacto de optimización. Reportar la curva o
superficie de sensibilidad, no el punto ganador.
- Robustez por remuestreo: bootstrap de trades/retornos o Monte Carlo
(reordenar bloques, perturbar fills con ruido de slippage, jitter en
timestamps de entrada) para obtener la DISTRIBUCIÓN del resultado, no un
único camino histórico. Si el intervalo incluye cero con comodidad, no hay
señal.
- Atribución de PnL (obligatoria en perpetuos): descomponer el retorno en
componente de precio, funding, comisiones y slippage. Una estrategia cuyo
PnL es 90% funding capturado tiene un perfil de riesgo y de capacidad
totalmente distinto a una direccional, aunque el Sharpe sea idéntico.
- Riesgo de cola: además de volatilidad y max drawdown, reportar
CVaR/expected shortfall y la peor racha de pérdidas. La media y la desviación
no describen un instrumento apalancado con liquidaciones.
7. Señales de alarma (para auditoría rápida)
- Sharpe > 2 reportado sin DSR/PBO ni N de ensayos.
- Splits de validación "a mano" sin purga documentada.
- Criterio de éxito redactado o modificado después de ver resultados.
- PnL que "mejora al quitar costes para ver la señal pura".
- Métricas calculadas sobre un solo régimen de mercado.
- Estrategia cuyo retorno depende de operar exactamente durante cascadas de
liquidación o caídas de exchange (cuando en la práctica no se puede ejecutar).