Lección 1.1.3 · 60 min

Libro de órdenes: bid, ask, spread y profundidad

El libro de órdenes es la lista de lo que los demás están dispuestos a comprar y vender, y a qué precio. Esta lección lo lee en sus tres niveles de detalle sobre la sesión de NOVA: el mejor precio, la escalera de diez niveles y los mensajes orden a orden, con los que se reconstruye el libro y se descubre una orden iceberg.

Fig. — Libro de NOVA a las 15:00 de Nueva York del 2 de junio de 2025: tamaño visible por nivel, compras a la izquierda y ventas a la derecha
03/05
Módulo
1.1 · Cómo funcionan los mercados
Duración
60 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

Qué es un libro de órdenes

En la negociación continua, cada orden limitada que no se ejecuta al llegar se queda esperando en el libro de órdenes: una lista ordenada de lo que otros participantes están dispuestos a comprar y vender. El libro tiene dos lados:

  • Bid (compras). Órdenes de compra ordenadas de mayor a menor precio. El primero es el mejor bid: el precio más alto que alguien paga ahora mismo.
  • Ask u offer (ventas). Órdenes de venta ordenadas de menor a mayor precio. El primero es el mejor ask: el precio más bajo al que alguien vende ahora mismo.

La distancia entre el mejor ask y el mejor bid es la horquilla (spread). Si alguien quiere comprar ya, paga el ask; si quiere vender ya, cobra el bid. Por eso la horquilla es el primer coste de operar (lección 1.1.5). El precio medio es el punto entre los dos, y es la referencia habitual de «el precio» en un instante.

Cada nivel es un precio con órdenes. Su tamaño es la suma de las acciones de todas las órdenes a ese precio. La profundidad es cuánto hay en el libro: en un nivel, en los cinco primeros, a menos de un céntimo del medio… Los precios van de tick en tick, el salto mínimo de precio: en NOVA, como en la mayoría de las acciones de EE. UU., un céntimo.

Los datos de esta lección son el libro visible de NOVA, la acción ficticia de la lección 1.1.1, el 2 de junio de 2025. Recuerda la simplificación del simulador: hay un único libro visible, el agregado de los centros con libro.

Tres niveles de detalle: L1, L2 y L3

Los proveedores venden el libro con tres grados de detalle, y cada uno se obtiene agregando el siguiente:

suma por preciosolo el primeroejecucionesL3: cada ordenL2: por nivelL1: mejor precioOperaciones
Fuente Mermaid
flowchart TB
  L3[L3: cada orden] -->|suma por precio| L2[L2: por nivel]
  L2 -->|solo el primero| L1[L1: mejor precio]
  L3 -->|ejecuciones| T[Operaciones]
NivelQué contieneEn los datos del cursoPara qué sirve
L1 (top of book)Mejor bid y mejor ask con sus tamañosnova_cotizaciones.parquet, una fila por cambioHorquilla, precio medio, alinear operaciones (1.1.1)
L2 (market by price)Varios niveles por lado, con tamaño y número de órdenesnova_libro_l2.parquet, 10 niveles cada 10 sProfundidad, impacto de una orden grande, desequilibrio
L3 (market by order)Cada orden: alta, cancelación, modificación y ejecución, con su identificadornova_libro_l3.parquet, 5 minutosCola de prioridad, icebergs, reconstrucción exacta del libro

Cuanto más detalle, más volumen de datos y más caro (lección 1.3.1). En NOVA, cinco minutos de L3 son 7.241 mensajes: a ese ritmo, la sesión completa pasaría del medio millón, frente a 129.247 cambios de L1 en todo el día. Para un sistema que opera a diario basta con L1 y barras; para estudiar costes de ejecución hace falta L2; para modelar la cola o la llegada de órdenes, L3.

Una foto del libro, nivel a nivel

Las fotos L2 de NOVA tienen una fila por nivel y lado, cada 10 segundos. Esta es la de las 19:00:00 UTC, las 15:00 de Nueva York, puesta como una escalera: compras a la izquierda, ventas a la derecha.

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

l2 = pd.read_parquet("nova_libro_l2.parquet")
foto = l2[l2["ts"] == "2025-06-02 19:00:00+00:00"]

