10 min de lectura
Los datos que usas deciden el resultado
De dónde salen los precios, qué les pasa por el camino y cómo comprobar que los tuyos no están rotos antes de construir nada encima.
- datos
- método
- backtesting
Una estrategia es una función que transforma datos en decisiones. Si los datos están mal, la función da igual. Es la parte más aburrida del trabajo y la que más backtests se lleva por delante, porque los errores de datos no dan error: dan resultados.
Esta guía usa los datos con los que trabajo: 2.960.640 velas de un minuto del Nasdaq, siete años, 333 MB de CSV. Todo lo que cuento aquí lo comprobé sobre ese fichero.
De dónde salen los precios
Hay tres orígenes y no son intercambiables.
Del bróker. Gratis, y son los precios a los que tú podrías haber operado, que es exactamente lo que quieres para un backtest. El problema es que cada bróker tiene los suyos: un CFD sobre el Nasdaq de un bróker y el de otro no marcan lo mismo al mismo segundo. Tu backtest no es reproducible por nadie más.
De un proveedor de datos. De pago, limpios, con historia larga y con documentación de qué contienen. Es lo profesional, y empieza en unos cientos de euros al año para datos de minuto.
Del mercado real, el futuro. Es el dato bueno, con volumen de verdad y sin el margen del bróker metido dentro. Es lo más caro, y tiene el lío de los vencimientos: un futuro muere cada tres meses, así que para tener una serie larga hay que empalmar contratos, y cada empalme deja un salto de precio que no ocurrió.
Qué le pasa a los datos por el camino
Aquí es donde se rompen los backtests. Cinco cosas, por orden de cuánto daño hacen.
Velas planas: el mercado cerrado que parece abierto
De mis 2.960.640 velas, 712.413 son planas: apertura, máximo, mínimo y cierre idénticos, y volumen cero. Son el mercado cerrado, el fin de semana y los festivos, que el proveedor rellena para que la serie no tenga huecos.
Es casi una de cada cuatro velas, y ninguna es mercado.
Velas de un minuto del Nasdaq, por año
Si no las filtras, tus medias móviles se aplanan durante el fin de semana, tus indicadores de volatilidad se hunden, y cualquier regla que compare la vela actual con la anterior cruza la noche del viernes al lunes como si fueran dos minutos seguidos. El filtro es una línea:
import pandas as pd
df = pd.read_csv("USATECHIDXUSD_1m.csv", parse_dates=["timestamp"])
# Fuera el mercado cerrado: sin rango y sin volumen no hubo negociacion
plana = (df["high"] == df["low"]) & (df["volume"] == 0)
print(f"{plana.sum():,} velas planas de {len(df):,} ({plana.mean():.1%})")
df = df[~plana]El horario de verano
Los mercados americanos abren a las 9:30 de Nueva York. En hora española eso son las 15:30 casi todo el año y las 14:30 unas tres semanas, porque Estados Unidos y Europa cambian la hora en fechas distintas.
Si tu regla filtra por hora fija en UTC o en hora local, esas semanas estás operando media hora antes o después de lo que crees. En una estrategia de sesión, eso es el experimento entero.
# Convertir a hora de Nueva York y filtrar por la hora REAL del mercado
df["ts"] = df["timestamp"].dt.tz_localize("UTC").dt.tz_convert("America/New_York")
sesion = df[df["ts"].dt.time.between(pd.Timestamp("09:30").time(),
pd.Timestamp("16:00").time())]Todo lo que dependa de una hora se convierte a la zona del mercado antes de comparar. Siempre, sin excepción.
Huecos, duplicados y precios imposibles
Un CSV de siete años tiene fallos. Minutos que faltan, minutos repetidos, y de vez en cuando un precio que se fue a la luna y volvió en la vela siguiente, que casi nunca ocurrió y casi siempre es un error del proveedor. Si tu estrategia entra en rupturas, esos ticks fantasma son operaciones ganadoras que nunca existieron.
El sesgo de supervivencia
Afecta sobre todo a acciones: si bajas el histórico de las empresas que hoy están en el índice y lo pruebas desde 2010, estás probando sobre las que sobrevivieron. Las que quebraron no están en tu lista. Cualquier estrategia de comprar y mantener sale espectacular en ese universo.
En índices y futuros esto no aplica, que es parte de por qué prefiero trabajar ahí.
La horquilla, que no está en el CSV
El fichero trae un precio por vela. Tú compras al precio de venta y vendes al de compra, y la diferencia es la horquilla. En mis datos el medio son 2,57 puntos, y no es constante: en la apertura y en las noticias se abre.
Un backtest que asume la horquilla media está siendo optimista justo en los momentos en los que muchas estrategias operan.
Cómo compruebo que unos datos no están rotos
Antes de construir nada, este script. Tarda un minuto y ha salvado más proyectos que cualquier otra cosa que haga.
import pandas as pd
df = pd.read_csv("USATECHIDXUSD_1m.csv", parse_dates=["timestamp"])
df = df.sort_values("timestamp")
print("Rango: ", df["timestamp"].min(), "->", df["timestamp"].max())
print("Filas: ", f"{len(df):,}")
print("Duplicados: ", df["timestamp"].duplicated().sum())
# Coherencia de cada vela: el maximo manda, el minimo aguanta
mal = df[(df["high"] < df["low"]) |
(df["high"] < df[["open", "close"]].max(axis=1)) |
(df["low"] > df[["open", "close"]].min(axis=1))]
print("Velas incoherentes:", len(mal))
# Saltos absurdos entre velas consecutivas
salto = df["close"].pct_change().abs()
print("Saltos > 2 % en un minuto:", (salto > 0.02).sum())
# Dias de negociacion por año: deberian rondar los 250
df["anio"] = df["timestamp"].dt.year
print(df.groupby("anio")["timestamp"].apply(lambda s: s.dt.date.nunique()))Los cuatro resultados que busco: cero duplicados, cero velas incoherentes, los saltos grandes justificables uno a uno, y entre 250 y 260 días por año. Si salen 365, tienes el mercado cerrado dentro. Si salen 180, te falta media serie.
- Velas totales
- 2.960.640 de un minuto, 2020 a 2026
- Velas planas
- 712.413, el 24 % del fichero
- Velas útiles
- 2.248.227 en 2.056 días de negociación
- Horquilla media
- 2,57 puntos, y se abre en la apertura
- Tamaño
- 333 MB en CSV
Lo que esta guía no arregla
Datos limpios no son datos representativos. Siete años del Nasdaq cubren el covid, una subida histórica y el 2022, pero no cubren una década lateral ni un cambio de estructura de mercado. Tu estrategia está validada contra lo que pasó, no contra lo que puede pasar.
Y limpiar tiene su propio riesgo: cada filtro que aplicas es una decisión, y las decisiones se pueden optimizar sin querer. Si pruebas tres formas de tratar los huecos y te quedas con la que da mejor resultado, acabas de meter un parámetro más en el modelo sin darte cuenta. Las reglas de limpieza se fijan antes de mirar ningún resultado, y no se tocan después.
Con los datos en su sitio, lo siguiente es mirar si lo que has construido sobrevive a datos que no ha visto. Ahí es donde se cae casi todo.
Contenido educativo. Nada de lo que leas aquí es una recomendación de inversión.
