Lección 1.3.1 · 55 min

Tipos de datos de mercado: EOD, barras, ticks, libro y referencia

El mismo día de negociación se puede guardar en una fila o en medio millón. Esta lección recorre la escalera completa con una sesión de la acción ficticia NOVA, del mensaje orden a orden a la barra diaria, mide lo que ocupa cada peldaño y repasa las trampas de cinta, marcas de tiempo y zonas horarias que vienen con cada uno.

Fig. — Filas y memoria en pandas de una sesión de NOVA (2 de junio de 2025) en cada granularidad, de la barra diaria a los mensajes orden a orden. *L3: cinco minutos de mensajes multiplicados por 78
01/08
Módulo
1.3 · Fuentes de datos de mercado
Duración
55 min
Lecciones del nivel 1
  1. 1.1 · Cómo funcionan los mercados

    1. 1.1.1 Participantes y centros de negociación
    2. 1.1.2 Sesiones, subastas, festivos y calendarios
    3. 1.1.3 Libro de órdenes: bid, ask, spread y profundidad
    4. 1.1.4 Tipos de órdenes
    5. 1.1.5 Costes, liquidación, apalancamiento y margen
  2. 1.2 · Clases de activos

    1. 1.2.1 Acciones: splits, dividendos y eventos corporativos
    2. 1.2.2 ETFs: réplica, tracking error, apalancados y UCITS
    3. 1.2.3 Futuros: especificaciones, margen, roll y contango
    4. 1.2.4 Forex: pares, pips, lotes, rollover y CFD
    5. 1.2.5 Opciones: call, put, valor intrínseco y valor temporal
    6. 1.2.6 Cripto: spot, perpetuos, funding y custodia
    7. 1.2.7 Renta fija y tipos de interés; CFDs y productos apalancados
  3. 1.3 · Fuentes de datos de mercado

    1. 1.3.1 Tipos de datos de mercado: EOD, barras, ticks, libro y referencia
    2. 1.3.2 Fuentes de datos gratuitas
    3. 1.3.3 APIs de datos retail y prosumer
    4. 1.3.4 Proveedores de datos profesionales
    5. 1.3.5 Datos de cripto y on-chain
    6. 1.3.6 Brókeres como fuente de datos
    7. 1.3.7 Licencias y términos de uso de datos
    8. 1.3.8 Cómo elegir proveedor de datos
  4. 1.4 · Ingeniería de datos financieros

    1. 1.4.1 Descarga por REST y websockets: paginación, límites y reintentos
    2. 1.4.2 Limpieza de datos: faltantes, ticks erróneos, huecos y zonas horarias
    3. 1.4.3 Ajustes por splits y dividendos: precios ajustados y sin ajustar
    4. 1.4.4 Universos sin sesgo de supervivencia: deslistados, fusiones y cambios de símbolo
    5. 1.4.5 Construcción de barras: tiempo, ticks, volumen, dólar y desequilibrio
    6. 1.4.6 Series continuas de futuros: reglas de roll, ajuste por diferencia y ajuste por ratio
    7. 1.4.7 Almacenamiento: CSV, Parquet, particionado, DuckDB, TimescaleDB y ArcticDB
    8. 1.4.8 Pipeline reproducible: descarga, validación, actualización incremental y tests de calidad
  5. 1.5 · Datos fundamentales y macro

    1. 1.5.1 Estados financieros, ratios, XBRL y SEC EDGAR
    2. 1.5.2 Datos macro, calendarios económicos, estimaciones y transcripciones
  6. 1.6 · Análisis exploratorio financiero

    1. 1.6.1 Rentabilidades, volatilidad, correlaciones móviles y drawdown
    2. 1.6.2 Hechos estilizados: colas gruesas, agrupamiento, autocorrelación y apalancamiento
    3. 1.6.3 Estacionalidad: día de la semana, mes, cambio de mes y sesiones intradía
  7. 1.7 · Análisis técnico programado

    1. 1.7.1 Indicadores técnicos en Python
    2. 1.7.2 Implementación propia frente a TA-Lib: validar resultados
    3. 1.7.3 Patrones de velas y soportes y resistencias
    4. 1.7.4 Multi-timeframe sin anticipación

Una escalera de agregación

Cuando se habla de «datos de mercado» se habla de cosas muy distintas: el precio de cierre de cada día, una vela de cinco minutos, cada operación, cada cambio del mejor precio o cada orden que entra y sale del libro. No son fuentes alternativas, sino peldaños de una misma escalera. En la base están los mensajes que emite el motor de negociación; todo lo demás es una agregación de ellos.