bid = foto[foto["lado"] == "bid"].set_index("nivel")
ask = foto[foto["lado"] == "ask"].set_index("nivel")
escalera = pd.concat({
    "bid": bid[["ordenes", "tamano", "precio"]],
    "ask": ask[["precio", "tamano", "ordenes"]],
}, axis=1)
escalera
OUT [01]Foto L2 de las 15:00 de Nueva York
          bid                    ask
      ordenes   tamano precio precio tamano ordenes
nivel
1        36.0  13432.0  52.74  52.75   1870       5
2        44.0   9380.0  52.73  52.76   9900      18
3        41.0   9059.0  52.72  52.77  13280      29
4         5.0   1800.0  52.71  52.78  17322      54
5         2.0    600.0  52.70  52.79  14521      49
6         1.0    100.0  52.69  52.80   5142      30
7         3.0    526.0  52.67  52.81   9303      22
8         1.0    300.0  52.64  52.82   4300      11
9         NaN      NaN    NaN  52.83   1229       8
10        NaN      NaN    NaN  52.84   2252       6

La figura de la cabecera dibuja la misma escalera. Se ven varias cosas que no están en un gráfico de precios. El lado comprador solo tiene ocho niveles en ese instante, y entre 52,69 y 52,67 falta el 52,68: «nivel» es un precio con órdenes, no cada tick. El primer nivel de compra tiene 13.432 acciones repartidas en 36 órdenes; el de venta, solo 1.870 en 5. Y en los diez niveles hay más del doble de acciones a la venta que a la compra. La foto es un instante: diez segundos después será otra.

Las medidas de L1 salen de los dos primeros niveles:

IN [02]python
def medidas_l1(foto):
    b = foto[(foto["lado"] == "bid") & (foto["nivel"] == 1)].iloc[0]
    a = foto[(foto["lado"] == "ask") & (foto["nivel"] == 1)].iloc[0]
    medio = (b["precio"] + a["precio"]) / 2
    horquilla = a["precio"] - b["precio"]
    qb, qa = b["tamano"], a["tamano"]
    return pd.Series({
        "bid": b["precio"], "ask": a["precio"], "medio": medio,
        "horquilla_ticks": round(horquilla / 0.01),
        "horquilla_pb": 1e4 * horquilla / medio,
        "desequilibrio": (qb - qa) / (qb + qa),
        "microprecio": (b["precio"] * qa + a["precio"] * qb)
                       / (qb + qa),
    })

medidas_l1(foto).round(4)
OUT [02]Horquilla, precio medio, desequilibrio y microprecio
bid                52.7400
ask                52.7500
medio              52.7450
horquilla_ticks     1.0000
horquilla_pb        1.8959
desequilibrio       0.7556
microprecio        52.7488
dtype: float64

La horquilla es de un tick, 1,9 puntos básicos sobre el precio medio. El desequilibrio del primer nivel va de −1 (solo hay venta) a +1 (solo compra):

I=qb−qaqb+qaI = \frac{q_b - q_a}{q_b + q_a}

Aquí vale 0,76: casi todo el primer nivel es compra. El microprecio pondera cada precio por el tamaño del lado contrario:

Pmicro=Pb qa+Pa qbqb+qaP_{\text{micro}} = \frac{P_b\, q_a + P_a\, q_b}{q_b + q_a}

Con 13.432 acciones esperando a comprar a 52,74 y solo 1.870 vendiendo a 52,75, lo probable es que el ask se agote antes que el bid, y el precio medio suba medio céntimo. El microprecio, 52,7488, ya está casi en el ask.

Profundidad acumulada

La pregunta práctica es cuántas acciones se pueden comprar o vender sin alejarse demasiado del precio medio. La profundidad acumulada la responde: para cada precio, la suma de lo que hay desde el mejor nivel hasta él.

IN [03]python
medio = medidas_l1(foto)["medio"]
prof = foto.sort_values(["lado", "nivel"]).copy()
prof["acumulado"] = prof.groupby("lado")["tamano"].cumsum()
prof["distancia_cent"] = (100 * (prof["precio"] - medio).abs()).round(1)
print(prof.groupby("lado")["tamano"].sum().to_string())
prof.pivot(index="nivel", columns="lado",
           values=["distancia_cent", "acumulado"])
