Lección 3.1.2 · 65 min

Curva de futuros: base, cost of carry, contango y roll yield

Cada día cotizan varios vencimientos del mismo futuro, y la forma de esa curva no es una previsión del mercado: es, sobre todo, el coste de mantener el subyacente hasta cada fecha. Esta lección mide ese coste en los cuatro tipos de futuro (índices, bonos, divisas y materias primas), separa lo que gana quien mantiene un futuro en cambio del precio y roll yield, y comprueba con la respuesta conocida de los datos sintéticos cuándo el roll yield es una ganancia y cuándo no.

Fig. — La curva del crudo sintético en cuatro fechas: contango extremo en abril de 2020, backwardation en 2022 y en 2025, contango moderado en 2024
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)

Una curva, muchos precios

La lección 1.2.3 presentó la base y el contango con un solo índice. Aquí se generaliza a los cuatro tipos de futuro. La idea es la misma en todos: comprar el futuro equivale a comprar el subyacente hoy y mantenerlo hasta el vencimiento, con lo que eso cuesta (financiación, almacenamiento) y lo que rinde (dividendos, cupones, intereses de la otra divisa, la utilidad de tener la mercancía). La diferencia entre el futuro y el contado es ese coste de mantenimiento (cost of carry):

F(t,T)=St e(r+u−y) τ,τ=T−tF(t, T) = S_t \, e^{(r + u - y)\,\tau}, \qquad \tau = T - t

con rr el tipo de financiación, uu el coste de almacenamiento y yy todo lo que rinde tener el subyacente: el dividendo de un índice, el tipo de interés de la divisa extranjera, o el rendimiento de conveniencia de una materia prima (lo que vale tener el barril en el depósito en vez de un papel).

Contado+ financiación r+ almacenamiento u− lo que rinde yFuturo a τ añosÍndice: dividendoDivisa: su tipoRend. conveniencia
Fuente Mermaid
flowchart TB
  S[Contado] --> R[+ financiación r]
  R --> U[+ almacenamiento u]
  U --> Y[− lo que rinde y]
  Y --> F[Futuro a τ años]
  Y --> Q[Índice: dividendo]
  Y --> D[Divisa: su tipo]
  Y --> C[Rend. conveniencia]

Cuando el futuro lejano está por encima del cercano, la curva está en contango (r+u>yr + u > y); por debajo, en backwardation. En los financieros, todos los términos se observan y el arbitraje fija la curva. En las materias primas, el rendimiento de conveniencia no se observa: se deduce de la curva, y cambia con la escasez.

Índices: la base es el coste de mantenimiento

Los datos traen, para cada índice, el contado, la rentabilidad por dividendo y el tipo a un mes de su divisa:

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

curvas = pd.read_parquet("futuros3_curvas.parquet")
ctr = pd.read_csv("futuros3_contratos.csv",
                  parse_dates=["vencimiento", "primer_aviso",
                               "fecha_alta", "fecha_roll"])
esp = pd.read_csv("futuros3_especificaciones.csv",
                  index_col="mercado")
contado = pd.read_csv("futuros3_indices_contado.csv",
                      parse_dates=["fecha"])
venc = ctr.set_index("contrato")["vencimiento"]
curvas["dias"] = (venc.reindex(curvas["contrato"]).to_numpy()
                  - curvas["fecha"]).dt.days
DIA = "2025-11-26"
c = contado[(contado["fecha"] == DIA)].set_index("indice")
c[["contado", "rentabilidad_dividendo", "tipo_1m"]]
OUT [01]Contratos, curvas y el contado de los índices
         contado  rentabilidad_dividendo  tipo_1m
indice
RVA      7841.33                   1.891     3.87
RVB     26175.84                   0.959     3.87
RVC      3226.71                   1.227     3.87
RVE      6950.49                   2.947     2.09
RVH     19718.00                   3.570     2.09

El 26 de noviembre de 2025, los índices en dólares (RVA, RVB, RVC) se financian al 3,87 % y los de la zona del evro (RVE, RVH), al 2,09 %. El dividendo va del 0,959 % de RVB (un índice tecnológico, como el Nasdaq-100) al 3,570 % de RVH. Con esos tres números, la curva entera está determinada:

IN [02]python
def curva(mercado, dia):
    d = curvas[(curvas["mercado"] == mercado)
               & (curvas["fecha"] == dia)]
    return d.sort_values("dias").set_index("contrato")[
        ["dias", "liquidacion"]]

for m in ["RVA", "RVE"]:
    S, q, r = c.loc[m, ["contado", "rentabilidad_dividendo",
                        "tipo_1m"]]
    d = curva(m, DIA)
    tau = d["dias"] / 365
    d["razonable"] = S * np.exp((r - q) / 100 * tau)
    d["base"] = d["liquidacion"] - S
    d["dif_pb"] = 1e4 * np.log(d["liquidacion"] / d["razonable"])
    print(m, f"S = {S}, r − q = {r - q:.2f} %")
    print(d.round(2).to_string(), "\n")
OUT [02]Valor razonable de los futuros de RVA y RVE
RVA S = 7841.33, r − q = 1.98 %
          dias  liquidacion  razonable    base  dif_pb