Mensajes L3Libro reconstruidoLibro L2Cotizaciones L1OperacionesBarras intradíaDatos diariosReferencia
Fuente Mermaid
flowchart TB
  M[Mensajes L3] --> B[Libro reconstruido]
  B --> L2[Libro L2]
  L2 --> L1[Cotizaciones L1]
  M --> T[Operaciones]
  T --> BA[Barras intradía]
  BA --> D[Datos diarios]
  R[Referencia] -.-> D
  • Mensajes L3 (market by order): cada orden que llega, se modifica, se cancela o se ejecuta, con su identificador. Es lo que publican los protocolos orden a orden de las bolsas, como ITCH de Nasdaq1Nota 1 · Nasdaq TotalView-ITCH 5.0 (enlace en los recursos): mensajes de alta, ejecución, cancelación, borrado y sustitución de órdenes, con marcas de tiempo en nanosegundos desde medianoche..
  • Libro L2 (market by price): el libro agregado por nivel de precio, con el tamaño total y el número de órdenes de cada nivel (lección 1.1.3).
  • Cotizaciones L1 (top of book): solo el mejor bid y el mejor ask, con sus tamaños.
  • Operaciones (trades o ticks): cada ejecución, con precio, tamaño, centro y condiciones.
  • Barras intradía: operaciones agregadas en intervalos (1 minuto, 5 minutos, 1 hora) como apertura, máximo, mínimo, cierre y volumen (OHLCV).
  • Datos diarios (EOD, end of day): una barra por sesión.
  • Datos de referencia: lo que describe los instrumentos (especificaciones, eventos corporativos, símbolos, universos). No se agrega de los mensajes, pero hace falta para interpretarlos y ajustarlos; por eso la flecha es discontinua.

La regla de la escalera es asimétrica: de un peldaño se puede bajar al siguiente (agregar), pero no subir. Con operaciones se construyen barras; con barras no se recuperan las operaciones.

Seis peldaños de NOVA

Los datos del nivel tienen un ejemplo de cada peldaño para la misma acción ficticia, NOVA, y para la misma sesión, el 2 de junio de 2025, salida de un libro simulado orden a orden (lección 1.1.1). Empezando por arriba, el dato diario:

IN [01]python
import numpy as np
import pandas as pd

diario = pd.read_csv("nova_diario_sin_ajustar.csv",
                     parse_dates=["fecha"]).set_index("fecha")
print(len(diario), "sesiones;", diario.index.min().date(), "→",
      diario.index.max().date())
diario.loc["2025-05-30":"2025-06-03"]
OUT [01]Datos diarios
2011 sesiones; 2018-01-02 → 2025-12-31
            apertura  maximo  minimo  cierre  volumen
fecha
2025-05-30     52.58   53.98   52.01   53.13  6106070
2025-06-02     53.35   53.93   52.55   53.12  8888714
2025-06-03     53.05   53.99   52.74   53.00  8044956

Una fila por sesión, ocho años en 2.011 filas. Responde preguntas de días a años: tendencias, volatilidad diaria, carteras que se rebalancean al cierre. Es el dato más barato de conseguir y de guardar, y el que más trampas de ajustes tiene (lección 1.4.3: este es sin ajustar, con el split de 2021 a la vista).

IN [02]python
barras = pd.read_parquet("nova_barras_5min.parquet").set_index("ts")
sesion = barras.loc["2025-06-02"]
print(len(barras), "barras en", barras.index.normalize().nunique(),
      "sesiones;", len(sesion), "el 2 de junio")
sesion.head(3)
OUT [02]Barras de 5 minutos
38940 barras en 502 sesiones; 78 el 2 de junio
                           apertura  maximo  minimo  cierre  volumen
ts
2025-06-02 13:30:00+00:00     53.35   53.48   53.28   53.46   285081
2025-06-02 13:35:00+00:00     53.46   53.48   53.22   53.24   220651
2025-06-02 13:40:00+00:00     53.24   53.47   53.23   53.35   187320

78 barras por sesión normal (seis horas y media en tramos de cinco minutos). Responden preguntas de minutos a días: patrones intradía, estacionalidad dentro de la sesión, ejecución en un horario. La marca de tiempo es el inicio de la barra, en UTC: la primera, 13:30 UTC, son las 9:30 de Nueva York.