OUT [03]Profundidad acumulada a cada lado
lado
ask    79119
bid    35197
      distancia_cent       acumulado
lado             ask   bid       ask      bid
nivel
1                0.5   0.5    1870.0  13432.0
2                1.5   1.5   11770.0  22812.0
3                2.5   2.5   25050.0  31871.0
4                3.5   3.5   42372.0  33671.0
5                4.5   4.5   56893.0  34271.0
6                5.5   5.5   62035.0  34371.0
7                6.5   7.5   71338.0  34897.0
8                7.5  10.5   75638.0  35197.0
9                8.5   NaN   76867.0      NaN
10               9.5   NaN   79119.0      NaN
Fig. — Profundidad acumulada del libro de NOVA a las 15:00 de Nueva York: acciones disponibles desde el precio medio hasta cada precio

A menos de 2,5 céntimos del medio hay 31.871 acciones a la compra (tres niveles) y 25.050 a la venta. Más allá, el lado vendedor sigue engordando mientras el comprador se queda casi plano: en 10 niveles, 35.197 contra 79.119. Una orden de compra de 20.000 acciones necesitaría los tres primeros niveles de venta; una de venta del mismo tamaño se llenaría con el primer nivel de compra y parte del segundo. Cuánto cuesta en cada caso es el impacto de la orden, que la lección 1.1.4 calcula recorriendo el libro y la 1.1.5 convierte en coste.

La horquilla a lo largo de la sesión

En una acción líquida con un precio de unas decenas de dólares, la horquilla suele estar pegada al mínimo, un tick. Las 2.340 fotos de la sesión permiten ver cuándo se abre:

IN [04]python
n1 = l2[l2["nivel"] == 1].pivot(index="ts", columns="lado",
                                values=["precio", "tamano"])
pb, pa = n1[("precio", "bid")], n1[("precio", "ask")]
qb, qa = n1[("tamano", "bid")], n1[("tamano", "ask")]
ticks = ((pa - pb) / 0.01).round()
pbs = 1e4 * (pa - pb) / ((pa + pb) / 2)

hora_ny = n1.index.tz_convert("America/New_York")
tabla = pd.DataFrame({"ticks": ticks.values, "pb": pbs.values,
                      "mas_de_1": (ticks > 1).values}, index=hora_ny)
print(ticks.value_counts().sort_index().to_string())
tabla.resample("30min").mean().round(3)
OUT [04]Horquilla de las fotos L2 por media hora
1.0    2252
2.0      87
3.0       1
                           ticks     pb  mas_de_1
ts
2025-06-02 09:30:00-04:00  1.022  1.916     0.022
2025-06-02 10:00:00-04:00  1.039  1.947     0.039
2025-06-02 10:30:00-04:00  1.028  1.925     0.028
2025-06-02 11:00:00-04:00  1.033  1.926     0.028
2025-06-02 11:30:00-04:00  1.044  1.940     0.044
2025-06-02 12:00:00-04:00  1.039  1.933     0.039
2025-06-02 12:30:00-04:00  1.028  1.914     0.028
2025-06-02 13:00:00-04:00  1.056  1.963     0.056
2025-06-02 13:30:00-04:00  1.006  1.883     0.006
2025-06-02 14:00:00-04:00  1.044  1.957     0.044
2025-06-02 14:30:00-04:00  1.022  1.931     0.022
2025-06-02 15:00:00-04:00  1.022  1.940     0.022
2025-06-02 15:30:00-04:00  1.111  2.102     0.111
Fig. — Porcentaje de fotos L2 de NOVA con horquilla de más de un tick en cada media hora del 2 de junio de 2025

El 96,2 % de las fotos tiene la horquilla mínima, de un tick. Las demás se reparten por el día, con más frecuencia en la última media hora, cuando la llegada de órdenes se acelera antes de la subasta de cierre (lección 1.1.2) y los creadores de mercado ajustan sus cotizaciones. En puntos básicos la horquilla depende del precio: el mismo céntimo es 1,88 puntos básicos con la acción a 53 USD y sería 10 con la acción a 10 USD. Para comparar costes entre activos, la horquilla se mide en puntos básicos; para entender la mecánica, en ticks.

¿Anticipa el libro el siguiente precio?

