Lección 3.2.1 · 65 min

Spreads de calendario, butterflies y condors

Comprar un mes de un futuro y vender otro del mismo mercado elimina casi toda la exposición a la dirección del precio y deja otra: la forma de la curva. Esta lección construye calendarios, butterflies y condors con los contratos de cada sesión, mide cuánto riesgo queda en los mercados sintéticos del curso y por qué el margen baja en la misma proporción.

Fig. — Riesgo diario de una posición simple, un spread de calendario, una butterfly y un condor en seis mercados, 2025
Lecciones del nivel 3
  1. 3.1 · Futuros en profundidad

    1. 3.1.1 Contratos de futuros principales
    2. 3.1.2 Curva de futuros: base, cost of carry, contango y roll yield
    3. 3.1.3 Gestión del roll, márgenes, SPAN y apalancamiento implícito
    4. 3.1.4 Sistemas de futuros diversificados: el enfoque de Carver
  2. 3.2 · Spreads de futuros

    1. 3.2.1 Spreads de calendario, butterflies y condors
    2. 3.2.2 Spreads intercommodity: crack, spark y crush
    3. 3.2.3 Spreads de tipos y de índices: 2s10s, NOB, NQ/ES y Europa frente a EE. UU.
    4. 3.2.4 Ratios de cobertura: por nominal, por DV01 y por volatilidad
    5. 3.2.5 Datos y backtesting de spreads: cotizados, sintéticos y por patas
    6. 3.2.6 Estacionalidad de spreads: análisis multi-año, patrones y trampas
  3. 3.3 · Forex avanzado

    1. 3.3.1 Microestructura FX: OTC, ECN, last look y sesiones
    2. 3.3.2 Carry y riesgo de crash, momentum y value en divisas; cestas
    3. 3.3.3 Riesgo de divisa en carteras multi-moneda; ejecución vía OANDA, IBKR o MT5
  4. 3.4 · Teoría y valoración de opciones

    1. 3.4.1 Payoffs, paridad put-call y límites de arbitraje
    2. 3.4.2 Árboles binomiales, Black-Scholes-Merton, Black-76 y Monte Carlo
    3. 3.4.3 Griegas: delta, gamma, vega, theta, rho, vanna, volga y charm
    4. 3.4.4 Volatilidad implícita: Newton-Raphson, Brent, py_vollib y QuantLib
    5. 3.4.5 Sonrisa, skew y estructura temporal; superficie de volatilidad con SVI
    6. 3.4.6 Volatilidad realizada frente a implícita; prima de riesgo de volatilidad; VIX y VSTOXX
    7. 3.4.7 Modelos avanzados: Heston, SABR y volatilidad local
  5. 3.5 · Estructuras de opciones en Python

    1. 3.5.1 Estructuras direccionales y verticales: call, put, covered call, collar y spreads
    2. 3.5.2 Estructuras de volatilidad y rango: straddles, strangles, cóndores y mariposas
    3. 3.5.3 Calendarios, diagonales, ratios, backspreads, risk reversals y jade lizard
    4. 3.5.4 Herramienta propia: payoff, griegas agregadas y escenarios
    5. 3.5.5 Gestión: ajustes, roll, cierre anticipado, asignación temprana y pin risk
  6. 3.6 · Estrategias sistemáticas de volatilidad y opciones

    1. 3.6.1 Venta sistemática de prima: put-write, strangles y su riesgo de cola
    2. 3.6.2 Delta hedging, gamma scalping y dispersión
    3. 3.6.3 Estrategias con VIX y VSTOXX: futuros y ETP de volatilidad
    4. 3.6.4 Backtesting de opciones: datos, fills y ajustes por eventos
  7. 3.7 · Cripto derivados y estrategias específicas

    1. 3.7.1 Perpetuos: mecánica del funding, mark price y liquidaciones
    2. 3.7.2 Arbitraje de funding, basis con futuros y arbitraje entre exchanges
    3. 3.7.3 Opciones cripto, datos on-chain y DeFi
    4. 3.7.4 ccxt para operar en varios exchanges
    5. 3.7.5 MiCA: el marco de la UE para criptoactivos y sus proveedores (CASP)

Un spread compra un mes y vende otro

Un futuro de crudo no es un contrato: son dieciocho, uno por mes de entrega, todos vivos a la vez (lección 1.2.3). Comprar uno y vender otro del mismo mercado es un spread de calendario (también intra-commodity spread). Los dos contratos responden casi igual a lo que mueve el precio del crudo, así que la dirección se cancela en buena parte. Lo que queda es la diferencia entre ellos: la pendiente de la curva entre esos dos meses, que depende del coste de mantener el subyacente, del almacenamiento y de la escasez del momento (lección 3.1.2).

Las curvas de esta lección son las del nivel 3 (futuros3_curvas.parquet): 23 mercados ficticios que imitan a contratos reales, con la liquidación de todos los contratos listados en cada sesión de 2010 a 2025. Son datos sintéticos: los niveles se parecen a la historia, pero no son datos de mercado.

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

cur = pd.read_parquet("futuros3_curvas.parquet")
ctr = pd.read_csv("futuros3_contratos.csv",
                  parse_dates=["vencimiento", "fecha_roll"])