IN [03]python
op = pd.read_parquet("nova_operaciones.parquet")
cot = pd.read_parquet("nova_cotizaciones.parquet")
print(len(op), "operaciones;", len(cot), "cambios de cotización")
print(op.iloc[1:3].to_string())
print(cot.iloc[1:3].to_string())
OUT [03]Operaciones y cotizaciones
50946 operaciones; 129247 cambios de cotización
                                ts  precio  tamano agresor     centro condicion
1 2025-06-02 13:30:00.301051+00:00   53.34     100   venta  PRINCIPAL   regular
2 2025-06-02 13:30:00.301052+00:00   53.34     100   venta  PRINCIPAL   regular
                                ts    bid    ask  tam_bid  tam_ask
1 2025-06-02 13:30:00.006643+00:00  53.34  53.36     1600      500
2 2025-06-02 13:30:00.075521+00:00  53.34  53.36     1600      800

Operaciones y cotizaciones son los datos «tick a tick». Las operaciones dicen qué se negoció, dónde y a qué precio; las cotizaciones, a qué precio se podía negociar en cada instante. Juntas permiten medir la horquilla efectiva y el deslizamiento (lección 1.1.5), clasificar compras y ventas o construir barras alternativas (lección 1.4.5).

IN [04]python
l2 = pd.read_parquet("nova_libro_l2.parquet")
l3 = pd.read_parquet("nova_libro_l3.parquet")
print(len(l2), "filas L2 (fotos cada 10 s, 10 niveles por lado)")
print(l2[l2["ts"] == l2["ts"].iloc[0]].head(4).to_string())
print(len(l3), "mensajes L3 en 5 minutos;",
      l3["evento"].value_counts().to_dict())
OUT [04]Libro L2 y mensajes L3
44126 filas L2 (fotos cada 10 s, 10 niveles por lado)
                         ts lado  nivel  precio  tamano  ordenes
0 2025-06-02 13:30:00+00:00  bid      1   53.34    1200        3
1 2025-06-02 13:30:00+00:00  bid      2   53.33     400        2
2 2025-06-02 13:30:00+00:00  bid      3   53.32    1100        3
3 2025-06-02 13:30:00+00:00  bid      4   53.31    1100        2
7241 mensajes L3 en 5 minutos; {'alta': 3443, 'cancelacion': 2842, 'ejecucion': 746, 'modificacion': 210}

El L2 dice cuánta liquidez había en cada nivel; el L3, quién (qué orden) la ponía y en qué posición de la cola estaba. En cinco minutos de NOVA hay 7.241 mensajes, y la mayoría no son operaciones: son altas y cancelaciones de órdenes que nunca se ejecutan. Ese ruido es la materia prima de los estudios de microestructura (colas, prioridad, órdenes iceberg) y casi nunca hace falta para un sistema de baja frecuencia.

TipoUna fila esResponde aUso típico
Diario (EOD)Una sesiónTendencia, volatilidad, carterasBacktests diarios, investigación de factores
Barras intradíaUn intervaloPatrones intradía, horariosSistemas intradía, estacionalidad de la sesión
OperacionesUna ejecuciónQué se negoció, dónde, cuántoVWAP, barras de volumen, costes
Cotizaciones (L1)Un cambio del mejor precioA qué precio se podía operarHorquilla, deslizamiento, alineación
Libro L2Un nivel en un instanteCuánta liquidez habíaImpacto de mercado, profundidad
Mensajes L3Un evento de una ordenColas y prioridadMicroestructura, simulación de ejecución
ReferenciaUn instrumento o eventoQué es y qué le ha pasadoAjustes, universos, especificaciones

Cuánto ocupa cada peldaño

La diferencia entre peldaños es de órdenes de magnitud. Para medirla en una sesión, se cuentan las filas y la memoria que ocupan en pandas. Los mensajes L3 solo están para cinco minutos; multiplicados por 78 dan una estimación de la sesión completa:

IN [05]python
def mb(df):
    return df.memory_usage(deep=True).sum() / 1e6

dia = diario.loc[["2025-06-02"]]
l3_bytes_fila = l3.memory_usage(deep=True).sum() / len(l3)
tamanos = pd.DataFrame({
    "filas": [len(dia), len(sesion), len(op), len(cot), len(l2),
              len(l3) * 78],
    "MB": [mb(dia), mb(sesion), mb(op), mb(cot), mb(l2),
           l3_bytes_fila * len(l3) * 78 / 1e6],
}, index=["diario", "barras 5 min", "operaciones", "cotizaciones",
          "libro L2 (10 s)", "mensajes L3 (estimado)"])
