Un Donchian de 20 días parece inofensivo en una spec. El agente escribe un máximo móvil de 20 barras, el backtest arranca en la fila uno del archivo parquet, y durante las dos primeras semanas el «máximo de 20 días» no es más que el máximo acumulado de las barras que haya. El día cuatro es un máximo de cuatro días. La estrategia que creías estar testeando no es la que produjo la primera docena de fills.
Tengo un notebook de barras diarias de ETHUSDT cuyo Sharpe de muestra completa es 1.4. Recorta las primeras 20 sesiones y cae a 0.6. Quédate con esas 20 y tira el resto del año uno, y imprime 3.1. Nadie filtró el mañana. La estrategia usó el pasado, solo que no el suficiente, y el informe trató esas operaciones a medio formar como evidencia.
Dejar que la ventana opere mientras todavía se está llenando
El destrozo habitual es min_periods=1. Pandas te calculará una media móvil sobre una sola barra si se lo permites. Los agentes lo hacen todo el rato, porque un NaN arriba del frame parece un bug, y rellenarlo pone el test unitario en verde.
Un objetivo de vol realizada de 20 días con dos observaciones de retorno es una explosión de size. La varianza de dos números es un cara o cruz, la inviertes, y la primera posición es varias veces el riesgo previsto. Un z-score contra una desviación típica casi cero hace el mismo truco con un signo: la estrategia parece tener una entrada de navaja que no vuelve a aparecer cuando la ventana es honesta.
Los breakouts son peores, porque parecen la regla de verdad. Un canal de 20 barras en la barra seis es un canal de seis barras. Sales con un racimo de operaciones justo al principio, a menudo en un tramo quieto que no habría disparado el indicador ya formado. Los mercados quietos derivan un poco. Un canal estrecho dispara. La curva de equity coge una ventaja inicial que ningún año posterior repite.
Zero-fill y forward-fill inventan otra mentira. Un RSI en 0 se lee como sobreventa. Un ATR ausente de 0 hincha el size unitario, y el backtest, diligente, compra un almacén. Prefiero que un NaN mate la orden a que un 0 invente una.
Sigo pillándome ploteando desde la fila 0 porque un mes en blanco a la izquierda del gráfico parece inacabado. El mes en blanco es la parte honesta.
Recortar la curva de equity, conservar la posición
Este sobrevive el code review. Calculas las features de 20 días como toca, tiras las primeras 20 filas de la curva ploteada y publicas desde el 21 de enero. La posición del 21 de enero se abrió el 14 de enero. El high-water del trailing stop, el contador de pirámide, el cash después de esos burns: todo eso se coló en la muestra «limpia».
El destrozo es una estrategia paper que no se puede arrancar en la fecha del write-up. Reinicias desde flat en el inicio reportado y las órdenes de la primera semana no coinciden. A veces el backtest ya está en una operación que el sistema paper no tiene motivo para entrar. A veces el sistema paper entra porque su lookback está frío, y el backtest se queda fuera porque su mes oculto ya se llevó el breakout. Dos libros de apertura, una fecha de inicio publicada.
Los folds de walk-forward lo hacen en silencio. Cada ventana de test tiene una cola de lookback que no plotear. Si te saltas simular esa cola, las primeras operaciones de test vuelven a ser operaciones de ventana incompleta. Si la simulas y reportas solo los días de test, la posición del día de test está condicionada a fills que no estás mostrando. Esa segunda versión puede ser una elección de investigación legítima. Llamar cold start a la primera mañana del fold, mientras un trailing stop ya está vivo desde la cola, es cómo dos investigadores sacan dos Sharpes de una misma config.
Hacer el warmup en días de calendario cuando la feature no es un día
«Dale 30 días» deja la feature subespecificada. Treinta días de calendario en un Donchian de 5 minutos son miles de barras de más respecto a un lookback de 20 periodos. Treinta días en una feature diaria que necesita 20 sesiones queda gorda o flaca, según fines de semana y huecos.
Un z-score de funding-rate en uno de nuestros venues de perps recibió un warmup de 30 días porque la spec decía 30 periodos y alguien tradujo periodos a calendario. El funding ahí se imprime cada ocho horas. Treinta días son unos 90 settlements. Treinta periodos son diez días. Los dos meses extra de burn-in coincidieron con una semana de depeg. Quitarlos hizo que la ventana live pareciera más calmada que la historia real de la estrategia. La gente culpó a la sensibilidad a la fecha de inicio. El warmup se había comido el régimen.
Y cripto frente a equity hace que el mismo número cambie de significado sin que nadie edite un parámetro. Veinte «días» de ETH incluyen sábados. Veinte sesiones de equity son casi un mes de calendario. Copias un lookback de 20 días de un notebook de acciones sobre velas perpetual horarias y tienes un canal de 20 horas con nombre de 20 días. La primera barra válida queda entonces a 20 horas, o a 20 días si alguna función posterior hace resample, y he visto las dos en el mismo diff del agente.
Fijar el primer timestamp negociable
El warmup es un requisito de datos, no una muestra extra. Cada feature nombra el número de observaciones terminadas que necesita, en las unidades en las que se calcula. El primer timestamp negociable es la primera barra en la que todo eso se cumple y una cuenta en flat habría podido enviar una orden.
| Feature | Lo que suele decir la spec | Lo que realmente tiene que existir | Sustituto silencioso |
|---|---|---|---|
| Donchian de 20 días | 20 máximos diarios | 20 sesiones completadas | Máximo acumulado con min_periods=1 |
| vol realizada de 30 días | ventana de 30 días | 30 retornos close-to-close | Varianza de dos días, invertida en size |
| z-score de funding de 20 prints | 20 días | 20 settlements de funding | 20 días de calendario (~90 prints), o 20 barras del timeframe incorrecto |
| RSI de 14 periodos en 5m | 14 periodos | 14 barras de 5 minutos cerradas | 14 días, o 14 barras con huecos forward-filled |
El P&L anterior a ese timestamp se queda fuera del track record. El estado anterior a ese timestamp puede seguir necesitando simulación, para que un trailing stop o un cooldown sea real cuando el reloj llega a la primera barra negociable, pero esos fills no entran en el Sharpe, el recuento de operaciones ni la matemática de capacidad. Luego ejecuta el chequeo feo: reinicia desde flat en ese timestamp, con el lookback disponible solo como datos. Si las órdenes cambian, estabas enviando operaciones ocultas.
El paper trading arranca con el mismo contrato. También cada ventana de test de walk-forward. Si el gráfico parece que le falta un mes, déjalo faltar.
← Todos los artículos