esp = pd.read_csv("futuros3_especificaciones.csv",
                  index_col="mercado")
dia = cur[(cur["mercado"] == "PEC")
          & (cur["fecha"] == "2025-06-04")].merge(
    ctr[["contrato", "vencimiento"]]).sort_values("vencimiento")
print(len(dia), "contratos de PEC listados el 2025-06-04")
dia[["contrato", "vencimiento", "liquidacion", "volumen"]].head(4)
OUT [01]La curva del crudo en una sesión
18 contratos de PEC listados el 2025-06-04
   contrato vencimiento  liquidacion  volumen
6    PECN25  2025-06-20        53.35   256676
8    PECQ25  2025-07-22        53.23   288298
10   PECU25  2025-08-20        53.23    93695
12   PECV25  2025-09-22        53.32    34244

PEC imita al WTI de NYMEX (1.000 barriles por contrato). El contrato de julio (PECN25) vence el 20 de junio, pero ya tiene menos volumen que el de agosto: la liquidez se ha ido al siguiente antes del vencimiento, que es lo que marca la columna fecha_roll de futuros3_contratos.csv. Para construir estructuras conviene numerar las patas desde el contrato que se tiene, el primero que aún no ha llegado a su fecha de roll:

IN [02]python
def patas(mercado, n=4):
    """Contratos 1.º, 2.º… de cada sesión. El 1.º es el que se
    tiene: el primero que aún no ha llegado a su fecha_roll."""
    c = cur[cur["mercado"] == mercado].merge(
        ctr[["contrato", "vencimiento", "fecha_roll"]],
        on="contrato")
    c = c[c["fecha"] < c["fecha_roll"]]
    c = c.sort_values(["fecha", "vencimiento"])
    c["k"] = c.groupby("fecha").cumcount() + 1
    return c[c["k"] <= n]

pec = patas("PEC")
pec.loc[pec["fecha"] == "2025-06-04",
        ["k", "contrato", "liquidacion"]]
OUT [02]Las patas por orden de vencimiento
       k contrato  liquidacion
68564  1   PECN25        53.35
68566  2   PECQ25        53.23
68568  3   PECU25        53.23
68570  4   PECV25        53.32

Con las patas numeradas, cada estructura es un vector de pesos sobre ellas. El calendario es la diferencia de dos patas; la butterfly, la diferencia de dos calendarios consecutivos que comparten la pata central; el condor, la diferencia de dos calendarios que no la comparten:

Simple +1Calendario +1 −1Butterfly +1 −2 +1Condor +1 −1 −1 +1
Fuente Mermaid
flowchart LR
  S[Simple +1] --> C[Calendario +1 −1]
  C --> B[Butterfly +1 −2 +1]
  C --> K[Condor +1 −1 −1 +1]
EstructuraPesos (1.º, 2.º, 3.º, 4.º)PrecioQué neutralizaQué apuesta
Simple+1F1F_1nadadirección
Calendario+1, −1F1−F2F_1 - F_2casi toda la direcciónpendiente entre dos meses
Butterfly+1, −2, +1F1−2F2+F3F_1 - 2F_2 + F_3dirección y pendientecurvatura alrededor del 2.º
Condor+1, −1, −1, +1(F1−F2)−(F3−F4)(F_1 - F_2) - (F_3 - F_4)dirección y casi toda la pendientecurvatura en un tramo más ancho

Comprar el calendario 1.º − 2.º (largo en el cercano, corto en el siguiente) gana si el cercano sube más que el siguiente: si la curva se empina en backwardation o se aplana en contango. Comprar la butterfly gana si el mes central baja respecto a la media de sus vecinos.

La serie de niveles y el P&L con los mismos contratos

La serie más fácil de construir es la del nivel del spread: en cada sesión, la liquidación del 1.º menos la del 2.º.

IN [03]python
niv = pec.pivot(index="fecha", columns="k", values="liquidacion")
cal = niv[1] - niv[2]                    # USD por barril
print(cal.describe().round(2).to_string())
print(f"Sesiones en backwardation (1.º > 2.º): {(cal > 0).mean():.1%}")
OUT [03]El spread 1.º − 2.º del crudo
count    4024.00
mean        0.15
std         1.64
min        -3.54
25%        -1.04
50%         0.14
75%         1.15
max         4.94
Sesiones en backwardation (1.º > 2.º): 53.5%

El spread del crudo sintético va de −3,54 USD por barril (contango profundo) a +4,94 (backwardation) y pasa algo más de la mitad de las sesiones en backwardation. Esa serie sirve para describir la curva, pero no es el P&L de nadie. El día del roll, «1.º» y «2.º» pasan a ser otros contratos y la serie salta sin que ninguna posición haya ganado ni perdido ese salto, el mismo problema de las series continuas de la lección 1.4.6:

IN [04]python
rolls = ctr.loc[ctr["mercado"] == "PEC", "fecha_roll"]
salto = cal.diff()
en_roll = salto.index.isin(rolls)
print(f"Cambio medio absoluto en día de roll: "
      f"{salto[en_roll].abs().mean():.3f} USD/barril")
print(f"Resto de sesiones:                  "
      f"{salto[~en_roll].abs().mean():.3f} USD/barril")