tamanos["filas"] = tamanos["filas"].astype(int)
tamanos.round(4)
OUT [05]Filas y memoria por sesión
                         filas       MB
diario                       1   0.0000
barras 5 min                78   0.0037
operaciones              50946   3.4860
cotizaciones            129247   5.1700
libro L2 (10 s)          44126   2.2506
mensajes L3 (estimado)  564798  33.0479

La figura de la cabecera dibuja la tabla en escala logarítmica. De la barra diaria al L3 hay casi seis órdenes de magnitud: una fila frente a más de medio millón. Y eso para una acción ficticia de liquidez media en un solo libro. Multiplicado por miles de valores y años de historia, la diferencia decide la infraestructura: diez años de datos diarios de todo un mercado caben en un portátil; los mensajes L3 de una sola bolsa durante un año, no (lección 1.4.7). También decide el precio: los proveedores cobran por granularidad, profundidad histórica y número de bolsas (lecciones 1.3.3 y 1.3.4).

IN [06]python
sesiones, valores = 252, 3_000
anual_gb = tamanos["MB"] * sesiones * valores / 1e3
anual_gb.round(3).rename("GB por año (3.000 valores)")
OUT [06]Un año de un mercado, a ojo
diario                        0.036
barras 5 min                  2.830
operaciones                2635.384
cotizaciones               3908.529
libro L2 (10 s)            1701.422
mensajes L3 (estimado)    24984.211
Name: GB por año (3.000 valores), dtype: float64

La cuenta es tosca, porque NOVA no es un valor representativo de todo un mercado y los formatos en disco comprimen mucho más que pandas en memoria (Parquet, lección 1.4.7). Pero el orden de magnitud es el que importa: con datos diarios, un año de 3.000 valores son unas decenas de megabytes; con operaciones y cotizaciones, varios terabytes; con L3, decenas de terabytes.

Treinta segundos de NOVA

La escalera se ve bien en un intervalo corto: de 14:00:00 a 14:00:30 UTC (las 10:00 en Nueva York), cuántos eventos registra cada granularidad:

IN [07]python
ini = pd.Timestamp("2025-06-02 14:00:00", tz="UTC")
fin = ini + pd.Timedelta("30s")
en = lambda df: df[(df["ts"] >= ini) & (df["ts"] < fin)]
print("mensajes L3:  ", len(en(l3[l3["ts"] > ini])))
print("cotizaciones: ", len(en(cot)))
print("operaciones:  ", len(en(op)))
print("fotos L2:     ", en(l2)["ts"].nunique())
print("barras 5 min:  1 (en curso)")
precios = en(cot)[["bid", "ask"]].drop_duplicates()
print("pares bid/ask distintos:", precios.values.tolist())
OUT [07]Medio minuto en cada granularidad
mensajes L3:   656
cotizaciones:  145
operaciones:   79
fotos L2:      3
barras 5 min:  1 (en curso)
pares bid/ask distintos: [[53.08, 53.09]]
Fig. — Treinta segundos de NOVA, de 14:00:00 a 14:00:30 UTC del 2 de junio de 2025: eventos acumulados en cada granularidad, de los mensajes orden a orden a la barra de 5 minutos

En medio minuto hay 656 mensajes de órdenes, 145 cambios en el mejor bid o ask (casi todos de tamaño: en esos 30 segundos el precio no se mueve del 53,08/53,09) y 79 operaciones; el L2 hace tres fotos y la barra de cinco minutos que los contiene todavía ni ha cerrado. La figura acumula los eventos segundo a segundo. (Las primeras 358 filas del L3, la foto inicial del libro a las 14:00:00 en punto, se excluyen de la cuenta.)

La asimetría de la escalera se puede comprobar en el otro sentido: con las operaciones se reconstruyen las barras y, con las barras, el dato diario. Deben coincidir con los ficheros agregados:

IN [08]python
ohlcv = {"precio": ["first", "max", "min", "last"], "tamano": "sum"}
# la subasta de cierre (20:00:00 UTC) va en la última barra
cierre = op["condicion"] == "subasta_cierre"
ts_barra = op["ts"].mask(cierre, op["ts"] - pd.Timedelta("1us"))
mias = op.set_index(ts_barra).resample("5min").agg(ohlcv)
mias.columns = ["apertura", "maximo", "minimo", "cierre", "volumen"]
print(len(mias), "barras; iguales:", np.allclose(mias, sesion))

dia_mio = pd.Series({"apertura": sesion["apertura"].iloc[0],
                     "maximo": sesion["maximo"].max(),
                     "minimo": sesion["minimo"].min(),
                     "cierre": sesion["cierre"].iloc[-1],
                     "volumen": sesion["volumen"].sum()})