contrato
RVAZ25      23      7851.75    7851.11   10.42    0.81
RVAH26     114      7892.00    7889.95   50.67    2.60
RVAM26     204      7930.50    7928.54   89.17    2.47
RVAU26     296      7970.25    7968.19  128.92    2.59
RVAZ26     387      8009.75    8007.60  168.42    2.68

RVE S = 6950.49, r − q = -0.86 %
          dias  liquidacion  razonable   base  dif_pb
contrato
RVEZ25      23       6946.0    6946.74  -4.49   -1.06
RVEH26     114       6929.0    6931.91 -21.49   -4.20
RVEM26     204       6914.0    6917.28 -36.49   -4.74
RVEU26     296       6900.0    6902.35 -50.49   -3.41
RVEZ26     387       6885.0    6887.62 -65.49   -3.80

En RVA, con el tipo por encima del dividendo (r−q=1,98r - q = 1{,}98 %), la curva está en contango: la base crece de 10,42 puntos a 23 días a 168,42 a 387. En RVE, con el dividendo por encima del tipo (r−q=−0,86r - q = -0{,}86 %), en backwardation: de −4,49 a −65,49. Los diez contratos están a menos de 5 puntos básicos de su valor razonable (dif_pb, entre −4,74 y +2,68): la diferencia es el redondeo al tick y un pequeño ruido que el generador añade y atenúa al acercarse el vencimiento. En los mercados reales la base tiene además la incertidumbre de los dividendos futuros y el coste real de financiarse, que no es el tipo a un mes.

Dicho al revés: si el futuro y el tipo se observan, el dividendo que el mercado descuenta sale de la curva:

qimpl=r−ln⁡(F/S)τq_{\text{impl}} = r - \frac{\ln(F/S)}{\tau}
IN [03]python
def que_se_tiene(fechas, mercado):
    cm = ctr[ctr["mercado"] == mercado].reset_index(drop=True)
    pos = np.searchsorted(cm["fecha_roll"].to_numpy(),
                          fechas.to_numpy(), side="right")
    return cm["contrato"].to_numpy()[pos]

filas = {}
for m in ["RVA", "RVB", "RVC", "RVE", "RVH"]:
    s = contado[contado["indice"] == m].set_index("fecha")
    tiene = que_se_tiene(s.index, m)
    f = curvas.set_index(["fecha", "contrato"])
    f = f.loc[list(zip(s.index, tiene))]
    tau = f["dias"].to_numpy() / 365
    F = f["liquidacion"].to_numpy()
    q_imp = 100 * (s["tipo_1m"] / 100
                   - np.log(F / s["contado"]) / tau)
    lejos = tau > 30 / 365            # con τ pequeño, el tick manda
    err = (q_imp - s["rentabilidad_dividendo"])[lejos]
    filas[m] = {"q_medio": s["rentabilidad_dividendo"].mean(),
                "error_medio": err.mean(), "error_dt": err.std()}
pd.DataFrame(filas).T.round(3)
OUT [03]Dividendo implícito en el futuro
     q_medio  error_medio  error_dt
RVA    1.855       -0.003     0.115
RVB    0.846        0.019     0.114
RVC    1.186        0.010     0.118
RVE    2.667        0.007     0.128
RVH    4.003        0.009     0.125

El dividendo implícito recupera el verdadero con un error medio de centésimas de punto y una desviación típica de 0,11 a 0,13 puntos porcentuales, en todas las sesiones de 2010 a 2025 en las que al contrato le quedan más de 30 días. Es la respuesta conocida: el generador construye cada futuro como el valor razonable más un ruido de unos 2 puntos básicos. Con menos de un mes al vencimiento, un tick de diferencia divide por un τ muy pequeño y el error se dispara; por eso el filtro. Los operadores de dividendos hacen esto mismo con futuros reales, al revés: estiman los dividendos y buscan futuros mal valorados.

Bonos y divisas: cupón, financiación y tipos

En un futuro de divisa, lo que rinde el subyacente es el tipo de interés de la divisa extranjera: la curva es la paridad cubierta de intereses (lección 1.2.4). En un futuro de bonos, es el cupón frente a la financiación del bono:

IN [04]python
for m in ["TPC", "DQE"]:
    print(m, curva(m, DIA)["liquidacion"].round(5).to_dict())
tipos = pd.read_csv("tipos3_curva.csv", index_col="fecha")
print(tipos.loc[DIA, ["usd_1m", "qev_1m", "usd_10a"]].to_dict())
OUT [04]Curva de la nota a 10 años y del evro
TPC {'TPCZ25': 113.04688, 'TPCH26': 113.07812, 'TPCM26': 113.125}
DQE {'DQEZ25': 1.36395, 'DQEH26': 1.37, 'DQEM26': 1.3761, 'DQEU26': 1.3822, 'DQEZ26': 1.38835}
{'usd_1m': 3.87, 'qev_1m': 2.09, 'usd_10a': 3.939}

El futuro de evros (DQE) sube con el plazo: de 1,36395 a 1,38835 en un año, un 1,8 % aproximadamente, la diferencia entre el 3,87 % del dólar y el 2,09 % del evro. Quien compra evros a plazo no cobra el tipo del evro y no paga el del dólar, y la curva lo compensa.