OUT [04]El salto del roll en la serie de niveles
Cambio medio absoluto en día de roll: 0.270 USD/barril
Resto de sesiones:                  0.156 USD/barril

En el día de roll la serie cambia de media un 70 % más que el resto de días, y ese cambio es un artefacto. El P&L correcto se calcula con los contratos que tenía la posición al cierre anterior: los pesos se fijan con las patas de la sesión t−1t-1 y se aplican a los cambios de esos mismos contratos entre t−1t-1 y tt. Con MM el multiplicador:

PyGt=M∑kwk(Fk,t−Fk,t−1),k fijado en t−1.\text{PyG}_t = M \sum_k w_k \left(F_{k,t} - F_{k,t-1}\right), \qquad k \text{ fijado en } t-1 .
IN [05]python
def cambios(mercado, n, log=False):
    """Cambio diario de cada pata k = 1..n con los contratos que
    tenía la estructura al cierre anterior (sin saltos de roll)."""
    p = patas(mercado, n)
    px = cur[cur["mercado"] == mercado].pivot(
        index="fecha", columns="contrato", values="liquidacion")
    d = (np.log(px) if log else px).diff().stack()
    ley = p.pivot(index="fecha", columns="k",
                  values="contrato").shift(1).dropna()
    out = {k: d.reindex(pd.MultiIndex.from_arrays(
        [ley.index, ley[k]])).to_numpy() for k in ley.columns}
    return pd.DataFrame(out, index=ley.index)

def pyg(mercado, pesos):
    """P&L diario en la divisa del contrato, por estructura."""
    c = cambios(mercado, len(pesos))
    mult = esp.loc[mercado, "multiplicador"]
    return (c @ np.array(pesos) * mult).dropna()

ESTRUCTURAS = {"simple": [1], "calendario": [1, -1],
               "butterfly": [1, -2, 1], "condor": [1, -1, -1, 1]}
vol = pd.DataFrame({m: {n: pyg(m, w).loc["2025"].std()
                        for n, w in ESTRUCTURAS.items()}
                    for m in ["RVA", "MTO", "PEC", "PEG",
                              "GRM", "GNA"]}).T
vol.round(0)
OUT [05]P&L con los mismos contratos
     simple  calendario  butterfly  condor
RVA  3957.0        41.0       25.0    24.0
MTO  1622.0        15.0       10.0     8.0
PEC  1258.0       149.0       29.0    46.0
PEG  1816.0       321.0      100.0   159.0
GRM   302.0        53.0       28.0    35.0
GNA  1695.0       637.0      639.0   596.0

La tabla es la figura de la cabecera: desviación típica del P&L diario por contrato en 2025, en USD. En el índice RVA (imita al E-mini S&P 500), el calendario se mueve una centésima parte de lo que se mueve el futuro; en el oro, todavía menos. En el crudo, el calendario conserva un 12 % del riesgo y la butterfly un 2,3 %. En el maíz y la gasolina, el calendario conserva cerca del 18 %. El gas es la excepción que esta lección explica más abajo: su butterfly (639 USD) se mueve tanto como su calendario (637).

Qué queda de la dirección

Un calendario no es neutral a la dirección por construcción. Si los dos contratos se movieran lo mismo, su diferencia no tendría riesgo; no lo hacen. En las materias primas, el cercano reacciona más a los choques que se espera que reviertan (el efecto Samuelson, medido en la lección 3.1.2), así que largo en el 1.º y corto en el 2.º conserva un pequeño largo:

IN [06]python
for m in ["RVA", "PEC", "GRM", "GNA"]:
    d = pd.concat([pyg(m, [1]), pyg(m, [1, -1])], axis=1,
                  keys=["simple", "cal"]).dropna()
    beta = d.cov().loc["cal", "simple"] / d["simple"].var()
    print(f"{m}: beta {beta:+.3f}  correlación "
          f"{d.corr().loc['cal', 'simple']:+.2f}")
OUT [06]Cuánto de dirección queda en el calendario
RVA: beta -0.003  correlación -0.20
PEC: beta +0.106  correlación +0.92
GRM: beta +0.238  correlación +0.89
GNA: beta +0.228  correlación +0.74

En el crudo, por cada 1.000 USD que gana la pata cercana, el calendario gana 106. Es poco en tamaño, pero la correlación de 0,92 dice que el calendario de crudo es, sobre todo, una versión reducida de la posición simple. En el maíz y en el gas la beta es mayor (0,24 y 0,23). Quien opera un calendario como si fuera «neutral» y lo combina con una posición simple en el mismo mercado está sumando exposición, no cubriéndola. Las coberturas que corrigen esta beta (por nominal, por DV01, por volatilidad) son el tema de la lección 3.2.4.

En el índice la beta es casi cero, por otra razón: el calendario de un índice no depende de choques que revierten, sino de la financiación. Un futuro de índice vale el contado capitalizado al tipo menos los dividendos (lección 3.1.2), así que la diferencia entre dos vencimientos es, casi exactamente, la financiación neta del tramo que los separa:

F2−F1≈S (r−q) (τ2−τ1).F_2 - F_1 \approx S \, (r - q) \, (\tau_2 - \tau_1).
IN [07]python
idx = pd.read_csv("futuros3_indices_contado.csv",
                  parse_dates=["fecha"])