print("Día igual:", np.allclose(dia_mio, dia.iloc[0]))
OUT [08]De las operaciones a las barras y al día
78 barras; iguales: True
Día igual: True

Las 78 barras salen exactamente de las operaciones, y el dato diario de las barras. Hay un detalle: la subasta de cierre se cruza a las 16:00:00 de Nueva York (20:00:00 UTC), justo en el borde, y un resample sin más abriría para ella sola una barra 79 de las 20:00. El proveedor de estos datos la cuenta en la barra de las 15:55, y para casar con él hay que hacer lo mismo (aquí, adelantando su marca un microsegundo al agrupar). Es el tipo de convención que hay que conocer para que dos fuentes coincidan.

Cinta consolidada o un solo centro

En EE. UU., todas las bolsas y centros envían sus operaciones y cotizaciones a un consolidador, que publica la cinta consolidada: en los valores cotizados en la NYSE y en otras bolsas regionales, los sistemas CTS (operaciones) y CQS (cotizaciones) de la Consolidated Tape Association2Nota 2 · Consolidated Tape Association, página de presentación (enlace en los recursos).. Un proveedor puede dar la cinta consolidada o el feed propio de una sola bolsa, y los números cambian mucho, como se vio en la lección 1.1.1:

IN [09]python
def barra_dia(t):
    return pd.Series({
        "apertura": t["precio"].iloc[0], "maximo": t["precio"].max(),
        "minimo": t["precio"].min(), "cierre": t["precio"].iloc[-1],
        "volumen": t["tamano"].sum(), "operaciones": len(t),
        "vwap": (t["precio"] * t["tamano"]).sum() / t["tamano"].sum()})

pd.DataFrame({"consolidada": barra_dia(op),
              "solo principal": barra_dia(
                  op[op["centro"] == "PRINCIPAL"])}).round(3)
OUT [09]El mismo día, dos cintas
             consolidada  solo principal
apertura          53.350          53.350
maximo            53.930          53.930
minimo            52.550          52.550
cierre            53.120          53.120
volumen      8888714.000     3564476.000
operaciones    50946.000       25776.000
vwap              53.319          53.291

Con la cinta de un solo centro, el volumen del día es el 40 % del real, hay la mitad de operaciones y el VWAP baja de 53,319 a 53,291. Apertura y cierre coinciden porque los fijan las subastas del centro principal; el máximo y el mínimo también coinciden ese día, pero no tienen por qué: el precio extremo de la sesión puede cruzarse en otro centro. Antes de comparar volúmenes entre fuentes, o de calcular un VWAP para medir una ejecución, hay que saber qué cinta se usa.

Marcas de tiempo y zonas horarias

Cada fila de datos de mercado lleva una marca de tiempo, y cada marca tiene una convención. Tres preguntas hay que hacerse siempre:

  1. ¿De qué evento es la marca? La del motor de negociación (cuando ocurre el evento) o la de recepción (cuando lo recibe quien graba los datos). Los proveedores profesionales suelen dar las dos: Databento, por ejemplo, publica ts_event y ts_recv, y advierte de que los relojes del mercado y del receptor no están necesariamente sincronizados3Nota 3 · Databento, «Common fields, enums and types» (enlace en los recursos)..
  2. ¿Inicio o fin del intervalo? En barras, una marca 14:00 puede ser el inicio (14:00–14:05) o el fin (13:55–14:00). Confundirlas es mirar el futuro.
  3. ¿Qué zona horaria? UTC, la hora de la bolsa o la del ordenador de quien descargó los datos. Las fechas sin hora (datos diarios) son la fecha de la sesión, no un instante.

La primera importa cuando se combinan centros: cada feed llega con su propia latencia, y ordenar por la marca de recepción cambia el orden de los eventos. Una simulación lo muestra con latencias supuestas de unos cientos de microsegundos, distintas por centro:

IN [10]python
rng = np.random.default_rng(7)
media_us = {"PRINCIPAL": 150, "MTF_A": 400, "MTF_B": 600,
            "OSCURO": 900, "INTERNALIZADOR": 1_200}
lat = rng.exponential(op["centro"].map(media_us).to_numpy())
op["ts_recv"] = op["ts"] + pd.to_timedelta(lat.round(), unit="us")
orden_evento = op.sort_values("ts", kind="stable").index
orden_recv = op.sort_values("ts_recv", kind="stable").index
cambia = (orden_evento != orden_recv).mean()
print(f"Operaciones en otra posición al ordenar por recepción: "
      f"{cambia:.1%}")