La nota a 10 años es más sutil. El bono que se entrega paga un cupón del 6 % y se financia al 3,87 %: el carry es positivo, y eso empuja la curva hacia abajo (backwardation). Pero en estos datos, como en los contratos reales, cada vencimiento entrega un bono distinto: el bono estándar de TPC vence 6,6 años después del vencimiento del futuro, así que el contrato de marzo entrega un bono tres meses más largo que el de diciembre. Con un cupón por encima del rendimiento, un bono más largo vale más, y eso empuja la curva hacia arriba:

IN [05]python
def precio_bono(y, anios, cupon=6.0):
    """Precio limpio de un bono con cupón anual que vence en `anios`
    (puede no ser entero), rendimiento y, por 100 de nominal."""
    t = np.arange(anios, 0, -1.0)[::-1]          # flujos
    sucio = (cupon * (1 + y) ** -t).sum() + 100 * (1 + y) ** -anios
    return sucio - cupon * (1 - anios % 1)   # sin el cupón corrido

y, r = 0.0375, tipos.loc[DIA, "usd_1m"] / 100
P1, P2 = precio_bono(y, 6.6), precio_bono(y, 6.85)
carry_trim = (6.0 - r * P1) / 4
print(f"precio del bono a 6,6 años {P1:.3f}, a 6,85 años {P2:.3f}")
print(f"un trimestre más de bono: {P2 - P1:+.3f}")
print(f"carry de un trimestre (cupón − financiación): "
      f"{-carry_trim:+.3f}")
OUT [05]Dos efectos en la curva de bonos
precio del bono a 6,6 años 112.916, a 6,85 años 113.359
un trimestre más de bono: +0.444
carry de un trimestre (cupón − financiación): -0.408

Con el rendimiento del bono de TPC de ese día (3,75 %, en tipos3_dv01.csv), un trimestre más de bono vale unos 0,44 puntos más y el carry de un trimestre resta unos 0,41: los dos efectos casi se anulan y la curva de TPC apenas sube (113,04688, 113,07812, 113,125). El cálculo es aproximado (cupón anual, misma tasa para los dos bonos), pero explica por qué en los futuros de bonos la pendiente entre vencimientos no es el carry: en la realidad, además, el bono más barato de entregar (CTD) puede cambiar de un vencimiento a otro, y con él la curva. La lección 3.2.4 vuelve a los bonos con su DV01.

Materias primas: almacenamiento y rendimiento de conveniencia

En una materia prima nadie publica el rendimiento de conveniencia. Se lee en la curva. La figura de la cabecera dibuja la del crudo en cuatro fechas:

IN [06]python
fechas = ["2020-04-20", "2022-06-08", "2024-03-13", DIA]
for dia in fechas:
    d = curva("PEC", dia)
    meses = (d["dias"] / 30.44).round(1)
    rel = 100 * np.log(d["liquidacion"]
                       / d["liquidacion"].iloc[0])
    print(dia, f"F1 = {d['liquidacion'].iloc[0]:.2f}",
          " ".join(f"{a:.0f}m:{b:+.1f}" for a, b
                   in zip(meses.iloc[[2, 5, 11, -1]],
                          rel.iloc[[2, 5, 11, -1]])))
OUT [06]La curva del crudo en cuatro fechas
2020-04-20 F1 = 26.82 2m:+15.3 5m:+31.9 11m:+51.6 17m:+62.6
2022-06-08 F1 = 130.49 2m:-3.9 6m:-8.3 11m:-14.6 17m:-18.7
2024-03-13 F1 = 52.82 2m:+2.3 5m:+5.7 11m:+12.3 17m:+18.5
2025-11-26 F1 = 76.69 3m:-6.0 6m:-11.1 12m:-14.3 17m:-13.2

El 20 de abril de 2020, con el primer contrato a 26,82 USD, el de 17 meses cotiza un 62,6 % (en logaritmos) por encima: es el contango de un mercado con exceso de oferta, el del guion de la pandemia de los datos. En junio de 2022, con el primero a 130,49, la curva baja: los lejanos cotizan hasta un 18,7 % por debajo. En marzo de 2024, contango suave; en noviembre de 2025, backwardation otra vez. La pendiente entre los dos primeros contratos, anualizada, da el rendimiento de conveniencia neto del almacenamiento:

IN [07]python
def pendiente(mercado, dia, a=0, b=1):
    """ln(F_a / F_b) / (τ_b − τ_a): > 0 en backwardation."""
    d = curva(mercado, dia)
    fa, fb = d["liquidacion"].iloc[[a, b]]
    ta, tb = d["dias"].iloc[[a, b]] / 365
    return np.log(fa / fb) / (tb - ta)

for dia in fechas:
    r = tipos.loc[dia, "usd_1m"] / 100
    k = -pendiente("PEC", dia)          # ln(F2/F1)/Δτ = r + u − y
    print(dia, f"ln(F2/F1)/Δτ {100 * k:+.1f} %,",
          f"tipo {100 * r:.2f} %,",
          f"y − u {100 * (r - k):+.1f} %")