s = idx[idx["indice"] == "RVA"].set_index("fecha")
rva = patas("RVA", 2)
f = rva.pivot(index="fecha", columns="k", values="liquidacion")
v = rva.pivot(index="fecha", columns="k", values="vencimiento")
dias = v.sub(v.index.to_series(), axis=0).apply(
    lambda c: c.dt.days)
carry = (s["tipo_1m"] - s["rentabilidad_dividendo"]) / 100
teo = s["contado"].to_numpy()[:, None] * np.exp(
    carry.to_numpy()[:, None] * dias / 365)
eq = pd.DataFrame({"real": f[2] - f[1],          # 2.º − 1.º
                   "teorico": teo[2] - teo[1]}).dropna()
print(f"Correlación: {eq.corr().iloc[0, 1]:.4f}; diferencia "
      f"mediana {(eq['real'] - eq['teorico']).abs().median():.2f}"
      " puntos")
eq.resample("YE").mean().round(1).loc["2019":]
OUT [07]El calendario de un índice es financiación
Correlación: 0.9997; diferencia mediana 0.14 puntos
            real  teorico
fecha
2019-12-31   2.9      3.0
2020-12-31  -7.9     -7.9
2021-12-31 -11.7    -11.7
2022-12-31   2.0      1.8
2023-12-31  30.1     30.1
2024-12-31  41.4     41.6
2025-12-31  39.1     38.9

La fórmula de financiación explica el calendario del índice con una correlación de 0,9997 y un error mediano de 0,14 puntos, menos que su tick (0,25). Con tipos por debajo de la rentabilidad por dividendo (2020 y 2021), el contrato lejano cotiza por debajo del cercano; con tipos del 4-5 % (2023-2025), unos 40 puntos por encima. Para quien mantiene el futuro y lo rueda cada trimestre, ese spread es el precio del roll (lección 3.1.3). Para quien lo opera, es una apuesta sobre los tipos a corto y los dividendos, no sobre la bolsa.

CalendarioÍndice: r − qBono: cupón y repoAlmacenable: stockGas: estación
Fuente Mermaid
flowchart TB
  C[Calendario] --> I["Índice: r − q"]
  C --> B["Bono: cupón y repo"]
  C --> A[Almacenable: stock]
  C --> E[Gas: estación]

Lo que mueve un calendario depende del mercado: la financiación neta en índices y divisas; el cupón, la financiación y el bono más barato de entregar en los bonos; el almacenamiento y la escasez en crudo, metales y granos; y, en el gas y la electricidad, el salto entre estaciones.

Márgenes reducidos

Una cámara de compensación no pide margen por pata, sino por el riesgo de la cartera (el SPAN de la lección 3.1.3). Si un calendario se mueve un 12 % de lo que se mueve la posición simple, su margen puede ser, aproximadamente, un 12 % del de la posición simple. En los datos, margen_spread_calendario se fijó así: el mismo número de desviaciones diarias que cubre el margen simple, aplicado a la desviación típica del spread. El cálculo con los 23 mercados:

IN [08]python
base = esp[esp["mercado_base"].isna()].index
filas = {}
for m in base:
    s1 = pyg(m, [1]).loc["2025"].std()
    s2 = pyg(m, [1, -1]).loc["2025"].std()
    filas[m] = {"riesgo": s2 / s1,
                "margen": esp.loc[m, "margen_spread_calendario"]
                / esp.loc[m, "margen_inicial"]}
rel = pd.DataFrame(filas).T.sort_values("riesgo")
print(rel.round(3).T.to_string())
OUT [08]Margen del spread frente a margen simple
          RVH    MTO    RVC   RVB   RVA    RVE    MTP    DQE    TPD    TPE    TPC    TPB    PEC    TPA    PEH    GRM    PEG    GRT    GRS    GRA    GRH    GNA    ELB
riesgo  0.004  0.009  0.009  0.01  0.01  0.012  0.013  0.022  0.033  0.045  0.053  0.073  0.118  0.136  0.146  0.175  0.177  0.181  0.185  0.192  0.199  0.376  0.389
margen  0.030  0.030  0.030  0.03  0.03  0.029  0.030  0.029  0.033  0.043  0.052  0.072  0.120  0.140  0.147  0.179  0.174  0.186  0.178  0.188  0.195  0.388  0.438
Fig. — Margen del spread de calendario frente a su riesgo, en proporción a la posición simple, en los 23 mercados

Desde los bonos hasta la electricidad, las dos filas casi coinciden: el margen del calendario es proporcional a su riesgo, del 3,3 % del margen simple en el bono a 30 años (TPD) al 44 % en la electricidad (ELB). Los índices, el oro, la plata y la divisa se quedan en el 3 %, aunque su riesgo relativo esté entre el 0,4 y el 2,2 %: el generador de los datos aplica un suelo del 3 % del margen simple. Las cámaras reales también aplican mínimos y recargos a los spreads (por ejemplo, entre vencimientos que cruzan un periodo de entrega) y los publican con sus parámetros de margen.

Un margen reducido es, ante todo, apalancamiento:

IN [09]python
m = esp.loc["PEC"]
precio = niv[1].loc["2025"].median()
print(f"Nominal de una pata: {10 * precio * m['multiplicador']:,.0f}"
      " USD")
print(f"Margen de 10 largos y 10 cortos sueltos: "
      f"{20 * m['margen_inicial']:,.0f} USD")
print(f"Margen de 10 spreads de calendario: "
      f"{10 * m['margen_spread_calendario']:,.0f} USD")
OUT [09]Diez spreads frente a diez posiciones simples
Nominal de una pata: 618,500 USD
Margen de 10 largos y 10 cortos sueltos: 112,000 USD
Margen de 10 spreads de calendario: 6,700 USD

Con 6.700 USD de margen se controlan 618.500 USD de nominal en cada pata, más de 1,2 millones entre las dos. La cifra de nominal no dice nada del riesgo, que es el del spread; pero el margen tampoco dice cuánto se puede perder.

Butterflies y condors: la curvatura

Si el calendario deja la pendiente, la butterfly intenta quitarla también. Para ver qué queda hace falta saber cómo se mueve la curva entera, y para eso sirve un análisis de componentes principales (PCA): los autovectores de la matriz de covarianza de los cambios diarios de los doce primeros contratos. En curvas de tipos y de materias primas, los tres primeros suelen leerse como nivel (toda la curva a la vez), pendiente (el corto contra el largo) y curvatura (el centro contra los extremos). En el gas:

IN [10]python
r = cambios("GNA", 12, log=True).dropna()
val, vec = np.linalg.eigh(np.cov(r.T))
val, vec = val[::-1], vec[:, ::-1]
vec = vec * np.sign(vec[0])           # carga positiva en la 1.ª
print("Varianza explicada:", (val[:4] / val.sum()).round(3))
cargas = pd.DataFrame(vec[:, :3], index=r.columns,
                      columns=["nivel", "pendiente", "curvatura"])
cargas.T.round(2)
OUT [10]Nivel, pendiente y curvatura del gas
Varianza explicada: [0.841 0.118 0.022 0.008]
             1     2     3     4     5     6     7     8     9     10    11    12
nivel      0.50  0.42  0.36  0.31  0.27  0.24  0.22  0.20  0.19  0.18  0.17  0.17
pendiente  0.55  0.31  0.11 -0.04 -0.16 -0.24 -0.29 -0.31 -0.31 -0.29 -0.27 -0.25
curvatura  0.38  0.02 -0.28 -0.41 -0.40 -0.30 -0.09  0.10  0.25  0.33  0.32  0.27
Fig. — Los tres primeros componentes principales de los cambios diarios de la curva del gas, 2010–2025

El nivel explica el 84,1 % de la varianza y carga más en los contratos cercanos (otra vez el efecto Samuelson: de 0,50 en el primero a 0,17 en el duodécimo). La pendiente (11,8 %) separa los cuatro primeros del resto. La curvatura (2,2 %) es positiva en los extremos y negativa en el centro. La exposición de cada estructura a cada factor es el producto de sus pesos por las cargas, y el reparto de su varianza entre los tres factores, esa exposición al cuadrado por la varianza de cada uno:

IN [11]python
pesos = pd.DataFrame({n: (w + [0] * 12)[:12]
                      for n, w in ESTRUCTURAS.items()},
                     index=cargas.index)
expo = pesos.T @ cargas
print(expo.round(2))
reparto = expo ** 2 * val[:3]
(100 * reparto.div(reparto.sum(axis=1), axis=0)).round(0)
OUT [11]A qué factor se expone cada estructura
            nivel  pendiente  curvatura
simple       0.50       0.55       0.38
calendario   0.08       0.24       0.35
butterfly    0.02       0.04       0.05
condor       0.03       0.09       0.23
            nivel  pendiente  curvatura
simple       84.0       14.0        1.0
calendario   37.0       45.0       19.0
butterfly    58.0       33.0        9.0
condor       31.0       29.0       40.0

El calendario reduce la exposición al nivel de 0,50 a 0,08, y su varianza dentro de estos tres factores se reparte entre nivel (37 %), pendiente (45 %) y curvatura (19 %): es sobre todo una apuesta de pendiente con algo de nivel, la beta de la sección anterior. La butterfly casi no se expone a ninguno de los tres (0,02, 0,04 y 0,05): sus pesos +1 −2 +1 son casi ortogonales a las tres cargas, y el reparto de su poca exposición importa poco. El condor queda expuesto sobre todo a la curvatura (0,23). Según este PCA, la butterfly del gas debería tener muy poco riesgo; la tabla del principio dice que en 2025 se movió 639 USD al día, tanto como el calendario. Lo que falta no está en estos tres factores.

Pero el PCA por orden de vencimiento promedia contratos de meses distintos: el 3.º es octubre en julio y marzo en diciembre. En un mercado con estaciones, lo que importa es qué meses de entrega cruza la estructura. El gas tiene un factor de invierno (en el modelo de los datos, carga +0,5 de noviembre a marzo y −0,5 de abril a octubre), y una butterfly cuyas alas caen a los dos lados de ese salto no lo neutraliza:

IN [12]python
g = cur[cur["mercado"] == "GNA"]
mes = g["contrato"].str[3].map("FGHJKMNQUVXZ".index)
n = (g["contrato"].str[4:].astype(int) + 2000) * 12 + mes
px = g.assign(n=n).pivot(index="fecha", columns="n",
                         values="liquidacion")
d = px.diff() * esp.loc["GNA", "multiplicador"]
hoy = px.index.year * 12 + px.index.month - 1
por_mes = {}
for c in px.columns[1:-1]:
    fly = d[c - 1] - 2 * d[c] + d[c + 1]
    ok = (c - hoy >= 3) & (c - hoy <= 9) & (px.index.year >= 2016)
    por_mes.setdefault("FGHJKMNQUVXZ"[c % 12], []).append(fly[ok])
riesgo = pd.Series({k: pd.concat(v).std()
                    for k, v in por_mes.items()})
riesgo.reindex(list("FGHJKMNQUVXZ")).round(0).to_frame("usd_dia").T
OUT [12]Butterflies del gas según los meses que cruzan
            F     G      H      J     K     M     N     Q     U      V      X     Z
usd_dia  54.0  55.0  391.0  489.0  45.0  31.0  43.0  44.0  71.0  422.0  511.0  35.0
Fig. — Riesgo diario de una butterfly de gas de meses consecutivos según el mes de su pata central, 2016–2025

Cada columna es una butterfly de tres meses de entrega seguidos, identificada por su mes central (código de mes de futuros: F enero, G febrero… Z diciembre), cuando le quedan de 3 a 9 meses. Ocho de las doce se mueven entre 31 y 71 USD al día. Las cuatro que cruzan un cambio de estación —centradas en marzo y abril (febrero-marzo-abril y marzo-abril-mayo) y en octubre y noviembre— se mueven entre 391 y 511: siete u ocho veces más. Son las estructuras que convierten una butterfly de gas en una apuesta sobre el invierno, y las que más sorprenden a quien la trata como «casi sin riesgo».

Spreads listados y convenciones de signo

Los calendarios, butterflies y condors no solo se construyen por patas: las bolsas los listan como instrumentos con su propio libro de órdenes. Una orden sobre el spread se ejecuta entera o no se ejecuta, sin el riesgo de quedarse con una pata sola. En los datos, spreads3_cotizados.parquet tiene el libro al cierre del calendario 1.º − 2.º de seis mercados:

IN [13]python
cot = pd.read_parquet("spreads3_cotizados.parquet")
fila = cot[(cot["mercado"] == "PEC")
           & (cot["fecha"] == "2025-06-04")].iloc[0]
print(fila[["spread", "liquidacion", "bid", "ask"]].to_string())
leg = niv.loc["2025-06-04"]
print(f"1.º − 2.º con las liquidaciones: {leg[1] - leg[2]:.2f}")
OUT [13]El libro de un spread cotizado
spread         PECN25-PECQ25
liquidacion             0.12
bid                     0.12
ask                     0.13
1.º − 2.º con las liquidaciones: 0.12

El spread PECN25-PECQ25 liquida a 0,12 USD por barril, la diferencia de las liquidaciones de las patas, y su libro cotiza a un tick (0,12 a 0,13). Comparar ese libro con el spread «sintético» que se obtiene cruzando las horquillas de las dos patas, y lo que cuesta ejecutar una pata y esperar a la otra (legging risk), es el tema de la lección 3.2.5.

Antes de enviar una orden sobre un spread listado hay que leer su convención de signo, porque no es la misma en todos los productos. La documentación de CME Globex define, entre otros:

Tipo de GlobexEjemploComprar el spreadPrecio
SP, calendario estándarNGZ9-NGF0compra la pata 1 (cercana), vende la 2pata 1 − pata 2
EQ, calendario de índices bursátilesESU9-ESZ9vende la pata 1 (cercana), compra la 2pata 2 − pata 1
BF, butterflySR1:BF M9-U9-Z9compra la 1, vende 2 de la 2, compra la 3pata 1 − 2 × pata 2 + pata 3
CF, condorSR1:CF M9U9Z9H0compra la 1, vende la 2 y la 3, compra la 4pata 1 − pata 2 − pata 3 + pata 4

Lo que esto cambia en un sistema

  • El P&L, con los mismos contratos. Una serie de niveles 1.º − 2.º sirve para describir la curva; para un backtest hay que fijar los contratos de cada día y rodar la estructura entera en una fecha decidida de antemano.
  • Neutral no es sin riesgo. El calendario de crudo conserva una beta de 0,11 y una correlación de 0,92 con la posición simple; la butterfly del gas que cruza una estación se mueve como un calendario.
  • El margen pequeño es apalancamiento. El tamaño de una posición en spreads se decide por su riesgo medido (y por su peor día), no por lo que deja abrir el margen.
  • Cada mercado tiene su motor. En índices, el calendario es financiación; en materias primas, almacenamiento y estaciones. Una regla que funciona en uno no tiene por qué funcionar en otro.
  • El signo, antes que nada. Cercano menos lejano o lejano menos cercano: depende de la bolsa, del producto y del proveedor de datos.

Ejercicios

  1. Comprueba que un condor de gas es exactamente la diferencia de dos calendarios (1.º − 2.º y 3.º − 4.º) y mide en 2025 el riesgo de cada uno y su correlación. ¿Por qué el condor (596 USD) no tiene menos riesgo que el calendario 1.º − 2.º (637)?