OUT [10]Ordenar por recepción cambia el orden
Operaciones en otra posición al ordenar por recepción: 28.7%

Con latencias de este tamaño, el 28,7 % de las operaciones cambia de posición en la secuencia. Para un sistema de baja frecuencia es irrelevante; para alinear operaciones con cotizaciones al microsegundo (lección 1.1.1) o para medir quién se adelanta a quién, es la diferencia entre un estudio correcto y uno falso.

La segunda y la tercera pregunta afectan a cualquier sistema intradía:

IN [11]python
b = sesion.head(2).copy()
b["fin"] = b.index + pd.Timedelta("5min")
b.index = b.index.tz_convert("America/New_York")
b[["fin", "apertura", "cierre"]].assign(
    fin=lambda x: x["fin"].dt.tz_convert("America/New_York"))
OUT [11]Inicio de barra, UTC y hora de Nueva York
                                                fin  apertura  cierre
ts
2025-06-02 09:30:00-04:00 2025-06-02 09:35:00-04:00     53.35   53.46
2025-06-02 09:35:00-04:00 2025-06-02 09:40:00-04:00     53.46   53.24
Fig. — La misma barra de 5 minutos con dos convenciones de marca de tiempo: la primera barra de NOVA del 2 de junio de 2025 va de 9:30 a 9:35 de Nueva York; su cierre solo se conoce a las 9:35, aunque el fichero la etiquete 13:30 UTC (esquema)

La barra que empieza a las 9:30 de Nueva York termina a las 9:35, y su cierre no se conoce hasta entonces. Una señal que use ese cierre solo puede ejecutarse a partir de las 9:35. Si el proveedor etiquetara por el fin, la misma barra llevaría la marca 9:35; mezclar dos fuentes con convenciones distintas desplaza una de ellas cinco minutos. Y al pasar de UTC a hora local, el cambio de horario de verano mueve la hora UTC de la apertura (13:30 en verano, 14:30 en invierno; lección 0.4.4): por eso conviene guardar en UTC y convertir solo para mostrar o para filtrar horarios.

Datos de referencia

El último tipo no tiene precio, pero sin él los precios no se entienden. Tres ejemplos del nivel:

IN [12]python
spec = pd.read_csv("fix_especificaciones.csv")
eventos = pd.read_csv("nova_eventos.csv", parse_dates=["fecha_ex"])
miembros = pd.read_csv("universo_miembros.csv",
                       parse_dates=["alta", "baja"])
print(spec[["multiplicador", "tick", "valor_tick", "meses"]]
      .to_string(index=False))
print(eventos[eventos["tipo"] != "dividendo"].to_string(index=False))
print(f"{len(miembros)} tickers han pasado por el índice; "
      f"{miembros['baja'].isna().sum()} siguen hoy")
OUT [12]Especificaciones, eventos y universo
 multiplicador  tick  valor_tick   meses
            50  0.25        12.5 H,M,U,Z
  fecha_ex                     tipo  ratio  importe fecha_pago
2021-08-23                    split    4.0      NaN 2021-08-20
2023-12-14 dividendo_extraordinario    NaN      1.5 2024-01-04
57 tickers han pasado por el índice; 40 siguen hoy
  • Especificaciones de contratos: multiplicador, tick, meses de vencimiento y reglas de liquidación de un futuro (lección 1.2.3). Sin el multiplicador, un movimiento de 10 puntos no se puede pasar a dinero.
  • Eventos corporativos: splits, dividendos, cambios de nombre, fusiones. Con ellos se ajustan las series (lección 1.4.3). El split 4 por 1 de NOVA en 2021 está en esta tabla; sin ella, el precio diario parece caer un 75 % en un día.
  • Universos: qué valores formaban un índice en cada fecha. 57 tickers han pasado por un índice que siempre tiene 40 miembros; usar solo los 40 de hoy es el sesgo de supervivencia (lección 1.4.4).

Los datos de referencia ocupan poco, cambian poco y nadie los mira hasta que fallan. Y cuando fallan, el error no da un aviso: produce un backtest plausible y falso.

Qué dato para qué pregunta

La regla práctica es usar el peldaño más alto (el más agregado) que responda a la pregunta. Cada peldaño más fino multiplica el coste, el volumen de datos y las formas de equivocarse.