OUT [07]Pendiente anualizada y rendimiento de conveniencia neto
2020-04-20 ln(F2/F1)/Δτ +96.5 %, tipo 0.21 %, y − u -96.3 %
2022-06-08 ln(F2/F1)/Δτ -24.1 %, tipo 1.56 %, y − u +25.6 %
2024-03-13 ln(F2/F1)/Δτ +13.5 %, tipo 5.30 %, y − u -8.2 %
2025-11-26 ln(F2/F1)/Δτ -38.6 %, tipo 3.87 %, y − u +42.4 %

La pendiente es r+u−yr + u - y, así que y−u=r−pendientey - u = r - \text{pendiente}. En abril de 2020, y−u=−96,3y - u = -96{,}3 %: guardar un barril cuesta muchísimo más de lo que rinde tenerlo. En marzo de 2024, −8,2 %: con el tipo al 5,30 %, la curva sube un 13,5 % anual, más que la financiación, porque almacenar cuesta. En junio de 2022 (+25,6 %) y noviembre de 2025 (+42,4 %), tener el barril vale mucho: el mercado paga por el producto disponible ahora y la curva baja. El rendimiento de conveniencia es la forma que tienen los modelos de decir «escasez».

Para medir la pendiente de los 23 mercados en toda la muestra hace falta la serie del contrato que se tiene y la del siguiente. Su carry anual es la pendiente entre los dos (positiva en backwardation, como en la lección 2.3.4):

ct=ln⁡(F1,t/F2,t)τ2−τ1c_t = \frac{\ln\left(F_{1,t} / F_{2,t}\right)}{\tau_2 - \tau_1}
IN [08]python
def serie(mercado):
    c = curvas[curvas["mercado"] == mercado]
    P = c.pivot(index="fecha", columns="contrato",
                values="liquidacion")
    D = c.pivot(index="fecha", columns="contrato", values="dias")
    tiene = que_se_tiene(P.index, mercado)
    i = P.columns.get_indexer(tiene)
    filas = np.arange(len(P))
    Pv = P.to_numpy()
    ayer = np.r_[i[0], i[:-1]]
    antes = np.r_[np.nan, Pv[filas[1:] - 1, ayer[1:]]]
    cm = ctr.loc[ctr["mercado"] == mercado, "contrato"].to_numpy()
    siguiente = dict(zip(cm[:-1], cm[1:]))
    sig = P.columns.get_indexer([siguiente.get(t) for t in tiene])
    ok = sig >= 0
    F2 = np.where(ok, Pv[filas, np.maximum(sig, 0)], np.nan)
    t1 = D.to_numpy()[filas, i] / 365
    t2 = np.where(ok, D.to_numpy()[filas, np.maximum(sig, 0)],
                  np.nan) / 365
    return pd.DataFrame({
        "contrato": tiene, "precio": Pv[filas, i],
        "ret": np.log(Pv[filas, ayer] / antes),
        "carry": np.log(Pv[filas, i] / F2) / (t2 - t1)},
        index=P.index)

mercados = esp[esp["mercado_base"].isna()].index
S = {m: serie(m) for m in mercados}
S["GNA"].loc["2025-11-07":"2025-11-14"].round(4)
OUT [08]El contrato que se tiene y su carry
           contrato  precio     ret   carry
fecha
2025-11-07   GNAZ25   8.700 -0.0221  0.3067
2025-11-10   GNAZ25   8.681 -0.0022  0.2743
2025-11-11   GNAZ25   8.397 -0.0333  0.1896
2025-11-12   GNAZ25   8.089 -0.0374  0.1443
2025-11-13   GNAZ25   8.123  0.0042  0.2365
2025-11-14   GNAZ25   8.024 -0.0123  0.2217

ret es el rendimiento del contrato que se tiene y carry, la pendiente anualizada hacia el siguiente: en la segunda semana de noviembre de 2025, el gas de diciembre cotiza por encima del de enero y el carry es positivo, entre el 14 % y el 31 % anual, y salta de un día a otro porque dos contratos a un mes de distancia amplifican cualquier movimiento relativo. Con las 23 series, la frecuencia del contango y el carry medio:

IN [09]python
carry = pd.DataFrame({m: S[m]["carry"] for m in mercados})
tabla = pd.DataFrame({
    "sector": esp.loc[mercados, "sector"],
    "contango_pct": 100 * (carry < 0).mean(),
    "carry_medio": 100 * carry.mean(),
    "carry_dt": 100 * carry.std(),
})
tabla.loc[["GNA", "GRM", "PEC", "ELB", "MTO", "DQE", "RVA", "TPC",
           "RVE", "RVH"]].round(1)
OUT [09]Cuántos días está cada mercado en contango
        sector  contango_pct  carry_medio  carry_dt
GNA    energia          61.0        -16.5      92.6
GRM  agricolas          57.3         -4.3      34.5
PEC    energia          46.2         -3.6      29.9
ELB    energia          50.8         -2.7     200.2
MTO    metales          64.8         -1.4       1.8
DQE    divisas          85.2         -1.0       1.0
RVA    indices          33.6          0.3       2.0
TPC      tipos          26.8          0.9       1.4
RVE    indices          12.1          2.1       1.3
RVH    indices           4.2          3.4       1.5

