Lección 1.1.2 · 55 min
Sesiones, subastas, festivos y calendarios
Un mercado abre y cierra a horas que cambian con la zona horaria, el horario de verano, los festivos y las medias sesiones. Esta lección calcula las sesiones de seis bolsas con exchange_calendars, reconstruye una subasta de apertura orden a orden y mide por qué el cierre concentra tanto volumen.
- Módulo
- 1.1 · Cómo funcionan los mercados
- Duración
- 55 min
Lecciones del nivel 1
1.1 · Cómo funcionan los mercados
1.2 · Clases de activos
- 1.2.1 Acciones: splits, dividendos y eventos corporativos
- 1.2.2 ETFs: réplica, tracking error, apalancados y UCITS
- 1.2.3 Futuros: especificaciones, margen, roll y contango
- 1.2.4 Forex: pares, pips, lotes, rollover y CFD
- 1.2.5 Opciones: call, put, valor intrínseco y valor temporal
- 1.2.6 Cripto: spot, perpetuos, funding y custodia
- 1.2.7 Renta fija y tipos de interés; CFDs y productos apalancados
1.3 · Fuentes de datos de mercado
- 1.3.1 Tipos de datos de mercado: EOD, barras, ticks, libro y referencia
- 1.3.2 Fuentes de datos gratuitas
- 1.3.3 APIs de datos retail y prosumer
- 1.3.4 Proveedores de datos profesionales
- 1.3.5 Datos de cripto y on-chain
- 1.3.6 Brókeres como fuente de datos
- 1.3.7 Licencias y términos de uso de datos
- 1.3.8 Cómo elegir proveedor de datos
1.4 · Ingeniería de datos financieros
- 1.4.1 Descarga por REST y websockets: paginación, límites y reintentos
- 1.4.2 Limpieza de datos: faltantes, ticks erróneos, huecos y zonas horarias
- 1.4.3 Ajustes por splits y dividendos: precios ajustados y sin ajustar
- 1.4.4 Universos sin sesgo de supervivencia: deslistados, fusiones y cambios de símbolo
- 1.4.5 Construcción de barras: tiempo, ticks, volumen, dólar y desequilibrio
- 1.4.6 Series continuas de futuros: reglas de roll, ajuste por diferencia y ajuste por ratio
- 1.4.7 Almacenamiento: CSV, Parquet, particionado, DuckDB, TimescaleDB y ArcticDB
- 1.4.8 Pipeline reproducible: descarga, validación, actualización incremental y tests de calidad
1.5 · Datos fundamentales y macro
1.6 · Análisis exploratorio financiero
1.7 · Análisis técnico programado
Las fases de una sesión
En una bolsa de acciones no se negocia de la misma forma a todas horas. La sesión se divide en fases y cada una tiene sus reglas para cruzar órdenes. Las dos formas básicas son la negociación continua, en la que una orden que llega se ejecuta al momento contra las que ya esperan en el libro (lección 1.1.3), y la subasta, en la que las órdenes se acumulan durante un tiempo sin ejecutarse y al final se cruzan todas a un único precio.
Fuente Mermaid
stateDiagram-v2 [*] --> Preapertura Preapertura --> Continua: subasta apertura Continua --> Volatilidad: precio fuera rango Volatilidad --> Continua: fin de subasta Continua --> Cierre: hora de cierre Cierre --> Poscierre: precio de cierre Poscierre --> [*]
- Preapertura y subasta de apertura. Se pueden enviar, modificar y cancelar órdenes, pero no hay operaciones. El sistema publica un precio teórico de equilibrio que se va moviendo con las órdenes. Al final, todas las órdenes compatibles se cruzan al mismo precio: el de apertura.
- Negociación continua. El libro está abierto: cada orden agresiva se ejecuta contra la mejor contraria.
- Subasta de volatilidad. Si una operación fuera a producirse demasiado lejos del último precio o del precio de referencia, el mercado suspende la negociación continua de ese valor y abre una subasta corta. Sirve para que una noticia o un error no se conviertan en una cascada de operaciones a precios absurdos. Los umbrales y la duración los fija cada bolsa en su reglamento, y en un backtest aparecen como huecos de unos minutos sin operaciones.
- Subasta de cierre. Igual que la de apertura, al final del día. Fija el precio de cierre oficial.
- Poscierre. En algunas bolsas, un rato en el que se puede operar solo al precio de cierre.
Dos bolsas que se usan a menudo en el curso, con sus horarios oficiales en hora local:
| Fase | NYSE (Nueva York) | BME, mercado continuo (Madrid) |
|---|---|---|
| Entrada de órdenes | desde las 6:30 | — |
| Subasta de apertura | cruce a las 9:30 | de 8:30 a 9:00 |
| Negociación continua | de 9:30 a 16:00 | de 9:00 a 17:30 |
| Periodo de desequilibrio del cierre | de 15:50 a 16:00 | — |
| Subasta de cierre | cruce a las 16:00 | de 17:30 a 17:35 |
| Negociación al precio de cierre | — | Trading At Last, de 17:35 a 17:45 |
En la NYSE, las órdenes al cierre (MOC y LOC, lección 1.1.4) se pueden enviar, modificar o cancelar hasta las 15:50. A partir de ahí la bolsa publica el desequilibrio entre compras y ventas al cierre y solo admite órdenes que lo reduzcan1Nota 1 · Horarios de la NYSE en su página «Holidays & Trading Hours» y en el folleto «NYSE opening and closing auctions»; los de BME, en la página «Horario Bolsa Española» de BME Exchange (consultadas el 21 de octubre de 2026).. En BME, el Trading At Last permite seguir comprando y vendiendo diez minutos más, pero solo al precio que acaba de fijar la subasta de cierre.
Calendarios de bolsa en Python
Escribir las horas a mano («la NYSE abre a las 15:30 de Madrid») funciona hasta el primer cambio de hora. Un
calendario de bolsa sabe, para cada fecha, si hay sesión, a qué hora abre y cierra en UTC, si hay pausa de
mediodía y si es una media sesión. Las dos librerías de referencia en Python son exchange_calendars (códigos ISO
10383 de mercado, como XNYS; 71 calendarios sin contar alias en la versión 4.13.2) y pandas_market_calendars, que
reutiliza esos calendarios y añade muchos más, sobre todo de futuros (211 nombres, alias incluidos, en la versión
5.5.0). Ambas están instaladas en el entorno del curso.
import exchange_calendars as xcals
import pandas as pd
bolsas = {"XTKS": "Tokio", "XHKG": "Hong Kong", "XLON": "Londres",
"XETR": "Xetra", "XMAD": "Madrid", "XNYS": "Nueva York"}
dia = pd.Timestamp("2025-06-02")
filas = {}
for codigo, nombre in bolsas.items():
cal = xcals.get_calendar(codigo)
filas[nombre] = {
"abre": cal.session_open(dia),
"pausa": cal.session_break_start(dia),
"reanuda": cal.session_break_end(dia),
"cierra": cal.session_close(dia),
}
sesiones = pd.DataFrame(filas).T
hhmm = lambda c: pd.to_datetime(c).dt.strftime("%H:%M")
sesiones.apply(hhmm).fillna("") abre pausa reanuda cierra
Tokio 00:00 02:30 03:30 06:30
Hong Kong 01:30 04:00 05:00 08:00
Londres 07:00 15:30
Xetra 07:00 15:30
Madrid 07:00 15:30
Nueva York 13:30 20:00Todas las horas salen en UTC, que es como hay que guardarlas (lección 0.4.4). Tokio y Hong Kong tienen pausa de
mediodía: una hora sin negociación continua en la que el calendario devuelve pausa y reanuda. En las bolsas sin
pausa esas columnas quedan vacías. En hora local las cosas se reconocen mejor:
for codigo, nombre in bolsas.items():
cal = xcals.get_calendar(codigo)
abre = cal.session_open(dia).tz_convert(cal.tz)
cierra = cal.session_close(dia).tz_convert(cal.tz)
print(f"{nombre:<11} {abre:%H:%M}-{cierra:%H:%M} {cal.tz}")Tokio 09:00-15:30 Asia/Tokyo
Hong Kong 09:30-16:00 Asia/Hong_Kong
Londres 08:00-16:30 Europe/London
Xetra 09:00-17:30 Europe/Berlin
Madrid 09:00-17:30 Europe/Madrid
Nueva York 09:30-16:00 America/New_YorkLa figura de la cabecera dibuja las seis sesiones sobre el mismo eje UTC. Tres cosas se ven a simple vista. Tokio ha cerrado cuando abre Europa, y Hong Kong solo coincide con ella una hora. Londres, Xetra y Madrid abren y cierran a la misma hora UTC ese día. Y entre Europa y Nueva York solo hay dos horas de solape, de 13:30 a 15:30 UTC: el único tramo en el que una estrategia puede comprar en Madrid y vender en Nueva York con los dos libros abiertos.
Ese solape no es fijo. Estados Unidos y Europa cambian la hora en fechas distintas, así que durante unas semanas al año la diferencia entre Madrid y Nueva York es de cinco horas en lugar de seis (la figura de la lección 0.4.4 lo muestra con las aperturas de 2026). El calendario lo resuelve sin que haya que pensarlo:
mad = xcals.get_calendar("XMAD")
nys = xcals.get_calendar("XNYS")
rango = ("2025-01-02", "2025-12-31")
comunes = mad.sessions_in_range(*rango).intersection(
nys.sessions_in_range(*rango))
solape = mad.closes[comunes] - nys.opens[comunes]
(solape.dt.total_seconds() / 3600).value_counts().sort_index()-1.5 2
2.0 225
3.0 20
Name: count, dtype: int64De las 247 sesiones comunes de 2025, 225 tienen dos horas de solape, 20 tienen tres (las semanas de desfase del horario de verano, en marzo y a finales de octubre) y 2 tienen un valor negativo: son las medias sesiones de Madrid del 24 y el 31 de diciembre, en las que el mercado continuo cierra a las 14:00, hora y media antes de que abra la NYSE. Un sistema que asuma «siempre dos horas de solape» se equivoca en 22 sesiones al año.
Festivos, cierres extraordinarios y medias sesiones
Los festivos de cada bolsa no coinciden con los de su país ni con los de las demás bolsas, y cambian cada año: un festivo que cae en sábado puede trasladarse al viernes, o no. Además hay cierres que nadie preveía: la NYSE cerró el 9 de enero de 2025 por el día de luto nacional por el expresidente Carter, anunciado el 30 de diciembre2Nota 2 · Calendario de 2025: comunicado de NYSE Group «NYSE Group Announces 2025, 2026 and 2027 Holiday and Early Closings Calendar»; cierre del 9 de enero, comunicado de ICE del 30 de diciembre de 2024. Calendario de 2026: página «Holidays & Trading Hours» de la NYSE.. Y hay medias sesiones: en la NYSE, el 3 de julio, el viernes siguiente a Acción de Gracias y el 24 de diciembre suelen cerrar a las 13:00.
nyse = xcals.get_calendar("XNYS")
def cerrados(cal, desde, hasta):
laborables = pd.bdate_range(desde, hasta)
return laborables.difference(cal.sessions)
for anio in ("2025", "2026"):
dias = cerrados(nyse, f"{anio}-01-01", f"{anio}-12-31")
print(anio, len(dias), "días:", ", ".join(dias.strftime("%d/%m")))2025 11 días: 01/01, 09/01, 20/01, 17/02, 18/04, 26/05, 19/06, 04/07, 01/09, 27/11, 25/12
2026 10 días: 01/01, 19/01, 16/02, 03/04, 25/05, 19/06, 03/07, 07/09, 26/11, 25/12Comparado con lo que publica la NYSE, el calendario acierta. Para 2026 se puede comprobar contra la lista de su página de festivos, copiada a mano:
nyse_com = pd.to_datetime([
"2026-01-01", "2026-01-19", "2026-02-16", "2026-04-03",
"2026-05-25", "2026-06-19", "2026-07-03", "2026-09-07",
"2026-11-26", "2026-12-25"])
medias_nyse_com = pd.to_datetime(["2026-11-27", "2026-12-24"])
libreria = cerrados(nyse, "2026-01-01", "2026-12-31")
medias = nyse.early_closes[nyse.early_closes.year == 2026]
print("Festivos iguales:", libreria.equals(pd.DatetimeIndex(nyse_com)))
print("Medias sesiones iguales:", medias.equals(medias_nyse_com))
nyse.closes[medias].dt.tz_convert("America/New_York").dt.strftime(
"%Y-%m-%d %H:%M")Festivos iguales: True
Medias sesiones iguales: True
2026-11-27 2026-11-27 13:00
2026-12-24 2026-12-24 13:00
Name: close, dtype: strEn 2026 el 4 de julio cae en sábado y el festivo se traslada al viernes 3, así que ese año no hay media sesión el día antes de la fiesta. Es el tipo de detalle que un calendario hecho a mano se salta. El calendario tampoco es eterno: se actualiza con cada versión de la librería. Un cierre extraordinario como el del 9 de enero de 2025 solo aparece en las versiones publicadas después del anuncio, así que conviene fijar la versión en el proyecto (lección 0.2.2) y actualizarla a propósito.
Los cambios de horario también quedan registrados. La Bolsa de Tokio alargó su sesión de tarde media hora el 5 de noviembre de 2024, con una subasta de cierre nueva3Nota 3 · JPX, «Cash Market Trading Hours Extension Kicked Off Today», 5 de noviembre de 2024. El horario vigente, de 9:00 a 11:30 y de 12:30 a 15:30, está en la página «Trading Hours» de JPX.:
tks = xcals.get_calendar("XTKS")
for d in ("2024-11-01", "2024-11-05"):
cierre = tks.session_close(d).tz_convert("Asia/Tokyo")
print(d, "cierra a las", cierre.strftime("%H:%M"))2024-11-01 cierra a las 15:00
2024-11-05 cierra a las 15:30pandas_market_calendars ofrece lo mismo con otra interfaz: un schedule con una fila por sesión. Es cómodo para
generar rejillas de barras, y trae calendarios separados para cada grupo de futuros (CME_Equity, CME_Rate…),
donde exchange_calendars tiene uno genérico por bolsa (CMES):
import pandas_market_calendars as mcal
nyse_m = mcal.get_calendar("NYSE")
nyse_m.schedule("2025-11-26", "2025-12-01") market_open market_close
2025-11-26 2025-11-26 14:30:00+00:00 2025-11-26 21:00:00+00:00
2025-11-28 2025-11-28 14:30:00+00:00 2025-11-28 18:00:00+00:00
2025-12-01 2025-12-01 14:30:00+00:00 2025-12-01 21:00:00+00:00El jueves 27 no aparece y el viernes 28 cierra a las 18:00 UTC, las 13:00 de Nueva York. Las dos librerías deberían dar las mismas sesiones; comprobarlo es barato y detecta versiones desfasadas:
sched = nyse_m.schedule("2025-01-02", "2025-12-31")
x_cierres = nyse.closes["2025-01-02":"2025-12-31"]
print(len(sched), "sesiones en 2025")
print("Mismos cierres:", (sched["market_close"] == x_cierres).all())250 sesiones en 2025
Mismos cierres: TrueLa subasta de apertura, orden a orden
En la subasta no hay agresor ni libro que se recorra: hay una lista de órdenes y un único precio para todas. La regla general es maximizar el volumen ejecutable. Para cada precio candidato :
Las órdenes a mercado cuentan a cualquier precio: una compra a mercado está dispuesta a pagar lo que sea, y una venta a mercado, a vender a lo que sea. La demanda baja al subir el precio; la oferta sube. El precio de la subasta es el con mayor , y la diferencia a ese precio es el desequilibrio: órdenes que quedan sin ejecutar y pasan a la sesión continua. Si varios precios empatan en volumen, cada bolsa tiene sus reglas de desempate (menor desequilibrio, cercanía al precio de referencia…), publicadas en su reglamento.
El fichero nova_subasta_apertura.csv es el libro de la subasta de apertura de NOVA del 2 de junio de 2025 en el
instante del cruce:
import numpy as np
sub = pd.read_csv("nova_subasta_apertura.csv")
print(len(sub), "órdenes")
sub.groupby(["lado", "tipo"])["tamano"].agg(["size", "sum"])139 órdenes
size sum
lado tipo
compra limitada 63 27400
mercado 8 17000
venta limitada 61 30600
mercado 7 14600compra = sub[sub["lado"] == "compra"]
venta = sub[sub["lado"] == "venta"]
def demanda(p): # compras dispuestas a pagar p o más
ok = compra["tipo"].eq("mercado") | compra["precio_limite"].ge(p)
return compra.loc[ok, "tamano"].sum()
def oferta(p): # ventas dispuestas a vender a p o menos
ok = venta["tipo"].eq("mercado") | venta["precio_limite"].le(p)
return venta.loc[ok, "tamano"].sum()
curva = pd.DataFrame({"precio": np.sort(sub["precio_limite"].dropna()
.unique())})
curva["demanda"] = curva["precio"].map(demanda)
curva["oferta"] = curva["precio"].map(oferta)
curva["ejecutable"] = curva[["demanda", "oferta"]].min(axis=1)
curva["deseq"] = curva["demanda"] - curva["oferta"]
mejor = curva["ejecutable"].idxmax()
curva.loc[mejor - 3:mejor + 3] precio demanda oferta ejecutable deseq
19 53.32 35200 30200 30200 5000
20 53.33 34200 32200 32200 2000
21 53.34 34200 33200 33200 1000
22 53.35 33900 34500 33900 -600
23 53.36 31400 34500 31400 -3100
24 53.37 29900 35800 29900 -5900
25 53.38 29900 36800 29900 -6900Las dos curvas se cruzan entre 53,34 y 53,35. A 53,34 habría 34.200 acciones de demanda y 33.200 de oferta: se ejecutarían 33.200. A 53,35 la demanda baja a 33.900 y la oferta sube a 34.500: se ejecutan 33.900, el máximo. A 53,36 la demanda cae a 31.400. El precio de apertura es 53,35 USD, con 33.900 acciones y un desequilibrio de −600: sobran 600 acciones a la venta, que pasan al libro de la sesión continua. La comprobación final es contra la cinta:
op = pd.read_parquet("nova_operaciones.parquet")
apertura = op.iloc[0]
print(apertura[["ts", "precio", "tamano", "condicion"]].to_string())
print("Coincide:", apertura["precio"] == curva.loc[mejor, "precio"]
and apertura["tamano"] == curva.loc[mejor, "ejecutable"])ts 2025-06-02 13:30:00+00:00
precio 53.35
tamano 33900
condicion subasta_apertura
Coincide: TrueLa primera operación del día es exactamente la subasta reconstruida: mismo precio, mismo volumen, a las 13:30:00 UTC y sin agresor. Es también el precio de apertura que dará cualquier proveedor de datos diarios. La primera operación de la sesión continua, 0,3 segundos después, ya fue a 53,34 (lección 1.1.1).
El volumen en U y la subasta de cierre
El volumen no se reparte por igual a lo largo del día. Las barras de 5 minutos de NOVA de 2024 y 2025 permiten medir la forma típica: para cada sesión completa, qué porcentaje del volumen del día cae en cada tramo, y luego la media de todas las sesiones.
barras = pd.read_parquet("nova_barras_5min.parquet")
ny = barras["ts"].dt.tz_convert("America/New_York")
barras["sesion"] = ny.dt.date
barras["hora"] = ny.dt.strftime("%H:%M")
n_barras = barras.groupby("sesion")["ts"].size()
print(n_barras.value_counts().to_string())
normales = barras[barras["sesion"].map(n_barras) == 78].copy()
total = normales.groupby("sesion")["volumen"].transform("sum")
normales["cuota"] = 100 * normales["volumen"] / total
perfil = normales.groupby("hora")["cuota"].mean()
perfil.iloc[[0, 1, 2, 3, 38, 39, 74, 75, 76, 77]].round(2)ts
78 496
42 6
hora
09:30 3.06
09:35 2.43
09:40 2.08
09:45 1.79
12:40 1.04
12:45 1.04
15:40 1.40
15:45 1.56
15:50 1.82
15:55 11.28
Name: cuota, dtype: float64Hay 496 sesiones completas de 78 barras y 6 medias sesiones de 42 (de 9:30 a 13:00), que se dejan fuera para no mezclar perfiles. La primera barra, de 9:30 a 9:35, reúne de media el 3,06 % del volumen del día; a mediodía cada barra ronda el 1 %; en la última media hora el volumen vuelve a subir, y la última barra, la de las 15:55, salta al 11,28 % porque incluye la subasta de cierre. Es la «U» clásica de las acciones, con la pata derecha mucho más alta que la izquierda.
¿Por qué el cierre? Porque es el precio con el que se valoran los fondos. Un fondo indexado que tiene que comprar las acciones que entran en su índice, o que recibe suscripciones, busca ejecutar exactamente al precio de cierre: así replica el índice sin error. La forma de conseguirlo es enviar órdenes a la subasta de cierre (órdenes MOC). Lo mismo hacen muchas gestoras que se miden contra el cierre. La sesión del 2 de junio de 2025 lo muestra con una cifra:
vol_dia = op["tamano"].sum()
por_tipo = op.groupby("condicion")["tamano"].sum()
(100 * por_tipo / vol_dia).round(2)condicion
bloque 3.66
regular 86.00
subasta_apertura 0.38
subasta_cierre 9.96
Name: tamano, dtype: float64Casi el 10 % del volumen del día se cruza en un solo instante, en la subasta de cierre, y la de apertura apenas llega al 0,4 %. Para un sistema de trading esto tiene dos caras. A favor: si la estrategia opera al cierre, la subasta ofrece muchísima liquidez a un precio conocido de antemano por todos. En contra: el precio de la última operación continua (15:59:59) no es el cierre oficial, y un backtest que «compra al cierre» con la barra de las 15:55 debe decidir si participa en la subasta (y entonces enviar la orden antes de las 15:50 en la NYSE) o en la sesión continua previa.
Lo que esto cambia en tus datos
Fuente Mermaid
flowchart TB
D[Datos crudos UTC] --> C{¿Hay sesión?}
C -- no --> X[Descartar fila]
C -- sí --> H{¿Dentro de horas?}
H -- no --> E[Pre o poscierre]
H -- sí --> B[Barra de sesión]
B --> M{¿Media sesión?}
M -- sí --> Q[42 barras]
M -- no --> R[78 barras]- Fechas de barra diaria. La barra diaria de una sesión lleva su fecha local, que no siempre es la fecha UTC de sus barras. Tokio abre a las 00:00 UTC, justo en el cambio de día, y en los mercados que abren la tarde anterior (muchos futuros) las primeras barras de una sesión tienen fecha UTC del día previo. Agrupa por sesión del calendario, no por fecha UTC.
- Barras que faltan. Una media sesión tiene 42 barras de 5 minutos, no 78. Un
resamplea 5 minutos sin calendario rellena con vacíos las horas en que la bolsa estaba cerrada (o se las salta si eran festivos), y un indicador de «N barras» mezcla días. - Subastas dentro de las barras. Muchos proveedores meten la subasta de cierre en la última barra, como aquí. Un filtro de «volumen anómalo» la tomará por una señal cada día.
- Huecos de volatilidad. Unos minutos sin operaciones en mitad de la sesión pueden ser una subasta de volatilidad, no un fallo de datos (lección 1.4.2).
- Rendimientos entre sesiones. El rendimiento de un lunes incluye el fin de semana y, tras un festivo, dos o tres días. Para comparar días, cuenta sesiones con el calendario y no días naturales (lección 1.6.3).
Ejercicios
- Calcula las horas de solape entre Madrid y Nueva York el 12 de marzo y el 2 de junio de 2025 y explica la diferencia.
Solución
for d in ("2025-03-12", "2025-06-02"):
h = (mad.session_close(d) - nys.session_open(d)).total_seconds()
print(d, "NYSE abre", nys.session_open(d).strftime("%H:%M"),
"UTC; Madrid cierra", mad.session_close(d).strftime("%H:%M"),
f"UTC; solape {h / 3600:.0f} h")2025-03-12 NYSE abre 13:30 UTC; Madrid cierra 16:30 UTC; solape 3 h
2025-06-02 NYSE abre 13:30 UTC; Madrid cierra 15:30 UTC; solape 2 hEl 12 de marzo Estados Unidos ya está en horario de verano (desde el 9 de marzo) y Europa todavía no (hasta el 30 de marzo): Nueva York abre a las 13:30 UTC y Madrid cierra a las 16:30 UTC. Tres horas de solape. El 2 de junio los dos están en horario de verano y Madrid cierra una hora antes en UTC: dos horas.
- Llega a la subasta de apertura de NOVA una compra a mercado de 5.000 acciones. Recalcula el precio, el volumen ejecutable y el desequilibrio.
Solución
extra = pd.DataFrame([{"lado": "compra", "tipo": "mercado",
"precio_limite": np.nan, "tamano": 5000}])
compra = pd.concat([compra, extra], ignore_index=True)
curva["demanda"] = curva["precio"].map(demanda)
curva["ejecutable"] = curva[["demanda", "oferta"]].min(axis=1)
curva["deseq"] = curva["demanda"] - curva["oferta"]
curva.loc[curva["ejecutable"].idxmax()]precio 53.37
demanda 34900.00
oferta 35800.00
ejecutable 34900.00
deseq -900.00
Name: 24, dtype: float64La demanda sube 5.000 acciones a cualquier precio, así que el cruce se desplaza hacia arriba: hacen falta precios más altos para que aparezca oferta suficiente. El precio pasa a 53,37 USD, dos céntimos más, con 34.900 acciones ejecutables y un desequilibrio de −900. Es lo que ocurre cuando una noticia de la noche anterior llena la subasta de compras: la apertura salta por encima del cierre previo y queda un hueco en el gráfico.
- Explica por qué una estrategia que calcula su señal con el precio de cierre y «compra al cierre» del mismo día tiene un sesgo de anticipación, y propón dos formas de corregirlo con los datos de esta lección.
Solución
El precio de cierre es el de la subasta de cierre, que se cruza a las 16:00, y en la NYSE las órdenes MOC solo pueden
enviarse hasta las 15:50. La señal usa un dato que no existía cuando había que enviar la orden. Correcciones: calcular
la señal con la barra que termina a las 15:50 (las barras de 5 minutos de nova_barras_5min.parquet lo permiten) y
ejecutar en la subasta de cierre; o calcularla con el cierre y ejecutar en la subasta de apertura siguiente, cuyo
precio se reconstruye como en esta lección. La segunda paga el hueco de la noche; la primera, el riesgo de los últimos
diez minutos.
Footnotes
-
Horarios de la NYSE en su página «Holidays & Trading Hours» y en el folleto «NYSE opening and closing auctions»; los de BME, en la página «Horario Bolsa Española» de BME Exchange (consultadas el 21 de octubre de 2026). ↩
-
Calendario de 2025: comunicado de NYSE Group «NYSE Group Announces 2025, 2026 and 2027 Holiday and Early Closings Calendar»; cierre del 9 de enero, comunicado de ICE del 30 de diciembre de 2024. Calendario de 2026: página «Holidays & Trading Hours» de la NYSE. ↩
-
JPX, «Cash Market Trading Hours Extension Kicked Off Today», 5 de noviembre de 2024. El horario vigente, de 9:00 a 11:30 y de 12:30 a 15:30, está en la página «Trading Hours» de JPX. ↩
Respuesta plegada en cada pregunta
Autoevaluación
El 2 de junio de 2025, ¿cuántas horas coinciden abiertas la Bolsa de Madrid y la NYSE?
- ANinguna: Madrid cierra antes de que abra Nueva York
- BDos horas, de 13:30 a 15:30 UTC
- CSeis horas y media
- DDepende del bróker
Ver respuesta
Respuesta B. Dos horas, de 13:30 a 15:30 UTC
La NYSE abre a las 9:30 de Nueva York (13:30 UTC en horario de verano) y el mercado continuo de Madrid cierra a las 17:30 de Madrid (15:30 UTC). En 2025, las semanas en que Estados Unidos ya ha cambiado de hora y Europa no, el solape sube a tres horas.
En una subasta, ¿qué precio se elige?
- AEl precio de la última operación del día anterior
- BEl precio que maximiza el volumen que se puede ejecutar entre compras y ventas
- CEl punto medio entre la mejor compra y la mejor venta
- DEl precio de la orden más grande
Ver respuesta
Respuesta B. El precio que maximiza el volumen que se puede ejecutar entre compras y ventas
Para cada precio candidato se suman las compras dispuestas a pagar ese precio o más y las ventas dispuestas a vender a ese precio o menos. El volumen ejecutable es el menor de los dos; el precio de la subasta es el que lo maximiza. Si hay empate, cada bolsa aplica sus reglas de desempate.
¿Por qué no sirve
pd.bdate_rangepara generar las sesiones de la NYSE?- APorque no admite zonas horarias
- BPorque cuenta como hábiles los festivos y los cierres extraordinarios y no sabe nada de las medias sesiones
- CPorque empieza la semana en domingo
- DSí sirve: da las mismas fechas
Ver respuesta
Respuesta B. Porque cuenta como hábiles los festivos y los cierres extraordinarios y no sabe nada de las medias sesiones
bdate_rangesolo quita sábados y domingos. En 2025 la NYSE cerró once días laborables (diez festivos y el cierre extraordinario del 9 de enero) y tuvo tres medias sesiones que terminan a las 13:00. Un calendario de bolsa los incluye.¿Por qué la última barra de 5 minutos de la sesión de NOVA tiene unas diez veces más volumen que las del mediodía?
- APorque los creadores de mercado se retiran antes del cierre
- BPorque incluye la subasta de cierre, donde ejecutan los fondos indexados y muchas gestoras que se valoran al precio de cierre
- CPorque es un error del proveedor de datos
- DPorque a esa hora abre Europa
Ver respuesta
Respuesta B. Porque incluye la subasta de cierre, donde ejecutan los fondos indexados y muchas gestoras que se valoran al precio de cierre
Un fondo que replica un índice se valora al cierre, así que quiere comprar y vender a ese precio exacto. Lo consigue enviando órdenes a la subasta de cierre. En NOVA, el 2 de junio de 2025, la subasta de cierre cruzó 885.500 acciones, el 10 % del volumen del día, en un único precio.
La Bolsa de Tokio cerraba a las 15:00 y desde el 5 de noviembre de 2024 cierra a las 15:30. ¿Qué pasa si un backtest usa la hora nueva para toda la historia?
- ANada: la hora de cierre no influye
- BTrata como cierre de sesión precios de media hora antes en los datos antiguos, o busca barras que no existían
- CSolo afecta a los futuros
- DLos datos se ajustan solos
Ver respuesta
Respuesta B. Trata como cierre de sesión precios de media hora antes en los datos antiguos, o busca barras que no existían
Un calendario de bolsa guarda la historia de los horarios.
exchange_calendarsda 15:00 para el 1 de noviembre de 2024 y 15:30 para el 5. Con un horario fijo, las señales «al cierre» de los datos antiguos se calcularían a una hora en la que el mercado ya estaba cerrado.
Ideas clave
- Una sesión tiene fases: preapertura con subasta, negociación continua, subastas de volatilidad cuando el precio se mueve demasiado y subasta de cierre. Cada una genera datos distintos.
- Las horas de los mercados se guardan en UTC y se calculan con un calendario de bolsa: la zona horaria, el horario de verano, las pausas de mediodía y los cambios de horario hacen inútil una hora fija.
- Los festivos, los cierres extraordinarios y las medias sesiones cambian de un año a otro.
exchange_calendarsypandas_market_calendarslos traen;pd.bdate_rangeno. - El precio de una subasta es el que maximiza el volumen ejecutable. En NOVA, 53,35 USD con 33.900 acciones, idéntico a la primera operación del día.
- El volumen intradía tiene forma de U, y la subasta de cierre es la operación más grande del día porque fija el precio con el que se valoran los fondos.
Recursos
Documentación
- NYSE: Holidays & Trading Hours (sesiones, subastas, festivos y medias sesiones)
- NYSE: Opening and Closing Auctions (fact sheet; MOC/LOC hasta las 15:50)
- BME Exchange: horario del mercado (SIBE, subastas y Trading At Last)
- JPX: Cash Market Trading Hours Extension Kicked Off Today (5 de noviembre de 2024)
- exchange_calendars (repositorio y documentación)
- pandas_market_calendars: documentación