días o másminutos u horassegundossíno¿Horizonte?Datos diariosBarras intradíaOperaciones y L1¿Colas, prioridad?Mensajes L3Libro L2
Fuente Mermaid
flowchart TB
  P{¿Horizonte?} -- días o más --> D[Datos diarios]
  P -- minutos u horas --> B[Barras intradía]
  P -- segundos --> T[Operaciones y L1]
  T --> C{¿Colas, prioridad?}
  C -- sí --> L3[Mensajes L3]
  C -- no --> L2[Libro L2]

Un sistema diario como los de los niveles 2 y 3 vive con datos diarios, bien ajustados y sin sesgo de supervivencia. Uno intradía necesita barras y, para estimar costes, operaciones y cotizaciones. Solo la investigación de microestructura o la ejecución de alta frecuencia justifican el libro completo.

Ejercicios

  1. Construye barras de 1 minuto con las operaciones de NOVA del 2 de junio y cuenta cuántas tiene la sesión. ¿Cuántas habría en barras de 30 minutos? ¿Dónde cae la subasta de cierre en cada caso?
Solución
IN [13]python
for regla in ("1min", "30min"):
    b = op.set_index("ts")["precio"].resample(regla).ohlc()
    print(regla, "→", len(b), "intervalos;", "último:",
          b.index[-1].strftime("%H:%M"), "UTC")
OUT [13]Barras de 1 y 30 minutos
1min → 391 intervalos; último: 20:00 UTC
30min → 14 intervalos; último: 20:00 UTC

Con resample sobre las operaciones, el último intervalo es el que contiene la subasta de cierre de las 20:00:00 UTC: 391 intervalos de 1 minuto (390 de la sesión continua más uno de las 20:00 con solo la subasta) y 14 de 30 minutos (13 más el de la subasta). Para tener las 390 barras de la sesión hay que decidir dónde va la subasta, como en la reconstrucción de las barras de 5 minutos.

  1. Calcula, con las operaciones, qué porcentaje del volumen de NOVA se negocia en la primera y en la última media hora de la sesión, y compáralo con el que le correspondería si el volumen fuera uniforme.
Solución
IN [14]python
v = op.set_index("ts")["tamano"].resample("30min").sum()
cuota = 100 * v / v.sum()
print(f"Primera media hora: {cuota.iloc[0]:.1f} %")
print(f"Última media hora (con la subasta): "
      f"{cuota.iloc[-2:].sum():.1f} %")
print(f"Uniforme: {100 / 13:.1f} % por media hora")
OUT [14]Volumen en U
Primera media hora: 13.5 %
Última media hora (con la subasta): 20.1 %
Uniforme: 7.7 % por media hora

La primera media hora concentra el 13,5 % del volumen y la última, con la subasta de cierre, el 20,1 %, frente al 7,7 % que les tocaría con un volumen uniforme. Es el perfil en U que se ve en casi todas las acciones (lecciones 1.1.2 y 1.6.3): por eso los algoritmos de ejecución reparten las órdenes siguiendo un perfil de volumen y no a partes iguales.

  1. Un proveedor ofrece «datos tick a tick» de una acción por un precio. ¿Qué preguntas le harías antes de comprarlos?
Solución

Qué contiene exactamente: solo operaciones, o también cotizaciones; si son L1, L2 o L3. Qué cinta: consolidada o de una sola bolsa, y qué centros incluye (oscuros, internalizadores, operaciones fuera de hora). Qué marcas de tiempo: del evento, de recepción o las dos, con qué precisión y en qué zona horaria. Qué condiciones de operación incluye (subastas, bloques, operaciones corregidas o canceladas). Si los datos están ajustados por eventos corporativos y cómo se entregan los eventos. Desde cuándo hay histórico y si incluye valores deslistados. Y la licencia: qué se puede hacer con ellos (lección 1.3.7).

Footnotes

  1. Nasdaq TotalView-ITCH 5.0 (enlace en los recursos): mensajes de alta, ejecución, cancelación, borrado y sustitución de órdenes, con marcas de tiempo en nanosegundos desde medianoche. ↩

  2. Consolidated Tape Association, página de presentación (enlace en los recursos). ↩

  3. Databento, «Common fields, enums and types» (enlace en los recursos). ↩

Respuesta plegada en cada pregunta