Tres familias:

  • Materias primas almacenables: contango cerca de la mitad de los días o más (del 46,2 % del crudo al 61,0 % del gas) y carry medio negativo: −3,6 % en el crudo, −4,3 % en el maíz, −16,5 % en el gas. El oro, con un carry medio de −1,4 % y una desviación típica de 1,8 puntos, es casi pura financiación.
  • Financieros: la pendiente es r−qr - q o su equivalente, estable (desviación típica de 1 a 2 puntos). RVH, con un dividendo alto, está en backwardation casi siempre (contango el 4,2 % de los días); la divisa DQE, en contango el 85,2 %, porque el tipo del dólar suele estar por encima del del evro en los datos.
  • Mercados con estacionalidad en la curva: la electricidad (ELB) tiene una desviación típica del carry de 200 puntos y el gas de 92,6: su pendiente entre dos meses consecutivos salta con la estación. La sección siguiente explica por qué esa parte no es carry.

La forma estacional no es carry

IN [10]python
d = curva("GNA", DIA)
print(d["liquidacion"].iloc[:14].round(3).to_dict())
OUT [10]La curva del gas natural
{'GNAF26': 7.239, 'GNAG26': 6.866, 'GNAH26': 6.259, 'GNAJ26': 4.255, 'GNAK26': 4.253, 'GNAM26': 4.385, 'GNAN26': 4.53, 'GNAQ26': 4.597, 'GNAU26': 4.612, 'GNAV26': 4.727, 'GNAX26': 5.907, 'GNAZ26': 6.284, 'GNAF27': 6.561, 'GNAG27': 6.452}

La curva del gas no es una pendiente, es una onda: enero de 2026 a 7,239, abril y mayo a 4,25, enero de 2027 otra vez a 6,561. El gas de invierno es más caro porque la demanda de calefacción lo es, y eso se sabe hoy. Entre el contrato de marzo (6,259) y el de abril (4,255) hay una «backwardation» del 38 % en un mes, pero quien compra el de abril no espera que suba hasta el precio del de marzo: son dos productos distintos (gas entregado en marzo y gas entregado en abril).

En el modelo de los datos esa forma es el término s(mes de T)s(\text{mes de } T) del logaritmo del precio: depende del mes de entrega, no del tiempo, así que un contrato concreto la arrastra toda su vida y no le da rendimiento (está descontada). La trampa es medir el carry entre meses consecutivos y operarlo: en el gas, el carry de la serie salta de signo con el calendario de rolls. Una alternativa habitual es comparar con el mismo mes del año siguiente, que tiene la misma forma estacional; la lección 3.2.6 trata la estacionalidad que sí es operable, la de los spreads.

Roll yield: lo que gana o pierde quien mantiene el futuro

Quien mantiene un futuro y lo rueda gana o pierde dos cosas: lo que se mueve el precio del contrato que se tiene, y la diferencia que paga en cada roll al vender un contrato y comprar el siguiente. Llamando PtP_t al precio del contrato que se tiene cada día (la serie sin ajustar de la lección 1.4.6):

∑trt⏟rendimiento total=ln⁡PTP0⏟cambio del precio+∑rollsln⁡FviejoFnuevo⏟roll yield\underbrace{\sum_t r_t}_{\text{rendimiento total}} = \underbrace{\ln\frac{P_T}{P_0}}_{\text{cambio del precio}} + \underbrace{\sum_{\text{rolls}} \ln\frac{F_{\text{viejo}}}{F_{\text{nuevo}}}}_{\text{roll yield}}
Rendimiento totalCambio del precioRoll yieldContango: −Backwardation: +
Fuente Mermaid
flowchart LR
  T[Rendimiento total] --> P[Cambio del precio]
  T --> RY[Roll yield]
  RY --> CO[Contango: −]
  RY --> BA[Backwardation: +]

En contango, cada roll vende el contrato cercano, más barato, y compra el siguiente, más caro: el roll yield es negativo. Que eso sea una pérdida o no depende de lo que haga el precio. Si el precio del primer contrato subiera justo lo que marca el contango (la «hipótesis de expectativas»), el cambio del precio compensaría el roll yield y el rendimiento total sería cero. Los datos permiten comprobarlo mercado a mercado:

IN [11]python
filas = {}
for m in mercados:
    s = S[m].loc["2011":]
    anios = len(s) / 252
    total = s["ret"].sum()
    precio = np.log(s["precio"].iloc[-1] / s["precio"].iloc[0])
    filas[m] = {"sector": esp.loc[m, "sector"],
                "total": 100 * total / anios,
                "precio": 100 * precio / anios,
                "roll": 100 * (total - precio) / anios,
                "carry_medio": 100 * s["carry"].mean()}
desc = pd.DataFrame(filas).T.infer_objects()
print(desc.loc[["RVA", "RVH", "TPD", "PEC", "GNA", "MTO",
                "GRA"]].round(2).to_string())
print("correlación roll–carry:",
      round(desc["roll"].corr(desc["carry_medio"]), 3))
OUT [11]Rendimiento total = cambio del precio + roll yield
        sector  total  precio   roll  carry_medio
RVA    indices  12.47   12.34   0.13         0.19
RVH    indices   6.98    3.60   3.39         3.44
TPD      tipos   1.31   -0.03   1.34         1.27
PEC    energia  -2.42   -0.01  -2.41        -2.47
GNA    energia -13.89    3.11 -17.00       -15.32
MTO    metales   0.71    1.99  -1.28        -1.44
GRA  agricolas  -6.82   -0.12  -6.69        -5.08
correlación roll–carry: 0.99