Si el primer nivel de venta está casi vacío y el de compra lleno, lo siguiente que suele pasar es que el ask se agote y el precio medio suba. Con las fotos de NOVA se puede medir: para cada foto, el desequilibrio y el cambio del precio medio hasta la foto siguiente, diez segundos después.

IN [05]python
medio_s = (pa + pb) / 2
deseq = (qb - qa) / (qb + qa)
cambio = 100 * (medio_s.shift(-1) - medio_s)   # céntimos
df = pd.DataFrame({"deseq": deseq, "cambio": cambio}).dropna()
df["tramo"] = pd.cut(df["deseq"], [-1, -0.6, -0.2, 0.2, 0.6, 1],
                     include_lowest=True)
print(f"correlación: {df['deseq'].corr(df['cambio']):.2f}")
df.groupby("tramo", observed=True)["cambio"].agg(
    ["mean", "size"]).round(3)
OUT [05]Desequilibrio y cambio del precio medio a 10 segundos
correlación: 0.56
                 mean  size
tramo
(-1.001, -0.6] -0.645   599
(-0.6, -0.2]   -0.146   374
(-0.2, 0.2]    -0.036   388
(0.2, 0.6]      0.088   382
(0.6, 1.0]      0.661   596
Fig. — Cambio medio del precio medio de NOVA en los 10 segundos siguientes según el desequilibrio del primer nivel del libro, 2 de junio de 2025

La relación es clara y casi simétrica: cuando el primer nivel está muy cargado a la venta (desequilibrio por debajo de −0,6), el precio medio baja de media 0,65 céntimos en los diez segundos siguientes; cuando está muy cargado a la compra, sube 0,66. La correlación es de 0,56. ¿Por qué el microprecio es mejor estimación del precio «verdadero» que el medio? Porque ya incorpora esa información. Comparando los dos con el precio medio de la foto siguiente:

IN [06]python
micro = (pb * qa + pa * qb) / (qb + qa)
siguiente = medio_s.shift(-1)
ok = siguiente.notna()
for nombre, pred in (("medio", medio_s), ("microprecio", micro)):
    rmse = np.sqrt(((siguiente - pred)[ok] ** 2).mean())
    print(f"{nombre:<12} error cuadrático medio: {100 * rmse:.3f} cent")
OUT [06]Medio frente a microprecio como predicción
medio        error cuadrático medio: 0.867 cent
microprecio  error cuadrático medio: 0.736 cent

El microprecio reduce el error de predicción del precio medio siguiente de 0,867 a 0,736 céntimos, un 15 %. Son datos sintéticos, en los que la relación se ha construido de forma limpia; en datos reales también aparece, pero más débil y a horizontes muy cortos, segundos o menos.

Prioridad precio-tiempo

Cuando llega una orden agresiva, ¿contra qué orden del libro se ejecuta? En casi todos los mercados de acciones, por prioridad precio-tiempo: primero el mejor precio y, dentro del mismo precio, la orden que llegó antes. Cada nivel es una cola.

Compra a mercado1.ª, más antigua2.ª ordenÚltima llegada
Fuente Mermaid
flowchart LR
  C[Compra a mercado] --> A[1.ª, más antigua]
  A --> B[2.ª orden]
  B --> N[Última llegada]

Las consecuencias son concretas. Una orden nueva se pone al final de la cola de su precio. Reducir el tamaño de una orden conserva su puesto; aumentarlo o cambiarle el precio equivale a cancelarla y enviar otra, que va al final. Y una orden limitada en el mejor bid no se ejecuta hasta que se hayan ejecutado o cancelado todas las que tenía delante. Por eso «el precio tocó mi límite» no significa «mi orden se ejecutó» (lección 1.1.4).

Del L3 al L2: reconstruir el libro

El fichero L3 tiene los mensajes orden a orden entre las 14:00 y las 14:05 UTC. Las 358 primeras filas, todas con la marca de las 14:00:00, son la foto inicial: cada orden viva, en orden de prioridad. Después viene un mensaje por cambio.

IN [07]python
l3 = pd.read_parquet("nova_libro_l3.parquet")
print(len(l3), "mensajes")
print(l3["evento"].value_counts().to_string())
l3.iloc[358:364]
OUT [07]Mensajes L3
7241 mensajes
evento
alta            3443
cancelacion     2842
ejecucion        746
modificacion     210
                                  ts  id_orden       evento lado  precio  tamano