Autoevaluación

  1. Quieres estudiar si una estrategia de cruce de medias diarias funciona en acciones de EE. UU. desde 2005. ¿Qué tipo de dato necesitas?

    • AMensajes L3 de todas las bolsas
    • BDatos diarios (EOD) con ajustes por eventos corporativos y un universo sin sesgo de supervivencia
    • CCotizaciones con el mejor bid y ask
    • DFotos L2 cada segundo
    Ver respuesta

    Respuesta B. Datos diarios (EOD) con ajustes por eventos corporativos y un universo sin sesgo de supervivencia

    Una regla que decide una vez al día con el cierre solo necesita OHLCV diario. Lo crítico no es la granularidad, sino los ajustes por splits y dividendos y que el universo incluya los valores que dejaron de cotizar (lecciones 1.4.3 y 1.4.4). Datos más finos solo añadirían coste.

  2. ¿Qué diferencia hay entre datos L2 y L3?

    • ANinguna
    • BL2 son operaciones y L3 cotizaciones
    • CL3 es L2 con retraso
    • DL2 agrega el libro por nivel de precio (tamaño total y número de órdenes); L3 da cada orden individual con su identificador y sus altas, cancelaciones y ejecuciones
    Ver respuesta

    Respuesta D. L2 agrega el libro por nivel de precio (tamaño total y número de órdenes); L3 da cada orden individual con su identificador y sus altas, cancelaciones y ejecuciones

    Con L3 (market by order) se puede reconstruir el libro y ver la cola de cada precio; con L2 (market by price) solo el total de cada nivel. Del L3 se puede obtener el L2, pero no al revés.

  3. Una barra de 5 minutos tiene la marca 14:00. Tu proveedor la etiqueta por el inicio. ¿Cuándo se conoce su cierre?

    • AA las 14:05, cuando termina la barra
    • BA las 14:00
    • CA las 13:55
    • DAl cierre de la sesión
    Ver respuesta

    Respuesta A. A las 14:05, cuando termina la barra

    Una barra etiquetada por el inicio contiene lo que ocurre de 14:00 a 14:05; su cierre solo existe a las 14:05. Usarlo como si estuviera disponible a las 14:00 es mirar cinco minutos en el futuro. Cada proveedor elige su convención, y hay que comprobarla.

  4. Comparas el volumen diario de NOVA de dos proveedores y uno da 3,56 millones de acciones y otro 8,89 millones. ¿Cuál es la explicación más probable?

    • AUno de los dos está mal
    • BUno incluye dividendos
    • CUno usa solo las operaciones del centro principal y el otro la cinta consolidada de todos los centros
    • DUno usa horario de verano
    Ver respuesta

    Respuesta C. Uno usa solo las operaciones del centro principal y el otro la cinta consolidada de todos los centros

    En la sesión de NOVA, el centro principal reúne 3.564.476 acciones y la cinta consolidada 8.888.714. Antes de comparar volúmenes, VWAP o máximos y mínimos, hay que saber qué cinta usa cada fuente.

  5. ¿Qué son los datos de referencia?

    • ALos precios de cierre oficiales
    • BLa información que describe los instrumentos y su vida: especificaciones de contratos, eventos corporativos, calendarios, símbolos y composición de universos
    • CLos datos de un índice de referencia
    • DLos datos con retraso de 15 minutos
    Ver respuesta

    Respuesta B. La información que describe los instrumentos y su vida: especificaciones de contratos, eventos corporativos, calendarios, símbolos y composición de universos

    Sin multiplicador, tick, vencimientos, splits, cambios de símbolo o fechas de alta y baja en un índice, los precios no se pueden interpretar ni ajustar. Ocupan poco, pero un error en ellos estropea todo lo demás.

Ideas clave

  • Los datos de mercado forman una escalera: mensajes orden a orden (L3) → libro por niveles (L2) → mejor precio (L1, cotizaciones) y operaciones → barras → datos diarios. Cada peldaño se obtiene del anterior, nunca al revés.
  • En NOVA, una sesión es 1 fila en datos diarios, 78 en barras de 5 minutos, 50.946 operaciones, 129.247 cotizaciones y del orden de medio millón de mensajes L3.
  • La granularidad se elige por la pregunta: una regla diaria no necesita ticks; un estudio de costes de ejecución necesita operaciones y cotizaciones; uno de colas y prioridad, L3.
  • Cinta consolidada y un solo centro dan volúmenes, máximos, mínimos y VWAP distintos. En NOVA, el centro principal reúne solo el 40 % del volumen.
  • Cada marca de tiempo tiene su convención: evento o recepción, inicio o fin de barra, UTC o hora local. Equivocarse es una fuente de sesgo de anticipación.
  • Los datos de referencia (especificaciones, eventos corporativos, universos) ocupan poco y lo condicionan todo.

Recursos