Quant500 Academy

4. El ticker miente: identificadores y reutilización

Nivel 1: De dónde vienen y qué traen dentro

Llevas tres módulos preocupándote por los números. Ahora el problema es la etiqueta que los agrupa. Casi todo el mundo cruza sus fuentes por el ticker, porque es lo que sale en el CSV y lo que uno tiene en la cabeza. Es el peor identificador posible, y falla en silencio: no lanza excepciones, simplemente te devuelve la empresa equivocada.

El ticker es una etiqueta de pantalla, no una identidad

Tres propiedades que hay que grabar a fuego:

Conclusión operativa: un ticker solo identifica algo si va acompañado de un mercado y de un rango de fechas.

Identificadores que sí aguantan

Ninguno es mágico: cada uno responde a una pregunta distinta, y el error típico es cruzar un identificador de entidad con uno de valor y perder por el camino las clases de acciones.

Qué le pasa a la serie histórica

Cuando una empresa cambia de código, la mayoría de los proveedores reescribe el histórico entero bajo el código nuevo. Eso es cómodo y a la vez traicionero: la serie de META arranca en 2012 aunque ese código no existiera hasta 2022. Si otra de tus fuentes conserva la serie vieja bajo el código antiguo, al unir por ticker te quedas con dos trozos que no se solapan, y ninguna advertencia.

Con fusiones es peor. La absorbida deja de existir; su serie termina. Si el proveedor "empalma" ambos históricos, obtienes una empresa de mentira, con un salto de precio y de fundamentales que no corresponde a ningún accionista real. El primer diagnóstico es contar cuántos identificadores estables ha llevado cada código:

import pandas as pd

fundam = pd.read_csv("fundamentales.csv", parse_dates=["fecha"])  # trae ticker y cik

colisiones = fundam.groupby("ticker")["cik"].nunique().sort_values(ascending=False)
print("Tickers con mas de una entidad detras:", (colisiones > 1).sum())
print(colisiones[colisiones > 1].head(15))

# Y al reves: entidades que han usado varios tickers a lo largo del historico.
mudanzas = fundam.groupby("cik")["ticker"].nunique()
print("Entidades que han cambiado de ticker:", (mudanzas > 1).sum())

Si ese primer conteo no sale cero, cualquier unión por ticker de tu proyecto está mezclando empresas. La forma correcta es mantener un mapa de vigencias y unir por identificador estable, no por etiqueta:

precios = pd.read_csv("precios.csv", parse_dates=["fecha"])
mapa = pd.read_csv("mapa_tickers.csv", parse_dates=["desde", "hasta"])  # ticker, cik, desde, hasta

precios = precios.merge(mapa, on="ticker", how="left")

# Los tramos aun abiertos vienen sin fecha de fin: hay que cerrarlos antes de comparar.
precios["hasta"] = precios["hasta"].fillna(pd.Timestamp("2099-12-31"))

vigente = (precios["fecha"] >= precios["desde"]) & (precios["fecha"] <= precios["hasta"])
descartadas = (~vigente).sum()
precios = precios[vigente]

print("Filas fuera de la vigencia del ticker:", descartadas)
print("Filas sin identificador estable:", precios["cik"].isna().sum())

panel = precios.merge(fundam, on=["cik", "fecha"], how="inner")
print("Filas del panel final:", len(panel))

Las filas descartadas son exactamente las que antes se colaban como datos de otra empresa. Merece la pena imprimirlas y mirarlas una por una la primera vez: casi siempre hay alguna sorpresa.

Por qué esto falla siempre en silencio

Un merge por ticker no tiene forma de saber que dos filas con la misma etiqueta hablan de cosas distintas. Para pandas, "ABC" es "ABC". El resultado no es una excepción, sino un panel con aspecto perfectamente normal donde:

De ahí la única disciplina que sirve: nunca unas dos fuentes por ticker sin imprimir antes cuántas filas entran, cuántas salen y cuántas se quedan sin pareja. Si esos tres números no cuadran con lo que esperabas, tienes un problema de identidad, no de datos.

Caso real: comprar el Zoom equivocado

A principios de 2020, con el confinamiento empujando la videoconferencia, mucha gente quiso comprar acciones de Zoom Video Communications, que cotiza bajo el código ZM. Existía además una compañía distinta y minúscula, Zoom Technologies, cuyo código era ZOOM. El código intuitivo era el de la empresa equivocada.

El resultado fue una subida disparatada del valor pequeño en pocas semanas, multiplicándose varias veces sin ninguna noticia que lo justificara, hasta que la SEC suspendió su negociación el 26 de marzo de 2020 alegando preocupación por la información que circulaba en el mercado y por la posible confusión de los inversores con una empresa de nombre parecido.

Ahí tienes el módulo entero en un caso: dos empresas sin relación, códigos casi idénticos, y un cruce hecho por la etiqueta en lugar de por la identidad. Si le pasó a miles de personas mirando una pantalla, imagina lo fácil que es que le pase a un merge de pandas que no protesta nunca. Formación, no asesoramiento financiero.

Para ampliar esta lección

El resto de Quant500

Lo que estás aprendiendo, aplicado al índice todos los días:

La cartera del modelo, cada semana en tu correo

Cada sábado, su semana en un minuto: cómo fue, lo mejor y lo peor, y qué directivos compraron con su dinero. Y el día que el modelo se rehace, qué entra y qué sale. Es una simulación, no un consejo. Como mucho un correo a la semana, sin publicidad y sin cuenta; te das de baja con un clic. Lo hace una persona: Pol Gracia.

Cartera modelo con resultados simulados, no una recomendación personalizada. Tu correo se usa solo para esto: privacidad.

Detrás de la Academia y del resto de Quant500 hay una sola persona: Pol Gracia Serrahima.