3. Fundamentales: cuándo se publicaron de verdad
Nivel 1: De dónde vienen y qué traen dentro
Con los precios, el problema es qué número te dan. Con los fundamentales, el problema es cuándo. Toda cifra contable arrastra dos fechas distintas, y confundirlas es el fallo que más veces convierte una estrategia mediocre en una maravilla imposible.
Las dos fechas de cualquier fundamental
- Fecha del periodo. El día al que se refiere la cifra: 31 de diciembre de 2019, 30 de junio de 2024. Es la etiqueta contable.
- Fecha de publicación. El día en que esa cifra fue conocida por el público, porque la empresa la comunicó o la presentó ante el regulador.
Entre una y otra pasan semanas o meses. Y aquí está el detalle que casi todas las fuentes baratas te ocultan: el CSV suele traer solo la primera. Te dan una tabla indexada por fin de trimestre y te dejan creer que ese día ya existía el dato. No existía. El 31 de diciembre nadie sabe todavía el beneficio del cuarto trimestre, ni siquiera la propia empresa.
Cuánto tarda de verdad: los plazos del regulador estadounidense
La SEC fija plazos máximos según el tamaño del emisor, y sirven como referencia del desfase típico:
- Informe trimestral (10-Q): 40 días naturales tras el cierre del trimestre para los emisores más grandes, y 45 días para los pequeños.
- Informe anual (10-K): 60 días para los grandes, 75 para la categoría intermedia y 90 para los pequeños.
Además hay un matiz que confunde a mucha gente: la nota de prensa de resultados suele salir antes que el informe completo, comunicada al mercado en un 8-K. Es decir, hay dos momentos distintos en que el mercado se entera de cosas distintas del mismo trimestre. La cifra auditada y detallada llega después.
Traducido a números redondos: para un anual, entre el fin del ejercicio y su presentación completa pueden pasar dos o tres meses. Si tu backtest asume que el 1 de enero ya podías filtrar por el beneficio del año que acababa de terminar, has adelantado el reloj un trimestre entero.
Lo primero, entonces, es mirar si tu fuente trae siquiera la segunda fecha, y qué pinta tiene el desfase:
import pandas as pd
fund = pd.read_csv("fundamentales.csv", parse_dates=["fin_periodo", "fecha_publicacion"])
print("Filas sin fecha de publicacion:", fund["fecha_publicacion"].isna().sum())
fund["desfase_dias"] = (fund["fecha_publicacion"] - fund["fin_periodo"]).dt.days
print(fund["desfase_dias"].describe())
# Anomalias: publicaciones antes del cierre del periodo o desfases absurdos.
raras = fund[(fund["desfase_dias"] < 0) | (fund["desfase_dias"] > 200)]
print(raras[["cik", "fin_periodo", "fecha_publicacion", "desfase_dias"]].head())Si la columna de publicación no existe, o si el describe te devuelve una mediana de cero días, tu fuente no es utilizable para nada que dependa del calendario: te está dando la contabilidad como si hubiera sido instantánea. El desarrollo completo de qué le hace eso a un backtest es materia del siguiente nivel; aquí basta con saber que es una propiedad de la fuente, no un detalle menor.
La cifra de 2019 que ves hoy no es la de 2019
La segunda mitad del problema es que las cifras cambian después de publicadas, y las bases de datos suelen sobrescribirlas sin dejar rastro:
- Revisiones ordinarias. Un dato preliminar de la nota de prensa se afina en el informe completo. Cambios pequeños, muy frecuentes.
- Reformulaciones. La empresa reconoce que las cuentas publicadas contenían errores materiales y republica los estados de periodos anteriores. En Estados Unidos, la corrección grave obliga a advertir que no hay que fiarse de los estados anteriores.
- Recálculos por cambio de norma contable o de perímetro. Cuando entra una norma nueva o se vende una división, los ejercicios anteriores se reexpresan para que sean comparables. Nadie mintió, pero el número de la tabla ha cambiado.
Una base de datos en el momento correcto (point-in-time) guarda todas las versiones y te deja preguntar "qué se sabía el 3 de marzo de 2020". Una base normal guarda solo la última. Si solo tienes instantáneas, al menos guárdalas y compáralas:
viejo = pd.read_parquet("fundamentales_2021_06.parquet")
nuevo = pd.read_parquet("fundamentales_2026_06.parquet")
clave = ["cik", "fin_periodo", "concepto"]
comp = viejo.merge(nuevo, on=clave, suffixes=("_viejo", "_nuevo"))
comp["cambio_pct"] = (comp["valor_nuevo"] / comp["valor_viejo"] - 1) * 100
revisados = comp[comp["cambio_pct"].abs() > 0.5]
print("Puntos revisados:", len(revisados), "de", len(comp))
print(revisados.groupby("concepto")["cambio_pct"].agg(["count", "median"]).sort_values("count", ascending=False).head(10))El resultado suele sorprender: los conceptos de flujo y las partidas con estimaciones (provisiones, deterioros, impuestos diferidos) se revisan mucho más que las ventas. Si tu señal se apoya en una partida muy revisable, buena parte de lo que mides en el pasado es información que entonces no estaba disponible en esa forma.
Tres reglas prácticas que salen de todo lo anterior:
- Guarda instantáneas fechadas. Aunque tu proveedor no tenga historial de versiones, tú puedes construirlo: descarga el panel completo cada trimestre y archívalo con la fecha de descarga en el nombre. En dos años tendrás algo que hoy no se vende barato.
- Trata la fecha de publicación como una columna obligatoria. Si una fuente no la trae, o la trae vacía en parte de las filas, esa parte del panel no es utilizable para nada que dependa del calendario, por muy bonitas que sean las cifras.
- Desconfía de los desfases demasiado limpios. Un desfase idéntico para todos los emisores, tipo exactamente 90 días, casi siempre significa que alguien lo ha estimado sumando un número fijo en vez de leer la fecha real del documento.
Caso real: Wirecard, junio de 2020
Wirecard había llegado a formar parte del índice alemán de grandes valores. En junio de 2020, sus auditores se negaron a firmar las cuentas de 2019 porque no encontraban unos 1.900 millones de euros que figuraban en cuentas fiduciarias. La compañía acabó reconociendo que ese saldo probablemente no existía y retirando la validez de estados financieros de ejercicios anteriores. Días después presentó insolvencia.
Piensa en lo que eso significa para una base de datos. Durante años, cualquier filtro cuantitativo que mirase la caja de Wirecard leyó una cifra publicada, auditada y perfectamente formateada. Hoy, esa fila puede aparecer corregida, vacía o marcada; y una descarga hecha en 2019 y otra hecha ahora no coinciden. Ni una ni otra está mal: son dos momentos distintos del mismo hecho. Guardar cuándo supiste cada cosa no es burocracia, es lo que hace que el pasado sea reconstruible. Formación, no asesoramiento financiero.