Solución
IN [14]python
c = cambios("GNA", 4) * esp.loc["GNA", "multiplicador"]
condor = c[1] - c[2] - c[3] + c[4]
dos_cal = (c[1] - c[2]) - (c[3] - c[4])
print("Idénticos:", np.allclose(condor.dropna(), dos_cal.dropna()))
d = pd.DataFrame({"cal_1_2": c[1] - c[2], "cal_3_4": c[3] - c[4]})
print(d.loc["2025"].std().round(0).to_string())
print(f"Correlación: {d.loc['2025'].corr().iloc[0, 1]:.2f}")
OUT [14]El condor, diferencia de dos calendarios
Idénticos: True
cal_1_2    637.0
cal_3_4    332.0
Correlación: 0.38

El condor es la diferencia de los dos calendarios. Restar dos posiciones reduce el riesgo solo si están muy correladas: con una correlación de 0,38 y riesgos de 637 y 332 USD, la varianza del condor es 6372+3322−2⋅0,38⋅637⋅332637^2 + 332^2 - 2 \cdot 0{,}38 \cdot 637 \cdot 332 y su desviación típica, unos 596 USD. En el gas, el calendario cercano y el lejano se mueven por razones distintas (el cercano, por el tiempo del momento; el lejano, por el salto de estación que tenga dentro), así que el condor no cancela casi nada. En el crudo, donde los calendarios consecutivos se parecen mucho, el condor tiene un tercio del riesgo del calendario (46 frente a 149 USD).

  1. Con los márgenes de la ficha de PEC, compara 10 largos en el contrato que se tiene con 10 calendarios 1.º − 2.º en 2016–2025: el peor día en USD, cuántas veces el margen inicial y en cuántas sesiones la pérdida del día supera el margen entero.
Solución
IN [15]python
for nombre, w, marg in [
        ("10 largos", [1], 10 * m["margen_inicial"]),
        ("10 calendarios", [1, -1],
         10 * m["margen_spread_calendario"])]:
    p = 10 * pyg("PEC", w).loc["2016":]
    peor = p.min()
    print(f"{nombre}: peor día {peor:,.0f} USD = "
          f"{-peor / marg:.1f} veces el margen; "
          f"días que superan el margen: {(p < -marg).sum()}")
OUT [15]El peor día en dinero y en margen
10 largos: peor día -92,800 USD = 1.7 veces el margen; días que superan el margen: 9
10 calendarios: peor día -13,000 USD = 1.9 veces el margen; días que superan el margen: 10

En dinero, el calendario pierde siete veces menos en su peor día (13.000 frente a 92.800 USD). En proporción al margen, pierde lo mismo o más: 1,9 veces el margen frente a 1,7, y la pérdida del día supera el margen entero en nueve sesiones con los largos y en diez con los calendarios. Como el margen del spread se fijó con el mismo número de desviaciones que el simple, el apalancamiento sobre el margen es el mismo; el spread solo es «más seguro» si se opera con el mismo número de contratos, no con el mismo margen. Los márgenes de la ficha son los de 2025 aplicados a toda la década: con los de cada momento, la comparación cambiaría.

  1. Un sistema compra 10 spreads ESU9-ESZ9 en CME (tipo EQ) pensando que está largo en septiembre y corto en diciembre. ¿Qué posición tiene en realidad y qué le pasa si los tipos a corto suben y la rentabilidad por dividendo no cambia?
Solución

Está corto en septiembre y largo en diciembre: en el calendario EQ de índices bursátiles, comprar el spread compra la pata lejana. El precio del spread es diciembre menos septiembre, que según la fórmula de financiación es S⋅(r−q)⋅(τ2−τ1)S \cdot (r - q) \cdot (\tau_2 - \tau_1). Si rr sube y qq no cambia, el spread sube y la posición, larga en el spread, gana. El sistema creía tener la apuesta contraria: si su intención era beneficiarse de una bajada de tipos, con la lectura equivocada del signo ha abierto justo lo opuesto. Por eso conviene que el código lea las patas y el signo de la definición del instrumento, no del nombre.

Respuesta plegada en cada pregunta