358 2025-06-02 14:00:00.111345+00:00  41031081         alta  bid   53.03     200
359 2025-06-02 14:00:00.121651+00:00  41031083         alta  bid   52.99      97
360 2025-06-02 14:00:00.154247+00:00  41030881  cancelacion  ask   53.12     100
361 2025-06-02 14:00:00.178017+00:00  41031084         alta  ask   53.10    1000
362 2025-06-02 14:00:00.209129+00:00  41030590  cancelacion  bid   53.04     200
363 2025-06-02 14:00:00.260941+00:00  41030785  cancelacion  ask   53.13     100

Las reglas de cada mensaje: alta añade una orden al final de la cola de su precio; cancelacion la quita; modificacion deja el nuevo tamaño y conserva la prioridad; ejecucion resta lo ejecutado y, si llega a cero, la orden sale. Con un diccionario de Python, que conserva el orden de inserción, eso es todo lo que hace falta para mantener las colas:

IN [08]python
def aplica(libro, m):
    """Aplica un mensaje L3 al libro {id: [lado, precio, tamaño]}."""
    if m.evento == "alta":
        libro[m.id_orden] = [m.lado, m.precio, m.tamano]
    elif m.evento == "cancelacion":
        del libro[m.id_orden]
    elif m.evento == "modificacion":
        libro[m.id_orden][2] = m.tamano      # conserva el puesto
    elif m.evento == "ejecucion":
        libro[m.id_orden][2] -= m.tamano
        if libro[m.id_orden][2] == 0:
            del libro[m.id_orden]

def a_l2(libro, n=10):
    """Agrega las órdenes por precio: el L2 de n niveles."""
    df = pd.DataFrame(list(libro.values()),
                      columns=["lado", "precio", "tamano"])
    g = (df.groupby(["lado", "precio"])["tamano"]
           .agg(tamano="sum", ordenes="size").reset_index())
    bids = g[g["lado"] == "bid"].nlargest(n, "precio")
    asks = g[g["lado"] == "ask"].nsmallest(n, "precio")
    out = pd.concat([bids, asks])
    out["nivel"] = out.groupby("lado").cumcount() + 1
    cols = ["lado", "nivel", "precio", "tamano", "ordenes"]
    return out[cols].reset_index(drop=True)

Ahora se reproducen los mensajes en orden y, en cada instante en que hay foto L2 (cada 10 segundos), se compara el libro reconstruido con la foto. Cada foto incluye todos los mensajes con marca de tiempo menor o igual que la suya:

IN [09]python
fotos = pd.date_range("2025-06-02 14:00:00", "2025-06-02 14:05:00",
                      freq="10s", tz="UTC")
libro, iguales, i = {}, 0, 0
mensajes = list(l3.itertuples(index=False))
for t in fotos:
    while i < len(mensajes) and mensajes[i].ts <= t:
        aplica(libro, mensajes[i])
        i += 1
    ref = l2[l2["ts"] == t].drop(columns="ts").reset_index(drop=True)
    iguales += a_l2(libro).equals(ref)
print(f"{iguales} de {len(fotos)} fotos coinciden")
print(len(libro), "órdenes vivas a las 14:05:00")
OUT [09]Las 31 fotos de la ventana, reconstruidas
31 de 31 fotos coinciden
345 órdenes vivas a las 14:05:00

Las 31 fotos coinciden exactamente: niveles, precios, tamaños y número de órdenes. Es la comprobación que conviene hacer siempre con un feed L3 propio: si el libro reconstruido se desvía del L2 del proveedor, falta algún mensaje o se ha aplicado mal una regla. Otra comprobación barata: las ejecuciones del L3 deben sumar el volumen de los centros con libro en la cinta de operaciones.

IN [10]python
op = pd.read_parquet("nova_operaciones.parquet")
ventana = op[(op["ts"] > "2025-06-02 14:00:00+00:00")
             & (op["ts"] <= "2025-06-02 14:05:00+00:00")]
con_libro = ventana["centro"].isin(["PRINCIPAL", "MTF_A", "MTF_B"])
print("L3:", l3.loc[l3["evento"] == "ejecucion", "tamano"].sum())
print("cinta, centros con libro:",
      ventana.loc[con_libro, "tamano"].sum())
