La única herramienta es un walk-forward rolling, y lo que valida no es un conjunto de parámetros.
Has leído la misma frase en los libros, e incluso en nuestro propio Cómo leer un backtest: no optimices sobre todos los datos, reserva al menos un 20–30% para validación fuera de muestra. Y entonces abres el espacio de trabajo, vas pinchando pestaña por pestaña, y ese ajuste de proporción no aparece por ninguna parte.
Que no lo encuentres es normal: el producto no tiene esa función. El asunto de «fuera de muestra» tiene en Blave una sola implementación: el walk-forward rolling de la quinta pestaña, donde lo que se rellena son días y donde lo que se valida tampoco es exactamente lo mismo que una división simple. Este artículo deja claro dónde está la diferencia y cómo se lee cada número de esa pestaña.
En Cómo evitar el sobreajuste hay una tabla que califica tres formas de hacerlo: optimizar sobre todos los datos (inútil), entrenar con el primer 70% y probar con el último 30% (útil pero limitado), y reelegir con ventana deslizante (lo más realista). Esa tabla es un juicio en el plano conceptual; el hecho en el plano del producto es que solo la tercera tiene botón.
| Forma de hacerlo | Conceptualmente | En Blave |
|---|---|---|
| Optimizar con todo el histórico y reportar sobre todo el histórico | Dentro de muestra, necesariamente optimista | La pestaña Backtest ya calcula el resultado sobre todo el histórico de por sí, y justo por eso hace falta validar aparte |
| Un solo corte: entrenar con la parte de delante, probar con la de atrás | Útil, pero solo se puede usar una vez | Esta función no existe; no hay ningún ajuste de proporción que encontrar |
| Walk-forward rolling: reelegir en cada ronda, probar el tramo siguiente | Lo más parecido a operar en real | La quinta pestaña del espacio de trabajo, «Fuera de muestra» |
La diferencia no es solo de interfaz. Una división simple valida si «este conjunto de parámetros va bien sobre los datos de la parte final»; un walk-forward rolling valida si la práctica misma de «elegir parámetros a partir del histórico» se sostiene en esta estrategia — repite n veces el acto de «elegir parámetros con un tramo de histórico» y puntúa cada vez con el tramo siguiente, que no ha visto.
En una frase: volver a elegir parámetros dentro de cada ventana de entrenamiento, aplicarlos a la ventana de prueba que viene justo después y unir todas las ventanas de prueba en una sola línea.
| Ronda | Ventana de entrenamiento | Ventana de prueba |
|---|---|---|
| 1 | 2022-01-05 → 2024-12-30 | 2024-12-31 → 2025-01-29 |
| 2 | 2022-02-04 → 2025-01-29 | 2025-01-30 → 2025-02-28 |
| 3 | 2022-03-06 → 2025-02-28 | 2025-03-01 → 2025-03-30 |
| … | (las rondas intermedias avanzan igualmente una ventana de prueba cada vez, 20 rondas en total) | |
| 20 | 2023-07-29 → 2026-07-23 | 2026-07-24 → 2026-08-22 |
Las ventanas de prueba se unen extremo con extremo al día: la ronda 1 termina en 2025-01-29 y la ronda 2 enlaza desde 2025-01-30, sin hueco ni solape en medio — los 20 tramos unidos son esa serie fuera de muestra.
Las ventanas de entrenamiento, en cambio, se solapan muchísimo: una ventana de tres años avanza solo 30 días por ronda, así que el período de entrenamiento de dos rondas cualesquiera es prácticamente el mismo tramo de datos. Lo que se solapa no se puede coser en una línea continua — y por eso en el gráfico solo está la de fuera de muestra.
En la implementación hace dos pasadas: la primera calcula la señal de cada conjunto de parámetros candidato una sola vez sobre todo el histórico y recorta de ahí el tramo de entrenamiento de cada ronda para valorarlo; la segunda solo recalcula el conjunto ganador de cada ronda, enhebra los tramos de prueba en una sola serie y valora el tramo entero de una vez. Por eso es muchísimo más rápido que «lanzar n barridos completos» — el ejemplo de abajo, de 20 rondas y 4.7 años en horario, terminó en 3.5 segundos en la ejecución del 2026-09-17 (el diálogo de confirmación de la interfaz da el caso general: «Suele tardar unos dos minutos; los resultados aparecen en esta pestaña.»).
Rolling es que la ventana de entrenamiento se desliza entera hacia delante en cada ronda; anchored es que el inicio queda fijo y la ventana de entrenamiento se va haciendo cada vez más larga. El producto solo ofrece rolling; anchored no se ofrece a propósito. Si le pides anchored al agente, responde con una frase fija y luego ejecuta rolling igualmente:
Tampoco vale la pena buscarle la vuelta: la lib que ejecuta el walk-forward es de solo lectura y el proceso residente rechaza la edición sin más; y además el archivo de resultados no tiene ningún campo para marcar «esto se ejecutó como anchored», así que aunque lo cambiaras de verdad, la pantalla seguiría mostrándolo como rolling.
En la pestaña solo hay dos casillas: ventana de entrenamiento y ventana de prueba, ambas en días, con un indicador al lado que muestra al momento cuántas rondas salen. Si dejas las dos en blanco, se aplica esta tabla por defecto:
| Longitud de los datos (días) | Ventana de entrenamiento (días) | Ventana de prueba (cada cuánto se reelige, en días) |
|---|---|---|
| ≥ 1185 | 1095(tres años) | 30 |
| 455–1184 | 365(un año) | 30 |
| < 455 | 4 veces la ventana de prueba | días totales ÷ 12, mínimo 30 |
Ese escalón de tres años tiene su razón: se acerca más a lo que la gente hace de verdad, que es elegir un conjunto fijo de parámetros a partir de todo el backtest. Si a un histórico de longitud media se le aplicara la fórmula de proporción sin más, la ventana de entrenamiento saldría por debajo del año, así que en medio se añadió el escalón de 365 / 30.
Dos límites duros lo paran en seco en lugar de darte un resultado a medias: por debajo de 3 rondas no se ejecuta ni se escribe el archivo de resultados («Los datos solo dan para {n} rondas; hacen falta 3 como mínimo para leer algo fuera de muestra»); por encima de 1000 rondas se bloquea igual («amplía la ventana de prueba»). Los datos sobrantes de la cola que no completan una ronda no se fuerzan, y debajo del gráfico se anota «los últimos {d} días no llegan a una ronda y quedan excluidos».
La tarjeta de conclusión mira un solo número:
WFE = Sharpe fuera de muestra ÷ Sharpe medio dentro de muestra
El numerador es el Sharpe de todo el tramo ya unido de la serie fuera de muestra; el denominador es la media del Sharpe propio de la celda ganadora dentro de la ventana de entrenamiento de cada ronda. Las cuatro etiquetas siguen estas fronteras (todas son «menor que», así que 0.5 cae en «justo por encima del umbral» y 0.7 en «por encima del umbral»):
| WFE | La tarjeta de conclusión muestra |
|---|---|
| No se puede calcular | Eficiencia fuera de muestra: no se puede juzgar |
| < 0.2 | Eficiencia fuera de muestra: muy por debajo del umbral |
| < 0.5 | Eficiencia fuera de muestra: por debajo del umbral |
| < 0.7 | Eficiencia fuera de muestra: justo por encima del umbral |
| ≥ 0.7 | Eficiencia fuera de muestra: por encima del umbral |
Y la explicación que hay al lado de ese número, léela al pie de la letra:
Un denominador muy pequeño o negativo pone todo el diagnóstico del revés: una estrategia que nunca fue fuerte dentro de muestra acaba sacando una «eficiencia» altísima justamente porque «no tenía nada que devolver». De ahí las dos defensas:
La estrategia de ejemplo del tutorial btc_sma_cross (BTCUSDT 1h, desde 2022-01-01, 1,720 días en total, SMA 45 / 100, sin tocar ni una letra de los parámetros). Los datos caen en el primer escalón, así que se aplican las ventanas por defecto 1095 / 30 y salen 20 rondas (600 días de ventanas de prueba en total); los últimos 25 días no completan una ronda y quedan excluidos.
| Elemento | Fuera de muestra (ventanas de prueba unidas, 600 días) | Dentro de muestra (20 ventanas de entrenamiento calculadas por separado y promediadas) |
|---|---|---|
| Sharpe | −0.45 | 1.3471 |
| Rentabilidad anual | −16.55% | +50.16% |
| Caída máxima | −46.57% | — |
| Operaciones | 183 | — |
Eficiencia fuera de muestra WFE = −0.45 ÷ 1.3471 = −0.334 → muy por debajo del umbral
Merece la pena señalar tres cosas. Primera, no se excluyó ni una sola ronda — el Sharpe de la ventana de entrenamiento de las 20 rondas fue mayor que 0, así que el denominador es la media completa de las 20 rondas, no lo que quedó tras descartar.
Segunda, el denominador de 1.3471 está muy por encima de 0.25, así que la segunda defensa no se activó y la división es válida: «el WFE es negativo» y «el WFE no se puede juzgar» son dos cosas distintas; lo primero es un resultado calculado, lo segundo es negarse a responder.
Tercera, esas dos columnas cubren de entrada períodos distintos — dentro de muestra es la media de 20 ventanas de entrenamiento que se solapan entre sí, y fuera de muestra son los 600 días posteriores, así que no es una comparación limpia del mismo período. Y ese desfase es justamente lo que el WFE pretende medir.
El mismo día y con el mismo código, el valor p de MCPT de esta estrategia es 0.0160 (n = 2000), y el propio stdout imprime significant edge at 95% — según el criterio del filtro de publicación, eso es un aprobado.
| Contraste | La pregunta que plantea | Resultado |
|---|---|---|
| MCPT | Sobre esta serie fija de posiciones, ¿se puede distinguir este resultado de la suerte? | p = 0.0160 → Aprobado |
| Walk-forward | El hecho mismo de elegir parámetros a partir del histórico, ¿sigue sirviendo en el tramo siguiente? | WFE = −0.334 → muy por debajo del umbral |
Ninguno de los dos está mal calculado, porque no responden a la misma pregunta. Por eso mismo ningún valor p, por bonito que sea, se puede dar por validado fuera de muestra (mira Cómo leer el valor p de MCPT). Y de paso, que quede claro: esto no es decir que la estrategia esté rota — es el ejemplo del tutorial que viene con el espacio de trabajo, y lo que se ilustra aquí es la diferencia de significado entre los dos contrastes.
Cada ronda elige los parámetros usando la media de un vecindario 3×3 (la misma regla que el barrido de parámetros, es decir, elegir la meseta y no el pico como se explica en Cómo evitar el sobreajuste), pero el Sharpe de entrenamiento que se reporta en la tabla de rondas es el número propio de la celda ganadora. Es a propósito:
| Qué usa el denominador | Consecuencia |
|---|---|
| El Sharpe propio de esa celda (comportamiento actual) | El denominador queda alto, así que el WFE sale conservador |
| La media del vecindario 3×3 | Una media de vecindario es estructuralmente más baja que la celda que rodea → el denominador se aplasta → el WFE queda inflado y toda la pestaña se lee demasiado optimista |
Más vale no hacer el diagnóstico que hacerlo con el denominador inflado.
En la unión entre dos rondas, la serie lleva la posición propia de la ronda nueva — está cortada, no puesta a cero. Forzar el cierre en cada costura equivaldría a inventarse n−1 salidas que nadie llegó a operar.
El coste de cambiar de parámetros tampoco se pierde: en la costura cambia el peso y al valorar se cobran las comisiones como corresponde. Y como los números de cada ronda se recortan de la misma serie ya cosida y no se vuelven a valorar, la suma de la tabla de rondas cuadra exactamente con el total del tramo entero.
Las señales se calculan sobre todo el histórico (los indicadores rolling solo así salen bien), pero cada tramo de entrenamiento se salta las velas de calentamiento de su propio comienzo — y no solo la primera ronda. Sin ese paso, la ronda 1 entrenaría con velas en las que el indicador todavía no ha entrado en calor y acabaría eligiendo ruido, y además la longitud efectiva de cada ronda sería distinta y no comparable. La tabla de rondas de arriba es la prueba: el START de la estrategia dice 2022-01-01, pero la ventana de entrenamiento de la ronda 1 no empieza hasta 2022-01-05 — esos pocos días de diferencia son justamente las WARMUP = 100 velas horarias (unos 4.2 días) que se descuentan.
La ventana de prueba no se recorta, porque ya viene caliente y porque tiene que ser continua para poder coserla. Y ya que estamos, una pregunta habitual de los lectores avanzados: aquí no hace falta un período de embargo — la ventana de prueba va pegada justo detrás de la ventana de entrenamiento que eligió sus parámetros, y los datos posteriores a ella no se usan en absoluto.
Al terminar no hay ningún botón de «aplicar los parámetros sugeridos», y al agente tampoco se le permite tocar el código de tu estrategia por culpa de este resultado. El estado vacío lo dice de entrada:
¿Por qué no se pueden copiar? Mira la deriva de parámetros de esa ejecución. A lo largo de 20 rondas solo eligió 4 conjuntos de parámetros distintos:
(45,100) ×14 → (55,80) → (45,100) → (45,80) ×3 → (35,80)
Las primeras 14 rondas se quedaron todas en la misma celda. Aunque «la mayoría de las veces elige 45 / 100» parezca una conclusión, esa curva fuera de muestra de −0.45 tampoco es el resultado de 45 / 100 — es un tramo entero corrido a relevos por 4 conjuntos de parámetros, que no pertenece a ninguno de ellos, así que no hay ningún conjunto que se pueda «adoptar». Cuando pides que se apliquen, el agente responde con una frase fija:
La cuadrícula de deriva de parámetros dibuja qué celda eligió cada ronda y en cuántas rondas se eligió, un recuadro de línea discontinua marca tus parámetros actuales, y la leyenda deja escrito que «los parámetros de la última ronda son solo de referencia, no un valor recomendado» — la última ronda de esa ejecución eligió 35 / 80, lo que solo significa «a la ventana de entrenamiento de esa última ronda le tocó justo esta celda». Además, esta pestaña no muestra ningún valor p y nunca ejecuta MCPT; correr un walk-forward cuenta como una iteración en las reglas de trabajo del agente.
¿Hay rondas suficientes? Por debajo de 3 no se ejecuta siquiera. Cuando hay muy pocas rondas, el WFE es solo la suerte de una o dos ventanas de prueba.
¿Se excluyó alguna ronda? El detalle por ronda anota cuáles tuvieron un Sharpe de ventana de entrenamiento ≤ 0. En la ejecución de arriba no se excluyó ninguna; cuantas más rondas se excluyan, más quiere decir que esta estrategia a menudo no encuentra nada ni siquiera dentro de sus propias ventanas de entrenamiento.
¿El WFE es «no se puede juzgar» o un número negativo? No es lo mismo. «No se puede juzgar» significa que la media dentro de muestra está por debajo de 0.25 y el cociente no tiene sentido; un número negativo significa que la división se hizo y que el tramo fuera de muestra perdió dinero.
¿Cuánto derivan los parámetros? Mira la línea «{n} rondas eligieron {u} pares distintos». La ejecución de arriba fueron 20 rondas y 4 conjuntos; si cada ronda salta a una celda completamente distinta, cada reelección está persiguiendo algo diferente.
¿No estarás buscando parámetros recomendados? No los hay. Para cambiar de parámetros usa el punto robusto del barrido de parámetros, no copies la última ronda.
Después de ejecutarlo una vez, si el WFE se desploma de mala manera, el problema no suele estar en este paso de fuera de muestra sino en el de elegir parámetros — y eso es territorio de Cómo evitar el sobreajuste. Si todavía no tienes una estrategia que merezca validarse, todas las estrategias oficiales de la Biblioteca de estrategias vienen con su backtest real y el resultado de los filtros de calidad, así que puedes mirar los números antes de decidir: Biblioteca de estrategias.