Autoevaluación

  1. En el crudo de los datos, el spread 1.º − 2.º tiene una desviación típica diaria de 149 USD por contrato frente a 1.258 de la posición simple, y su beta a la pata cercana es +0,106. ¿Qué significa esa beta?

    • AQue el spread no tiene ninguna exposición a la dirección del crudo
    • BQue por cada 1.000 USD que gana o pierde la pata cercana, el calendario gana o pierde unos 106 en el mismo sentido: el contrato cercano se mueve más que el siguiente
    • CQue el spread está cointegrado con el crudo
    • DQue hay que vender 0,106 contratos del segundo mes por cada uno del primero
    Ver respuesta

    Respuesta B. Que por cada 1.000 USD que gana o pierde la pata cercana, el calendario gana o pierde unos 106 en el mismo sentido: el contrato cercano se mueve más que el siguiente

    Es el efecto Samuelson de la lección 3.1.2: el contrato cercano reacciona más que el siguiente a los choques que revierten, así que largo en el cercano y corto en el siguiente conserva un pequeño largo en crudo. La correlación entre los dos P&L es 0,92: el calendario se mueve casi siempre en la dirección del crudo, pero con una décima parte del tamaño.

  2. ¿Cuánto margen inicial piden 10 spreads de calendario de PEC frente a 10 largos y 10 cortos de los mismos contratos tratados por separado?

    • ALo mismo: son las mismas 20 patas
    • BLa mitad, porque una pata compensa la otra
    • C6.700 USD frente a 112.000: el margen del spread sigue a su riesgo, un 12 % del de la posición simple
    • DNada, porque el riesgo neto es cero
    Ver respuesta

    Respuesta C. 6.700 USD frente a 112.000: el margen del spread sigue a su riesgo, un 12 % del de la posición simple

    La cámara mira el riesgo de la cartera, no el número de patas (lección 3.1.3). El margen del calendario de PEC es 670 USD frente a 5.600 de la posición simple: el 12 %, la misma proporción que su desviación típica diaria. Con ese margen se controla un nominal de 618.500 USD por pata.

  3. Una butterfly de gas de meses seguidos con la pata central en noviembre tiene un riesgo diario de 511 USD; con la central en junio, de 31. ¿Por qué?

    • APorque en noviembre hay menos liquidez
    • BPorque sus alas cruzan el paso de verano a invierno: el factor de invierno del gas carga con signo opuesto en octubre y en noviembre, y los pesos +1 −2 +1 no lo neutralizan
    • CPorque el contrato de noviembre vence antes
    • DPor azar: con diez años de datos la diferencia no significa nada
    Ver respuesta

    Respuesta B. Porque sus alas cruzan el paso de verano a invierno: el factor de invierno del gas carga con signo opuesto en octubre y en noviembre, y los pesos +1 −2 +1 no lo neutralizan

    Una butterfly neutraliza nivel y pendiente si la curva es suave entre sus tres meses. La del gas tiene un salto entre octubre y noviembre (y otro entre marzo y abril): cualquier butterfly que lo cruce queda expuesta a ese factor. Las cuatro que lo cruzan dan entre 391 y 511 USD; las ocho que no, entre 31 y 71.

  4. En CME, comprar el spread ESU9-ESZ9 (calendario de índice bursátil, tipo EQ) significa:

    • AComprar septiembre y vender diciembre; el precio es septiembre menos diciembre
    • BVender septiembre y comprar diciembre; el precio es diciembre menos septiembre
    • CComprar los dos contratos
    • DLo mismo que comprar NGZ9-NGF0: comprar la primera pata
    Ver respuesta

    Respuesta B. Vender septiembre y comprar diciembre; el precio es diciembre menos septiembre

    La documentación de Globex lo señala como excepción: en el calendario estándar (SP, p. ej. NGZ9-NGF0) comprar el spread compra la primera pata y el precio es pata 1 − pata 2; en el calendario de índices bursátiles (EQ), comprar compra la pata lejana y el precio es lejana − cercana. Leer mal la convención invierte la posición.

  5. En los índices, los metales y la divisa de los datos, el margen del calendario es el 3 % del margen simple, aunque su riesgo sea solo del 0,4 al 2,2 % del de la posición simple. ¿Qué indica?

    • AUn error en los datos
    • BQue el riesgo de esos spreads es mayor de lo que dicen las desviaciones típicas
    • CUn suelo: el margen no baja de un mínimo, así que en esos mercados cubre muchas más desviaciones diarias del spread que en el resto
    • DQue esos mercados no admiten spreads de calendario
    Ver respuesta

    Respuesta C. Un suelo: el margen no baja de un mínimo, así que en esos mercados cubre muchas más desviaciones diarias del spread que en el resto

    El generador fija el margen del spread con el mismo número de desviaciones que el simple y un suelo del 3 % del margen simple. Donde el spread casi no se mueve (financiación pura en índices, oro y divisa) manda el suelo: el margen del calendario del índice RVA cubre unas 15 desviaciones diarias de su P&L, frente a 5 de la posición simple.

Ideas clave

  • Un spread de calendario compra un mes y vende otro del mismo mercado: elimina casi toda la dirección y deja la pendiente de la curva. En los datos, su riesgo diario va del 0,4 % (índices) al 39 % (electricidad) del de la posición simple.
  • El P&L de una estructura se calcula con los mismos contratos de un día a otro; la serie de niveles 1.º − 2.º salta en cada roll.
  • Butterfly (+1 −2 +1) y condor (+1 −1 −1 +1) neutralizan también casi toda la pendiente: apuestan por la curvatura. En el gas, la que cruza el paso entre estaciones tiene siete u ocho veces más riesgo que las demás.
  • El margen del spread sigue a su riesgo (12 % del simple en el crudo) con un suelo; el apalancamiento nominal es enorme y el peor día de 2016–2025 de 10 calendarios de crudo costó 1,9 veces su margen.
  • En un índice, el calendario es financiación: la diferencia 2.º − 1.º sigue a S·(r − q)·Δτ con una correlación de 0,9997.
  • Las convenciones de signo cambian según el producto: en CME el calendario estándar compra la pata cercana; el de índices bursátiles, la lejana.

Recursos