print("cinta, todos los centros:", ventana["tamano"].sum())
OUT [10]Ejecuciones L3 frente a la cinta
L3: 78705
cinta, centros con libro: 78705
cinta, todos los centros: 134726

Las 78.705 acciones ejecutadas contra el libro coinciden con la cinta. El resto del volumen de esos cinco minutos se cruzó en el oscuro y en el internalizador, que no pasan por el libro: el L3 más completo de una bolsa no enseña toda la negociación de la acción.

Con el libro reconstruido se ve la cola completa de un nivel, que ningún L2 enseña:

IN [11]python
cola = [(oid, o[2]) for oid, o in libro.items()
        if o[0] == "bid" and o[1] == max(
            v[1] for v in libro.values() if v[0] == "bid")]
print("precio:", libro[cola[0][0]][1], "· órdenes:", len(cola),
      "· acciones:", sum(q for _, q in cola))
pd.DataFrame(cola[:5], columns=["id_orden", "tamano"])
OUT [11]La cola del mejor bid a las 14:05:00
precio: 53.17 · órdenes: 34 · acciones: 14140
   id_orden  tamano
0  41034369    1078
1  41034404     200
2  41034422     100
3  41034426      62
4  41034433     500

La primera orden de la cola tiene 1.078 acciones y se ejecutará antes que ninguna otra a ese precio. Una orden de compra nueva a 53,17 tendría delante 14.140 acciones: antes de que le toque, alguien tiene que vender todo eso, o las órdenes de delante cancelarse.

La orden iceberg

Una orden iceberg enseña solo una parte de su tamaño. Cuando la parte visible se ejecuta entera, el sistema repone otro tramo desde la reserva oculta, con el mismo identificador y al final de la cola. En el L2 solo se ve el tramo visible. En el L3 la delata la repetición: una orden normal tiene un único alta.

IN [12]python
altas = l3[l3["evento"] == "alta"].groupby("id_orden").size()
print(altas[altas > 1].to_string())

ice = l3[l3["id_orden"] == altas.idxmax()]
print(ice.groupby("evento")["tamano"].agg(["size", "sum"]).to_string())
print("precio:", ice["precio"].iloc[0], "· lado:", ice["lado"].iloc[0])
print("de", ice["ts"].min().strftime("%H:%M:%S"),
      "a", ice["ts"].max().strftime("%H:%M:%S.%f"))
OUT [12]Órdenes con más de un alta
id_orden
41031312    30
           size   sum
evento
alta         30  9000
ejecucion    86  9000
precio: 53.09 · lado: ask
de 14:00:20 a 14:01:31.224465

La orden 41031312 vende a 53,09. Aparece 30 veces con 300 acciones (la primera y 29 reposiciones) y se ejecuta en 86 trozos que suman 9.000 acciones, todo lo que tenía, entre las 14:00:20 y las 14:01:31. Quien miraba el L2 veía en 53,09 unos cientos de acciones a la venta; en realidad había 9.000. El efecto en el precio se ve en la cotización:

IN [13]python
cot = pd.read_parquet("nova_cotizaciones.parquet").set_index("ts")
tramo = cot["2025-06-02 14:00:10":"2025-06-02 14:02:00"]
tramo.resample("10s").last()
OUT [13]El mejor precio mientras dura la iceberg
                             bid    ask  tam_bid  tam_ask
ts
2025-06-02 14:00:10+00:00  53.08  53.09     3631    13073
2025-06-02 14:00:20+00:00  53.08  53.09    12431    10914
2025-06-02 14:00:30+00:00  53.08  53.09    19151     2361
2025-06-02 14:00:40+00:00  53.08  53.09    26743      653
2025-06-02 14:00:50+00:00  53.08  53.09    32909       71
2025-06-02 14:01:00+00:00  53.08  53.09    37482      259
2025-06-02 14:01:10+00:00  53.08  53.09    41363      259
2025-06-02 14:01:20+00:00  53.08  53.09    38533      249
2025-06-02 14:01:30+00:00  53.09  53.10     7681       54
2025-06-02 14:01:40+00:00  53.11  53.12     6156       89
2025-06-02 14:01:50+00:00  53.13  53.15     3946     4475
2025-06-02 14:02:00+00:00  53.13  53.15     3850     4975
Fig. — Mejor bid y mejor ask de NOVA entre las 14:00 y las 14:02:30 UTC del 2 de junio de 2025, con la orden iceberg de venta en 53,09