Todo en porcentaje anual de 2011 a 2025. El roll yield medido coincide con el carry medio de la serie (correlación de 0,99 entre los 23 mercados): el roll yield no es más que el carry acumulado. Lo interesante es la columna del precio:

  • En el gas (GNA), el precio del contrato que se tiene sube un 3,11 % al año, pero el roll yield es de −17,00 % y quien mantiene el futuro pierde un 13,89 % al año. La figura lo dibuja: 1 USD de 2011 termina en 0,12, mientras el precio que se ve en pantalla termina un 59 % más alto.
  • En el crudo (PEC), el precio termina donde empezó (−0,01 % al año) y el rendimiento total es el roll yield, −2,41 %.
  • En el aceite de soja (GRA), roll yield de −6,69 % y rendimiento total de −6,82 %.
  • En los índices, el roll yield es pequeño (r−qr - q): +0,13 % en RVA, +3,39 % en RVH, donde el dividendo supera al tipo. El rendimiento total es sobre todo el del precio.
  • En el bono a 30 años (TPD), el roll yield (+1,34 %) es casi todo el rendimiento: el carry positivo de tener un bono con cupón alto financiado a tipos bajos.
Fig. — Gas natural sintético, 2011-2025: el precio del contrato que se tiene frente a lo que gana quien lo mantiene y rueda
IN [12]python
desc.groupby("sector")[["total", "precio", "roll",
                        "carry_medio"]].mean().round(2)
OUT [12]Por sector
           total  precio  roll  carry_medio
sector
agricolas  -6.39   -1.30 -5.09        -4.02
divisas    -1.23   -0.10 -1.12        -1.07
energia    -3.62    1.42 -5.04        -4.55
indices    10.49    9.65  0.84         0.89
metales    -0.12    1.07 -1.19        -1.39
tipos       0.46   -0.14  0.60         0.59

En energía y agrícolas, el precio apenas compensa el contango (+1,42 % y −1,30 % al año, frente a un roll yield de −5,04 % y −5,09 %). Esa es la respuesta conocida del generador: el rendimiento esperado de un futuro de materia prima es

E[Δln⁡F]=−k+∑jwj e−κQτ[(κQ−κP) xj+derivaj]E[\Delta \ln F] = -k + \sum_j w_j\, e^{-\kappa_Q \tau}\left[(\kappa_Q - \kappa_P)\,x_j + \text{deriva}_j\right]

por año, donde kk es la pendiente de contango que tiene la curva cuando los factores xjx_j están en cero. El primer término dice que el contango se pierde: el precio no sube para alcanzarlo. El segundo es la prima de carry de los agrícolas y la energía, donde la curva descuenta una reversión más rápida (κQ\kappa_Q) que la real (κP\kappa_P): en backwardation, el futuro se queda barato. En el oro, sin reversión (κP=κQ=0\kappa_P = \kappa_Q = 0), el roll yield negativo (−1,28 %) es casi el tipo de interés: un futuro de oro es oro financiado, y quien compra el físico paga lo mismo.

El efecto Samuelson: los lejanos se mueven menos

La curva tiene una última propiedad útil: no todos los vencimientos se mueven igual.

IN [13]python
x = curvas[curvas["mercado"].isin(["PEC", "GNA", "GRM", "MTO",
                                   "RVA"])].sort_values(
    ["contrato", "fecha"])
x = x.assign(r=np.log(x["liquidacion"]).groupby(
    x["contrato"]).diff())
