Golden SkyGolden SkyGuía Técnica

Referencia técnica · Paso 11 · OOS Testing

Confirmación y degradación

La única data que ninguna fase anterior vio. El OOS no busca estrategias nuevas: confirma las que el walk-forward ya validó, sobre una ventana reservada, y mide cuánto se degrada su ventaja fuera de la muestra de descubrimiento.

§0Notación

oos_startfecha de corte IS → OOS
ISin-sample (todo lo previo al corte)
OOSventana reservada, nunca vista
wfv_pfPF pooleado del walk-forward
pf_changedegradación relativa del PF
decaycaída de PF tolerada por el gate

§1Confirma, no busca

El OOS solo scorea los combos que el walk-forward marcó como FDR-significativos. No testea todo el pool — hacerlo sería empezar una segunda búsqueda sobre datos frescos.

Por qué solo los validados. Testear también los perdedores del WFV en OOS es una segunda búsqueda: entre suficientes candidatos, algunos "ganan" en la muestra OOS por puro azar. Eso convierte el OOS de confirmación en descubrimiento — y contamina la última data limpia que queda. Validado = FDR-significativo (el gate estadístico del WFV).

Fallback exploratorio: si ningún combo fue FDR-significativo (Monte Carlo apagado o nada pasó), el OOS testea los de PF pooleado > 1 con un warning explícito — "un 'pasa' acá no equivale a validación estadística". Es exploración, no confirmación.

§2Preparar los datos sin filtrar futuro

El riesgo del OOS es que la preparación de features "vea" el futuro. Tres piezas data-dependientes se manejan fit-en-IS / apply-a-OOS.

prepare_oos_features build_feature_frame( df_full )  // mismo transform que el step de indicadores
→ las filas IS salen idénticas por construcción (causalidad, test de identidad)
PiezaCómo se evita el leakage
WinsorizaciónLos bounds (clip de outliers) se aprenden solo con las filas IS y se aplican a toda la serie → el OOS se clipea con bounds del pasado, el IS queda idéntico.
σ GARCHÚnico caso leakage-sensitive: no se fitea sobre el full. Se fitea en IS y se forecastea a OOS (extend_conditional_volatility_oos). Las demás policies (ATR, %, bar extreme, fija) son causales → computarlas sobre el full y windowear no filtra nada.
TargetsLos Target_* forward-looking de barras IS en la frontera miran barras OOS → "contaminados" por diseño. Inofensivos: el scoring OOS no usa targets, solo features causales + régimen + OHLC. Nunca se usan para re-seleccionar sobre OOS.

§3Mismo motor, otra ventana

El scoring OOS usa exactamente el mismo motor que el backtest y el walk-forward. La única diferencia es la ventana de datos — nunca la fórmula.

run_window_backtest ventana = [ oos_start_idx , n )  // frontera por timestamp
misma exit policy, costos, triple-swap y block_unknown_regime
exit acotado al fin de ventana  // un trade tardío cierra en el límite, sin mirar más allá

Las métricas se computan con el mismo compute_metrics (igual initial_capital, periods_per_day, pf_cap) que el ranking del Step 9. Invariante del pipeline: las métricas OOS e IS se calculan idénticas — lo único que cambia es la ventana de datos, no la definición. El excluded_regimes del combo se hereda inmutable y se aplica en el motor.

§4Degradación y gate

Se compara el PF OOS contra el del WFV. El gate exige que el rigor NO se afloje respecto del WFV — al contrario de lo que sería tentador para la "prueba final".

pf_change pf_change = oos_pf − wfv_pf| wfv_pf |  // positivo = se sostiene o mejora

min_trades, min_profit_factor y max_pf_decay son parámetros de entrada (defaults abajo).

passed ⟺ oos_total_trades ≥ min_trades (default 15)
  Y oos_pf ≥ min_profit_factor (default 1.15 — igual que el WFV)
  Y pf_change ≥ −max_pf_decay (default 0.50 → tolera perder hasta 50% del PF)

Audit fix #4 — la progresión de rigor no se invierte. Sería un error clásico que el gate final (OOS) fuera el más laxo de la cadena: dejaría pasar en la última prueba lo que las anteriores habrían frenado. Por eso min_profit_factor es ≥ el del WFV, no menor. El orden de salida pone primero los que pasan, luego por PF OOS (no por Δ PF, para no premiar a un perdedor que "mejora" mucho desde un PF bajo).

§5Qué significa (y qué no)

El OOS es, conceptualmente, la prueba más fuerte: es la única data que ningún paso del descubrimiento tocó. Pero es una herramienta más, no un veredicto absoluto.

Confirma, no consagra. Un "pasa" en OOS dice que el edge se sostuvo sobre datos frescos con el rigor del WFV — no que la estrategia esté lista para real. Sigue el transfer (§12): ver si la ventaja se traslada a instrumentos emparentados, no solo a otra ventana temporal del mismo activo. Y la decisión final de mandar a real es del trader, no de un gate.

Viene de 10 (WFO) y 9 (WFV, fuente de los combos). Sigue en 12: transfer a instrumentos emparentados.

Fuentes:
· services/oos_service.py — prepare_oos_features (fit-IS/apply-OOS), execute_oos, gate
· domain/validation_common/window_backtest.py — run_window_backtest (motor único, block_unknown)
· domain/backtester/garch.py — extend_conditional_volatility_oos
· domain/indicators_quality/winsorize.py — compute/apply_winsorization_bounds
· webapp/docs/STEPS_10_12_MIGRATION_PLAN.md §2.2 — data-prep leakage-safe, audit fix #4