Durante algo más de un minuto, el ask no se mueve de 53,09 aunque el tamaño visible a la venta se reduce a unas decenas o cientos de acciones y el bid acumula decenas de miles: cada vez que el tramo visible se agota, aparece otro. Cuando la reserva se termina, a las 14:01:31, el ask pasa de 53,09 a 53,15 en menos de treinta segundos. Para quien compra, la iceberg es liquidez que no esperaba; para quien estudia el libro, un desequilibrio que «debería» haber movido el precio y no lo hizo.

Ejercicios

  1. Calcula la horquilla en puntos básicos, el desequilibrio y el microprecio de la foto L2 de las 13:30:00 UTC, la primera de la sesión, y compáralos con los de las 15:00 de Nueva York.
Solución
IN [14]python
primera = l2[l2["ts"] == "2025-06-02 13:30:00+00:00"]
pd.DataFrame({"13:30 UTC": medidas_l1(primera),
              "19:00 UTC": medidas_l1(foto)}).round(4)
OUT [14]Medidas L1 de la primera foto
                 13:30 UTC  19:00 UTC
bid                53.3400    52.7400
ask                53.3600    52.7500
medio              53.3500    52.7450
horquilla_ticks     2.0000     1.0000
horquilla_pb        3.7488     1.8959
desequilibrio       0.4118     0.7556
microprecio        53.3541    52.7488

En la primera foto, justo después de la subasta de apertura, la horquilla es de dos ticks (53,34 a 53,36) y el libro todavía es fino: 1.200 acciones en el mejor bid y 500 en el mejor ask. El desequilibrio es positivo y el microprecio queda por encima del medio, como a las 15:00, pero con una horquilla doble. Los primeros segundos de la sesión continua son los más caros de cruzar.

  1. Con el libro reconstruido a las 14:05:00, ¿cuántas acciones tendría delante una orden de venta nueva al mejor ask? ¿Y una al segundo nivel de venta?
Solución
IN [15]python
asks = sorted({o[1] for o in libro.values() if o[0] == "ask"})
for precio in asks[:2]:
    delante = sum(o[2] for o in libro.values()
                  if o[0] == "ask" and o[1] <= precio)
    print(f"vendiendo a {precio}: {delante} acciones por delante")
OUT [15]Acciones por delante en la cola de venta
vendiendo a 53.18: 4654 acciones por delante
vendiendo a 53.19: 37172 acciones por delante

A precio igual, la orden nueva va al final de la cola, así que tiene delante todo el nivel: 4.654 acciones en 53,18. En 53,19 tendría delante 37.172. En el segundo nivel tiene delante ese nivel entero (32.518 acciones) y además el primero, que se ejecuta antes por tener mejor precio. Cuanto más lejos del mejor precio, más probable es que la orden no se ejecute nunca si el precio se da la vuelta.

  1. Un proveedor te ofrece L1 gratis, L2 por una cuota mensual y L3 por una cuota mucho mayor. Tu sistema opera una vez al día, con órdenes de 500 acciones de acciones muy líquidas. ¿Qué nivel necesitas y para qué usarías cada uno?
Solución

Con L1 y barras basta para operar: el tamaño (500 acciones) está muy por debajo de la profundidad típica del primer nivel, así que el coste es esencialmente media horquilla, y la horquilla sale del L1. Un L2 serviría para comprobar de vez en cuando que la profundidad sigue siendo suficiente (por ejemplo, en la apertura o en días de noticias) y para estimar el impacto si el tamaño crece. El L3 no aporta nada a ese horizonte: sirve para modelar colas, icebergs y la llegada de órdenes, cosas que importan a quien opera en segundos o provee liquidez.

Respuesta plegada en cada pregunta