x = x[(x["fecha"] >= "2011-01-01") & (x["dias"] > 15)]
x["tramo"] = (x["dias"] // 91) * 3          # meses: 0, 3, 6…
vol = (x.groupby(["tramo", "mercado"])["r"].std().unstack()
       * np.sqrt(252))
vol.loc[:18].round(3)
OUT [13]Volatilidad por meses hasta el vencimiento
mercado    GNA    GRM    MTO    PEC    RVA
tramo
0        0.341  0.254  0.154  0.320  0.188
3        0.229  0.188  0.154  0.248  0.190
6        0.185  0.144  0.154  0.198  0.190
9        0.163  0.123  0.155  0.167  0.190
12       0.146  0.106  0.154  0.146  0.182
15       0.132  0.094  0.155  0.132    NaN
18       0.119  0.091  0.154    NaN    NaN

En el gas, la volatilidad anual del contrato pasa del 34,1 % en el tramo de 0 a 3 meses al 11,9 % a 18; en el maíz, del 25,4 % al 9,1 %; en el crudo, del 32,0 % al 13,2 % a 15 meses. En el oro y en el índice, nada: en torno al 15,4 % y al 19 % en todos los tramos. Es el efecto Samuelson: en los mercados donde los choques de oferta y demanda se corrigen con el tiempo, mueven mucho el precio de entrega cercana y poco el de dentro de un año. En el modelo de los datos, un vencimiento a τ años recibe e−κQτe^{-\kappa_Q \tau} de cada choque, con κ_Q de hasta 4 en el gas. La figura lo enseña por meses:

Fig. — Efecto Samuelson en los futuros sintéticos: volatilidad de cada contrato según los meses que le quedan, 2011-2025

Para un sistema tiene dos consecuencias. La volatilidad de la serie continua salta en cada roll en los mercados con reversión (el contrato nuevo está más lejos y se mueve menos), así que conviene estimarla con los rendimientos del mismo contrato y con una ventana que no se alargue demasiado. Y elegir un vencimiento más lejano reduce el riesgo por contrato, pero cambia la apuesta: en el gas, el contrato a un año apenas responde a lo que mueve el primero. La lección 3.1.3 mide qué pasa al rodar antes o después.

Ejercicios

  1. Calcula el tipo de financiación implícito (repo implícito) de los futuros de RVE el 26 de noviembre de 2025 suponiendo conocido el dividendo, y compáralo con el tipo a un mes del evro.
Solución
IN [14]python
S_, q_, r_ = c.loc["RVE", ["contado", "rentabilidad_dividendo",
                          "tipo_1m"]]
d = curva("RVE", DIA)
tau = d["dias"] / 365
d["r_impl"] = 100 * np.log(d["liquidacion"] / S_) / tau + q_
print(f"tipo a 1 mes {r_:.2f} %")
d.round(3)
OUT [14]Tipo implícito en la curva de RVE
tipo a 1 mes 2.09 %
          dias  liquidacion  r_impl
contrato
RVEZ25      23       6946.0   1.921
RVEH26     114       6929.0   1.956
RVEM26     204       6914.0   2.005
RVEU26     296       6900.0   2.048
RVEZ26     387       6885.0   2.054

Es la misma ecuación despejada para el tipo. Los contratos con más de tres meses dan un tipo implícito unas décimas por debajo del 2,09 %, la diferencia de 3 a 5 puntos básicos entre la liquidación y el valor razonable dividida por τ; el de 23 días da un error mayor, porque un punto de precio (el tick de RVE) son casi 1,5 puntos básicos y se divide por un τ de 0,063. En los mercados reales, ese tipo implícito se compara con el coste de financiarse de cada uno: si es más alto, sale a cuenta vender el futuro y comprar el índice (cash and carry).

  1. Repite la descomposición de rendimiento total, precio y roll yield del crudo (PEC) solo para 2020 y solo para 2022. ¿Cuándo el roll yield ayudó y cuándo perjudicó?
Solución
IN [15]python
for a in ["2020", "2022"]:
    s = S["PEC"].loc[a]
    total = s["ret"].sum()
    precio = np.log(s["precio"].iloc[-1] / s["precio"].iloc[0])
    roll = total - precio
    print(a, f"total {100 * total:+.1f} %, precio "
          f"{100 * precio:+.1f} %, roll {100 * roll:+.1f} %")
OUT [15]Crudo: 2020 frente a 2022
2020 total -163.5 %, precio -89.1 %, roll -74.3 %
2022 total -22.9 %, precio -26.1 %, roll +3.2 %

En 2020, con la curva en contango fuerte durante la caída, el roll resta 74,3 puntos de logaritmo: el precio del contrato que se tiene cae un 89,1 % en logaritmos y quien mantenía el futuro, un 163,5 % (de cada dólar le quedaban unos 20 céntimos). En 2022, en backwardation, el roll suma 3,2 puntos: el futuro perdió menos (−22,9 %) que el precio (−26,1 %). Es el mismo mecanismo que en el gas, con el signo de cada año.

  1. ¿Por qué la volatilidad de una serie continua de gas construida con el contrato que se tiene puede saltar en cada roll, y cómo afecta a un sistema que dimensiona por volatilidad (lección 2.2.2)?
Solución

Por el efecto Samuelson: el contrato que se tiene está cada vez más cerca del vencimiento y su volatilidad sube; en el roll se pasa a uno un mes más lejano, que se mueve menos. Una volatilidad estimada con ventanas largas mezcla tramos de los dos, y una que use rendimientos del contrato nuevo antes de tenerlo los infravalora. Un sistema que dimensiona por volatilidad compra más contratos justo después del roll (vol baja) y menos al final de la vida del contrato (vol alta). No es un error en sí, porque el riesgo real cambia de esa manera, pero hay que estimarla con rendimientos del mismo contrato y con una ventana coherente con la duración de un contrato.

Respuesta plegada en cada pregunta

Autoevaluación

  1. El 26 de noviembre de 2025 el índice RVA está en 7.841,33, el tipo a 1 mes en el 3,87 % y el rendimiento por dividendo en el 1,891 %. ¿Dónde debería cotizar el futuro a 114 días?

    • APor debajo del contado, porque el dividendo reduce el precio
    • BUnos 48 puntos por encima: S·e^((r − q)τ) con r − q = 1,98 % y τ = 114/365 da 7.889,95; el contrato liquida a 7.892
    • CAl mismo precio que el contado
    • DDonde el mercado espere que esté el índice en marzo
    Ver respuesta

    Respuesta B. Unos 48 puntos por encima: S·e^((r − q)τ) con r − q = 1,98 % y τ = 114/365 da 7.889,95; el contrato liquida a 7.892

    En un futuro financiero la curva la fija el arbitraje: quien compra el índice paga el tipo y cobra el dividendo; quien compra el futuro, no. El valor razonable es 7.889,95 y el contrato liquida 2,60 puntos básicos por encima.

  2. La curva del crudo del 20 de abril de 2020 tiene una pendiente de +96,5 % anual entre los dos primeros contratos con un tipo del 0,21 %. ¿Qué dice del rendimiento de conveniencia neto (conveniencia menos almacenamiento)?

    • AQue es muy positivo: tener crudo físico es valioso
    • BQue es de −96,3 %: almacenar cuesta muchísimo más de lo que rinde tener el barril, la situación de un mercado con exceso de oferta y depósitos llenos
    • CQue es cero
    • DNada: la pendiente depende solo del tipo de interés
    Ver respuesta

    Respuesta B. Que es de −96,3 %: almacenar cuesta muchísimo más de lo que rinde tener el barril, la situación de un mercado con exceso de oferta y depósitos llenos

    Con F = S·e^((r + u − y)τ), la pendiente es r + u − y y la conveniencia neta, y − u = r − pendiente = 0,21 − 96,5. Un contango así solo existe cuando sobra el producto y guardarlo es caro.

  3. En el gas natural sintético, de 2011 a 2025, el precio del contrato que se tiene sube un 3,11 % al año y quien mantiene el futuro pierde un 13,89 % al año. ¿De dónde sale la diferencia?

    • ADe las comisiones
    • BDel roll yield: −17,00 % al año, porque la curva está casi siempre en contango y cada roll vende el contrato barato que converge y compra el siguiente, más caro
    • CDe un error en la serie continua
    • DDel margen inicial
    Ver respuesta

    Respuesta B. Del roll yield: −17,00 % al año, porque la curva está casi siempre en contango y cada roll vende el contrato barato que converge y compra el siguiente, más caro

    Rendimiento total = cambio del precio + roll yield. El precio del primer contrato no sube lo suficiente para alcanzar el contango, así que el contango se pierde. La figura del gas lo enseña: 1 USD en 2011 termina en 0,12.

  4. ¿Por qué en el oro el roll yield es negativo (−1,28 % al año en los datos) y aun así no es una prima que cobre quien vende el futuro?

    • APorque en el oro el contango es el coste de financiación (y almacenamiento): quien tiene el oro físico lo paga igual, así que el futuro y el físico financiado rinden lo mismo
    • BPorque el oro no tiene futuros
    • CPorque el oro siempre está en backwardation
    • DPorque la volatilidad del oro es cero
    Ver respuesta

    Respuesta A. Porque en el oro el contango es el coste de financiación (y almacenamiento): quien tiene el oro físico lo paga igual, así que el futuro y el físico financiado rinden lo mismo

    En los activos de inversión fáciles de almacenar, la pendiente es casi solo el tipo (y el almacenamiento). Un futuro de oro equivale a oro financiado: el roll yield negativo es el tipo que el comprador del físico también pagaría.

  5. La volatilidad del gas sintético es del 41,7 % en el contrato al que le queda menos de un mes y del 10,3 % a 23 meses. ¿Cómo se llama el efecto y qué implica?

    • AEfecto Samuelson: los choques que revierten mueven mucho el vencimiento cercano y poco los lejanos; elegir un contrato más lejano reduce el riesgo por contrato y cambia lo que se está apostando
    • BEfecto calendario: el gas se mueve menos en verano
    • CUn error de los datos
    • DSonrisa de volatilidad
    Ver respuesta

    Respuesta A. Efecto Samuelson: los choques que revierten mueven mucho el vencimiento cercano y poco los lejanos; elegir un contrato más lejano reduce el riesgo por contrato y cambia lo que se está apostando

    En los datos, la curva descuenta que los choques revierten con velocidad κ_Q, así que un vencimiento a τ años se mueve e^(−κ_Q·τ) veces lo que el contado. En el oro, sin reversión, la volatilidad es plana.

Ideas clave

  • La curva de un futuro financiero la fija el arbitraje: índice S·e^((r − q)τ), divisa X·e^((r_USD − r_divisa)τ), bono con cupón menos financiación. Los futuros de índices de los datos liquidan a menos de 5 puntos básicos de su valor razonable.
  • En las materias primas, F = S·e^((r + u − y)τ): la pendiente mide almacenamiento menos rendimiento de conveniencia. El crudo pasa de +96,5 % anual de contango en abril de 2020 a −38,6 % en noviembre de 2025.
  • La forma estacional de la curva (gas de invierno caro, electricidad de verano) no es carry: está descontada y no da rendimiento a quien compra el contrato.
  • Rendimiento de mantener un futuro = cambio del precio + roll yield. En los 23 mercados, el roll yield medido y el carry medio tienen una correlación de 0,99; en el gas, el roll yield es de −17,00 % al año.
  • En los datos, el precio de las materias primas no sube para alcanzar el contango: el roll yield negativo es una pérdida real (la respuesta conocida, −k). Que en un mercado real el contango sea o no una prima es una pregunta empírica, no una ley.
  • Efecto Samuelson: en los mercados con reversión, los lejanos se mueven mucho menos que el primero (gas: 41,7 % frente a 10,3 %); en el oro, nada.

Recursos

Datos