Autoevaluación

  1. El mejor bid de NOVA es 52,74 y el mejor ask 52,75. ¿Cuál es la horquilla en puntos básicos sobre el precio medio?

    • A1 punto básico
    • BUnos 1,9 puntos básicos
    • C0,01 puntos básicos
    • D19 puntos básicos
    Ver respuesta

    Respuesta B. Unos 1,9 puntos básicos

    La horquilla es 0,01 USD, un tick. Sobre el precio medio, 52,745, es 0,01 / 52,745 = 0,000190, es decir, 1,90 puntos básicos. En ticks es la mínima posible; en puntos básicos depende del precio de la acción.

  2. ¿Qué contiene un dato L2 que no contiene un L1?

    • ALas operaciones ejecutadas
    • BEl tamaño agregado en varios niveles de precio a cada lado, no solo en el mejor
    • CEl identificador de cada orden
    • DQuién envió cada orden
    Ver respuesta

    Respuesta B. El tamaño agregado en varios niveles de precio a cada lado, no solo en el mejor

    L1 es el mejor bid y el mejor ask con sus tamaños. L2 añade los siguientes niveles de precio, cada uno con el tamaño total y, a veces, el número de órdenes. El identificador de cada orden es L3; quién la envió no lo publica ningún nivel.

  3. En la foto de las 15:00 de Nueva York, el mejor bid tiene 13.432 acciones y el mejor ask 1.870. ¿Dónde está el microprecio?

    • AJusto en el punto medio, 52,745
    • BCerca del ask, en torno a 52,749
    • CCerca del bid, en torno a 52,741
    • DPor debajo del bid
    Ver respuesta

    Respuesta B. Cerca del ask, en torno a 52,749

    El microprecio pondera cada precio por el tamaño del lado contrario: bid × tamaño del ask + ask × tamaño del bid, dividido por la suma. Con mucha más compra que venta en el primer nivel, se acerca al ask: el lado delgado es el que está a punto de agotarse.

  4. Una orden de venta aparece una y otra vez con el mismo identificador al final de la cola de 53,09, siempre con 300 acciones, cada vez que se ejecuta entera. ¿Qué es?

    • AUn error del proveedor de datos
    • BUna orden iceberg: enseña 300 acciones y repone la parte visible desde una reserva oculta
    • CUn creador de mercado que cancela y vuelve a enviar
    • DUna orden stop
    Ver respuesta

    Respuesta B. Una orden iceberg: enseña 300 acciones y repone la parte visible desde una reserva oculta

    Una iceberg tiene una parte visible y una reserva. Al agotarse lo visible, el sistema repone otro tramo con el mismo identificador y lo pone al final de la cola, porque la parte nueva pierde la prioridad temporal. En el L2 solo se ve el tramo visible; en el L3 la delata la repetición del identificador.

  5. Llega una orden de compra a mercado de 500 acciones y en el mejor ask hay tres órdenes: A (200, la más antigua), B (100) y C (400). ¿Cómo se reparte?

    • AContra C, la más grande
    • B200 contra A, 100 contra B y 200 contra C
    • CA partes iguales entre las tres
    • DContra la más reciente
    Ver respuesta

    Respuesta B. 200 contra A, 100 contra B y 200 contra C

    Con prioridad precio-tiempo, dentro de un mismo precio se ejecuta primero la orden que llegó antes. A se llena entera, luego B, y C se ejecuta por lo que falta (200) y le quedan 200 en el libro, conservando su puesto.

Ideas clave

  • El libro tiene dos lados: compras (bid) ordenadas de mayor a menor precio y ventas (ask) de menor a mayor. La distancia entre los mejores es la horquilla.
  • L1 es el mejor precio de cada lado; L2, varios niveles con el tamaño agregado; L3, cada orden con su identificador. Cada nivel se obtiene agregando el siguiente.
  • La profundidad dice cuánto se puede ejecutar sin mover mucho el precio, y cambia de un instante a otro: el libro visible de NOVA a las 15:00 tenía 35.197 acciones a la compra y 79.119 a la venta en diez niveles.
  • El desequilibrio del primer nivel anticipa el siguiente movimiento del precio medio en los datos de NOVA; el microprecio lo incorpora en una sola cifra.
  • La prioridad precio-tiempo decide quién se ejecuta primero. Con los mensajes L3 se reconstruye el libro exacto, y el L2 que se obtiene coincide con las 31 fotos de la ventana.

Recursos