Lección 2.3.4 · 70 min

Carry en divisas, futuros y bonos; estacionalidad y efectos calendario

El carry es lo que gana una posición si los precios no se mueven: el diferencial de tipos de una divisa, la pendiente de la curva de un futuro, el cupón y el deslizamiento por la curva de un bono. Esta lección lo mide en los datos sintéticos del nivel, donde la prima está plantada con su valor real, lo convierte en carteras con ejecución al día siguiente y costes, enseña por qué cae de golpe y prueba los efectos calendario en series donde no hay ninguno.

Fig. — Cartera de carry en divisas (tres contra tres, neta de costes) y los cinco tramos de crash del generador
Lecciones del nivel 2
  1. 2.1 · Estadística y econometría para trading

    1. 2.1.1 Contrastes de hipótesis, p-valores, bootstrap y regresión con errores robustos
    2. 2.1.2 Estacionariedad: ADF, KPSS, diferenciación y diferenciación fraccional
    3. 2.1.3 Modelos ARMA y ARIMA: autocorrelación simple (ACF) y parcial (PACF)
    4. 2.1.4 Modelos de volatilidad: ARCH, GARCH, EGARCH y GJR con la librería arch
    5. 2.1.5 Cointegración: Engle-Granger, Johansen y vida media de la reversión
    6. 2.1.6 Filtro de Kalman para hedge ratios dinámicos
    7. 2.1.7 Detección de regímenes: modelos de Markov ocultos y cambios estructurales
    8. 2.1.8 El problema de las pruebas múltiples: Bonferroni, FDR y el «factor zoo»
  2. 2.2 · Anatomía de un sistema de trading

    1. 2.2.1 Hipótesis de ventaja: riesgo, comportamiento, estructura e información
    2. 2.2.2 Universo, señal, filtro, entrada, salida, sizing y gestión del riesgo
    3. 2.2.3 Frecuencias: intradía, swing y posicional, y la capacidad de una estrategia
    4. 2.2.4 Diario de investigación y registro de experimentos contra el data snooping
  3. 2.3 · Familias de estrategias

    1. 2.3.1 Seguimiento de tendencia y momentum
    2. 2.3.2 Reversión a la media: RSI y Bollinger, reversión intradía y huecos
    3. 2.3.3 Pairs trading y arbitraje estadístico: distancia, cointegración y Kalman
    4. 2.3.4 Carry en divisas, futuros y bonos; estacionalidad y efectos calendario
    5. 2.3.5 Factores (value, calidad, baja volatilidad, tamaño) y estrategias de eventos
    6. 2.3.6 Introducción al market making: inventario, spread y selección adversa (Avellaneda-Stoikov)
    7. 2.3.7 Estrategias específicas de cripto: momentum, arbitraje de funding y basis
  4. 2.4 · Backtesting: motores y paradigmas

    1. 2.4.1 Backtest vectorizado desde cero: matrices, desfase, costes y límites
    2. 2.4.2 Backtest por eventos desde cero: bucle, cartera, órdenes y fills
    3. 2.4.3 vectorbt: barridos masivos de parámetros y simulación de carteras
    4. 2.4.4 backtesting.py y backtrader: dos motores didácticos y su estado
    5. 2.4.5 NautilusTrader: arquitectura, datos, estrategias y el mismo código en backtest y en real
    6. 2.4.6 LEAN/QuantConnect y Zipline Reloaded; bt para asignación de activos
    7. 2.4.7 Modelado de costes: comisiones, horquilla, impacto, financiación y préstamo de títulos
    8. 2.4.8 Modelado de fills: órdenes limitadas, cola, fills parciales, huecos y stops
  5. 2.5 · Sesgos y validación

    1. 2.5.1 Sesgos de backtest: anticipación, supervivencia, selección y narrativa
    2. 2.5.2 In-sample y out-of-sample: walk-forward anclado y móvil
    3. 2.5.3 Validación cruzada combinatoria purgada para estrategias
    4. 2.5.4 Deflated Sharpe Ratio y Probability of Backtest Overfitting (PBO)
    5. 2.5.5 Monte Carlo: remuestreo de trades, bootstrap de bloques y permutaciones de señales
    6. 2.5.6 Sensibilidad de parámetros: mesetas frente a picos, robustez entre activos y periodos
    7. 2.5.7 Datos sintéticos para pruebas de estrés: GBM, GARCH y bootstrapping
    8. 2.5.8 Checklist de «backtest honesto» antes de pasar a paper trading
  6. 2.6 · Métricas de rendimiento

    1. 2.6.1 CAGR, Sharpe, Sortino, Calmar, Omega, drawdown y Ulcer Index
    2. 2.6.2 Win rate, payoff, expectativa, alpha, beta, information ratio, turnover y capacidad
    3. 2.6.3 Informes con QuantStats o pyfolio-reloaded y tearsheets propios

Qué es el carry

El carry de una posición es lo que rinde si los precios no se mueven. Koijen, Moskowitz, Pedersen y Vrugt (2018) lo definen así para cualquier activo y lo descomponen en dos partes: el rendimiento esperado si nada cambia (el carry) y el cambio de precio, que nadie conoce de antemano. La definición es útil porque el carry se conoce hoy: es una señal sin estimación, sin parámetros que optimizar y sin anticipación posible.

CarryDivisasFuturosBonosDiferencial tiposPendiente curvaCupón y roll-down
Fuente Mermaid
flowchart TB
  C[Carry] --> FX[Divisas]
  C --> FU[Futuros]
  C --> BO[Bonos]
  FX --> D1[Diferencial tipos]
  FU --> D2[Pendiente curva]
  BO --> D3[Cupón y roll-down]
ActivoCarryQué tiene que pasar para cobrarlo
Divisa (largo frente al USD)Tipo de la divisa − tipo del USDQue el tipo de cambio no se deprecie tanto como el diferencial
Futuro (largo)Pendiente de la curva: ln(F₁ / F₂) / (τ₂ − τ₁)Que la curva no cambie y el contrato converja hacia el contado
Bono (largo, financiado)Rendimiento − tipo de financiación + roll-downQue la curva de tipos no se mueva

La teoría dice que el carry no debería ganar nada: si una divisa paga más interés, el mercado debería esperar que se deprecie lo mismo (paridad descubierta de tipos), y si un futuro está en backwardation, el contado debería caer hasta compensarlo. Lo que se observa en la literatura es que esa compensación es solo parcial, y que el carry rinde una prima con un riesgo concreto: pierde de golpe en las crisis. Brunnermeier, Nagel y Pedersen (2008) documentan que las divisas de tipo alto tienen una asimetría negativa, ligada a las salidas de posiciones en episodios de estrés.

Carry en divisas: el diferencial de tipos

fx2_carry.parquet tiene diez divisas ficticias frente al USD, en días laborables de 2005 a 2025: el precio en USD de una unidad (spot) y los tipos a corto de la divisa y del USD, en % anual. Quien está largo de una divisa (la compra con dólares prestados y la deposita) gana su variación más el diferencial de tipos, con la convención de 360 días del mercado monetario:

rt=Δln⁡St+(it−1−it−1∗)dt360r_{t} = \Delta \ln S_{t} + \left(i_{t-1} - i^{\ast}_{t-1}\right)\frac{d_t}{360}

con SS el spot, ii el tipo de la divisa, i∗i^{\ast} el del USD y dtd_t los días naturales desde la sesión anterior (3 los lunes). El diferencial que cuenta es el del día anterior: es el que se conocía al abrir la posición.

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

fx = pd.read_parquet("fx2_carry.parquet")
spot = fx.pivot(index="fecha", columns="divisa", values="spot")
dif = (fx.pivot(index="fecha", columns="divisa", values="tipo_divisa")
       - fx.pivot(index="fecha", columns="divisa", values="tipo_usd"))
dias = spot.index.to_series().diff().dt.days
d_spot = np.log(spot).diff()
interes = dif.shift(1).div(100).mul(dias / 360, axis=0)
r_fx = d_spot + interes

anual = pd.DataFrame({
    "diferencial_pct": dif.mean(),
    "interes_pct": 100 * interes.mean() * 260,
    "spot_pct": 100 * d_spot.mean() * 260,
    "total_pct": 100 * r_fx.mean() * 260,
})
anual.round(2)
OUT [01]Rentabilidad de estar largo en cada divisa
        diferencial_pct  interes_pct  spot_pct  total_pct
divisa
ALV                7.32         7.40      0.43       7.83
BOR                5.10         5.16     -5.45      -0.29
CAS                2.92         2.95     -0.81       2.14
DUN                2.93         2.96      0.35       3.31
EST                1.20         1.21     -0.34       0.88
FOR                0.59         0.60     -2.82      -2.23
GAL               -0.41        -0.41      2.09       1.68
HUR               -1.06        -1.07     -0.19      -1.26
ISL               -0.81        -0.81      2.43       1.61
JAR               -1.77        -1.79      2.54       0.75

La columna interes_pct es el diferencial cobrado (algo mayor que el diferencial medio por la convención de 360 días) y spot_pct, lo que se movió el tipo de cambio. ALV, la de tipo más alto (7,3 puntos sobre el USD), cobró un 7,40 % anual de interés y además se apreció un 0,43 %: un 7,83 % anual estando largo. BOR, la segunda, cobró un 5,16 % y perdió un 5,45 % en el spot, casi todo en un solo mes (febrero de 2009, abajo). Las de tipo bajo (GAL, ISL, JAR) pagaron interés y se apreciaron. El patrón medio es el de la respuesta conocida, pero divisa a divisa el ruido del tipo de cambio, de un 10 % a un 15 % anual, es mucho mayor que el diferencial.

La regresión de Fama (1984) es la forma clásica de contrastar la paridad descubierta. Fama usó la prima del tipo a plazo (forward), que por la paridad cubierta es el diferencial de tipos; aquí se usa el diferencial directamente: el cambio del tipo de cambio del mes siguiente sobre el diferencial de hoy.

Δln⁡St+1=a+b (it−it∗)+εt+1\Delta \ln S_{t+1} = a + b\,\left(i_t - i^{\ast}_t\right) + \varepsilon_{t+1}

Con la paridad, b=−1b = -1: la divisa se deprecia lo mismo que paga de más. Si el tipo de cambio fuera un paseo aleatorio, b=0b = 0 y el carry se cobraría entero. En los datos, la respuesta conocida es b=−0,3b = -0{,}3 fuera de los crashes, que añaden pérdidas proporcionales al diferencial. Con diez divisas que comparten los mismos meses, los residuos de un mismo mes están correlados: el error típico tiene que agruparse por fecha (lección 2.1.1).

IN [02]python
import statsmodels.api as sm

fin_mes = (spot.index.to_series()
           .groupby(spot.index.to_period("M")).max())
s_mes = np.log(spot.loc[fin_mes])
x_mes = dif.loc[fin_mes] / 100 / 12      # diferencial del mes
y_mes = s_mes.diff().shift(-1)           # cambio del mes siguiente

panel = pd.DataFrame({"y": y_mes.stack(), "x": x_mes.stack()}).dropna()
meses = panel.index.get_level_values("fecha").to_period("M")
fama = sm.OLS(panel["y"], sm.add_constant(panel["x"])).fit(
    cov_type="cluster", cov_kwds={"groups": meses.astype(str)})
b, eb = fama.params["x"], fama.bse["x"]
print(f"b = {b:.2f}  (error típico {eb:.2f})")
print(f"IC 95 %: [{b - 1.96 * eb:.2f}, {b + 1.96 * eb:.2f}]")

crash = meses.isin(pd.PeriodIndex(
    ["2008-09", "2008-10", "2008-11", "2008-12", "2010-05",
     "2011-08", "2011-09", "2015-08", "2015-09", "2020-02",
     "2020-03"], freq="M") - 1)   # x de fin de mes, y del siguiente
sin = sm.OLS(panel["y"][~crash], sm.add_constant(panel["x"][~crash]))
sin = sin.fit(cov_type="cluster",
              cov_kwds={"groups": meses[~crash].astype(str)})
print(f"sin los meses de crash: b = {sin.params['x']:.2f} "
      f"(error típico {sin.bse['x']:.2f})")
OUT [02]Regresión de Fama con errores agrupados por mes
b = -0.53  (error típico 0.36)
IC 95 %: [-1.24, 0.18]
sin los meses de crash: b = -0.09 (error típico 0.34)

La pendiente es −0,53, y su intervalo al 95 % va de −1,24 a +0,18: incluye la paridad descubierta (−1), el paseo aleatorio (0) y la respuesta conocida (−0,3). Sin los meses de crash, la pendiente sube a −0,09 con un error típico de 0,34: unos pocos meses mueven la estimación casi media unidad. Es la lección general del nivel aplicada a una regresión famosa: el método es correcto, pero con diez divisas y 251 meses no tiene potencia para separar las hipótesis que importan. Por eso la rentabilidad de una cartera de carry, que agrega todas las divisas y todos los meses en una sola serie, es una medida más directa de la prima.

Una cartera de carry con ejecución al día siguiente

La estrategia clásica ordena las divisas por diferencial y compra las de tipo alto con las de tipo bajo. Aquí, con diez divisas: al cierre del último día de cada mes se ordenan por diferencial, se compran las tres de tipo más alto y se venden las tres de tipo más bajo, con un tercio del capital en cada una. La posición entra en la sesión siguiente (shift(1) sobre los pesos diarios) y se mantiene hasta el siguiente fin de mes. Cada cambio de peso paga un coste de 3 puntos básicos por lado sobre el nominal negociado, una horquilla razonable para divisas líquidas de un cliente institucional; en las de tipo alto de países emergentes suele ser mayor.

IN [03]python
puesto = dif.loc[fin_mes].rank(axis=1)
pesos_mes = ((puesto >= 8).astype(float)
             - (puesto <= 3).astype(float)) / 3
# señal al cierre del fin de mes, posición desde la sesión siguiente
pesos = pesos_mes.reindex(spot.index, method="ffill").shift(1)

COSTE = 3 / 1e4                                   # por lado
giro = pesos.diff().abs().sum(axis=1).fillna(pesos.abs().sum(axis=1))
bruto = (pesos * r_fx).sum(axis=1)
neto = (bruto - COSTE * giro)[pesos.abs().sum(axis=1) > 0]

def resumen(r, n=260):
    eq = (1 + r).cumprod()
    mensual = r.resample("ME").sum()
    return pd.Series({
        "rent_anual_pct": 100 * r.mean() * n,
        "vol_anual_pct": 100 * r.std() * np.sqrt(n),
        "sharpe": r.mean() / r.std() * np.sqrt(n),
        "asimetria_mensual": mensual.skew(),
        "peor_mes_pct": 100 * mensual.min(),
        "max_dd_pct": 100 * (eq / eq.cummax() - 1).min(),
    })

pd.DataFrame({"bruto": resumen(bruto[neto.index]),
              "neto": resumen(neto)}).round(2)
OUT [03]Cartera de carry: tres contra tres, mensual
                   bruto   neto
rent_anual_pct      3.56   3.50
vol_anual_pct       9.24   9.24
sharpe              0.38   0.38
asimetria_mensual  -1.85  -1.85
peor_mes_pct      -22.72 -22.72
max_dd_pct        -49.61 -49.68

Neta de costes, la cartera rinde un 3,50 % anual con una volatilidad del 9,24 %: un Sharpe de 0,38. Los costes casi no importan (de 3,56 % a 3,50 %), porque el orden por tipos cambia poco de un mes a otro y se negocia muy poco. Lo que sí importa son las otras tres filas: una asimetría mensual de −1,85, un peor mes de −22,7 % y una caída máxima del 49,7 %. Con una volatilidad del 9 % y rentabilidades normales, una caída de la mitad del capital sería casi imposible; el carry la tiene porque sus pérdidas no son normales.

IN [04]python
partes = pd.DataFrame({
    "interes": (pesos * interes).sum(axis=1),
    "divisa": (pesos * d_spot).sum(axis=1),
    "costes": -COSTE * giro,
}).loc[neto.index]
(100 * partes.mean() * 260).round(2)
OUT [04]De dónde sale el resultado: interés frente a divisa
interes    6.56
divisa    -3.00
costes    -0.05
dtype: float64

La cartera cobra un 6,56 % anual de diferencial y pierde un 3,00 % en los tipos de cambio: se queda con algo más de la mitad del carry. La respuesta conocida (el spot se lleva un 30 % del diferencial, más los crashes) predice algo parecido. Los costes, 0,05 puntos al año, son irrelevantes con esta frecuencia.

Los crashes del carry

La figura de la cabecera es la curva de la cartera neta, con los cinco tramos de crash del generador sombreados. El mecanismo plantado es el que describe la literatura: en una huida hacia la calidad, las divisas de tipo alto caen y las de tipo bajo, que hacen de refugio, suben. La cartera está larga de las primeras y corta de las segundas, así que pierde por los dos lados a la vez.

IN [05]python
crashes = {"2008 T4": ("2008-09-15", "2008-12-31"),
           "2010 may": ("2010-05-03", "2010-05-31"),
           "2011 ago-sep": ("2011-08-01", "2011-09-30"),
           "2015 ago-sep": ("2015-08-17", "2015-09-30"),
           "2020 feb-mar": ("2020-02-24", "2020-03-31")}
en_crash = {k: 100 * neto[a:b].sum() for k, (a, b) in crashes.items()}
print(pd.Series(en_crash).round(1).to_string())
print()
mensual = neto.resample("ME").sum()
print((100 * mensual.nsmallest(5)).round(1).to_string())
OUT [05]Resultado en cada tramo de crash y peores meses
2008 T4        -23.4
2010 may        -7.6
2011 ago-sep    -8.0
2015 ago-sep    -4.4
2020 feb-mar   -15.6

fecha
2009-02-28   -22.7
2020-03-31   -13.2
2008-11-30    -8.6
2022-08-31    -8.3
2010-05-31    -7.6

En el último trimestre de 2008 la cartera pierde un 23,4 %, y en febrero y marzo de 2020 un 15,6 %: dos episodios que se llevan, cada uno, varios años de diferencial. El peor mes, sin embargo, no está en ningún tramo plantado: febrero de 2009, con −22,7 %, es la caída del 37 % de BOR en un mes, una cola de las innovaciones t de Student del modelo de volatilidad. Es un recordatorio útil: el riesgo de cola de una cartera concentrada en pocas divisas no se limita a los crashes que uno conoce, y un backtest con los tramos de estrés quitados «porque fueron excepcionales» sobrestima lo que se puede ganar.

Estrés en mercadosVentas de riesgoCaen tipo altoSuben refugioPierde el carryCierre forzado
Fuente Mermaid
flowchart TB
  E[Estrés en mercados] --> V[Ventas de riesgo]
  V --> A[Caen tipo alto]
  V --> B[Suben refugio]
  A --> P[Pierde el carry]
  B --> P
  P --> L[Cierre forzado]
  L --> A

El bucle del diagrama es lo que hace que los crashes del carry sean bruscos: las pérdidas fuerzan a reducir posiciones, y las ventas empujan aún más abajo las mismas divisas. Para un sistema, la consecuencia práctica es que el Sharpe y la volatilidad no describen el riesgo: hay que mirar la asimetría, el peor mes y las pérdidas en episodios concretos, y dimensionar la posición para sobrevivirlos (lección 2.2.2).

Carry en futuros: la pendiente de la curva

En un futuro, el carry es la pendiente de la curva entre el contrato que se tiene y el siguiente (lección 1.2.3). Si el primero cotiza por encima del segundo (backwardation), el carry es positivo: con la curva quieta, el contrato que se tiene sube hacia el contado a medida que vence. futuros2_carry.parquet lo trae calculado para los 24 mercados:

ct=ln⁡(F1,t/F2,t)τ2−τ1c_t = \frac{\ln\left(F_{1,t} / F_{2,t}\right)}{\tau_2 - \tau_1}
IN [06]python
cont = pd.read_parquet("futuros2_continuos.parquet")
carry = pd.read_parquet("futuros2_carry.parquet")
spec = pd.read_csv("futuros2_especificaciones.csv",
                   index_col="mercado")

px = cont.pivot(index="fecha", columns="mercado",
                values="cierre_ajustado")
c_anual = carry.pivot(index="fecha", columns="mercado",
                      values="carry_anual")
r_fut = np.log(px).diff()
(100 * c_anual.mean()).groupby(spec["sector"]).agg(
    ["mean", "min", "max"]).round(1)
OUT [06]Carry medio por sector
                mean   min  max
sector
agricolas       -3.6  -5.4 -1.4
bonos            1.1   0.3  2.2
divisas          0.6  -1.3  1.9
energia         -2.4 -10.3  4.0
metales         -2.7  -4.7 -0.6
renta_variable  -0.0  -0.1  0.1

El carry medio depende del sector. Los bonos tienen carry positivo (un 1,1 % de media), mayor cuanto más largo el plazo; los agrícolas y los metales, negativo (−3,6 % y −2,7 %), como el contango por almacenamiento y financiación de muchas materias primas; la energía va del −10,3 % del gas al +4,0 % del crudo pesado; los índices, casi cero, porque su carry en el generador es un 2 % menos el tipo libre, que de media está cerca del 2 %. Ordenar los 24 mercados por carry es en parte ordenar sectores, y en parte algo que cambia con el tiempo: el carry de una materia prima se mueve con su precio.

En estos datos el carry tiene dos partes, y no pagan lo mismo. Los precios de las materias primas, las divisas y los bonos revierten hacia un nivel de referencia (un ancla que crece despacio), como en el modelo de un factor de Schwartz (1997)1Nota 1 · Eduardo S. Schwartz, «The Stochastic Behavior of Commodity Prices: Implications for Valuation and Hedging», The Journal of Finance 52(3), 1997, https://doi.org/10.1111/j.1540-6261.1997.tb02721.x.. Cuando el contado está muy por encima del ancla, la curva entra en backwardation porque el mercado ya espera que baje; cuando está muy por debajo, en contango. Esa parte del carry, la de reversión, es «justa»: descuenta un movimiento esperado del contado y casi no predice el rendimiento del futuro. La otra, la exógena (almacenamiento, financiación, presión de las coberturas), es la que lleva la prima. La respuesta conocida del generador, en términos anuales, es:

E[r]=0,5 cexo+0,1 crev+0,15 σ signo⁡(r252)E[r] = 0{,}5\,c^{\text{exo}} + 0{,}1\,c^{\text{rev}} + 0{,}15\,\sigma\,\operatorname{signo}\left(r_{252}\right)

más la prima de la renta variable en los índices y una caída de los bonos en 2022. El último término es una prima de tendencia: la volatilidad del mercado por el signo de su rendimiento de las 252 sesiones anteriores. Solo se observa la suma c=cexo+crevc = c^{\text{exo}} + c^{\text{rev}}, y la parte de reversión está correlada con la tendencia: un mercado que lleva un año subiendo está por encima de su ancla, en backwardation y con tendencia positiva. Una regresión sobre el carry solo mezcla las tres cosas; con la tendencia a la vez, separa al menos la última.

IN [07]python
fin_f = px.index.to_series().groupby(px.index.to_period("M")).max()
r_sig = np.log(px.loc[fin_f]).diff().shift(-1) * 12
sigma = r_fut.std() * np.sqrt(252)          # σ de cada mercado
tend = sigma * np.sign(np.log(px).diff(252)).loc[fin_f]
datos_c = pd.DataFrame({"y": r_sig.stack(),
                        "carry": c_anual.loc[fin_f].stack(),
                        "tend": tend.stack()}).dropna()
grupos = datos_c.index.get_level_values("fecha").astype(str)
for x in (["carry"], ["carry", "tend"]):
    m = sm.OLS(datos_c["y"], sm.add_constant(datos_c[x])).fit(
        cov_type="cluster", cov_kwds={"groups": grupos})
    print(", ".join(f"{k} {m.params[k]:.2f} (et {m.bse[k]:.2f})"
                    for k in x))
print(f"n = {len(datos_c)}; correlación carry-tendencia: "
      f"{datos_c['carry'].corr(datos_c['tend']):.2f}")
OUT [07]Rendimiento del mes siguiente sobre el carry y la tendencia
carry 0.27 (et 0.13)
carry 0.17 (et 0.14), tend 0.11 (et 0.08)
n = 7176; correlación carry-tendencia: 0.49

Sola, la pendiente del carry es 0,27 con un error típico de 0,13: ni el 0,5 de la parte exógena ni el 0,1 de la reversión, sino una mezcla de las dos. Con la tendencia en la regresión, el carry baja a 0,17 y la tendencia sale 0,11 (verdad: 0,15). Parte de lo que la regresión simple atribuía al carry era momentum, porque las dos variables tienen una correlación de 0,49 a fin de mes. El README de los datos da 0,26, 0,15 y 0,12 con la volatilidad de su tabla y otra anualización: la misma conclusión. La σ\sigma de la celda es la volatilidad de toda la muestra de cada mercado, un factor de escala constante como el de la tabla; para medir vale, para operar habría que usar la de la ventana anterior.

Los errores típicos están agrupados por mes porque los 24 mercados comparten sus sorpresas, y son grandes: con el carry y la tendencia juntos, ninguno de los dos coeficientes llega a dos errores típicos. Los 7.176 meses-mercado parecen muchos, pero son 299 meses de 24 mercados correlados. Y la regresión no puede separar las dos partes del carry, porque solo ve la suma: el 0,5 plantado en la parte exógena no se recupera con una regresión sobre el carry observado.

Fig. — Carry de fin de mes y rentabilidad del mes siguiente en los 24 futuros, en veinte grupos por carry

La figura agrupa las observaciones en veinte grupos por carry y pinta la rentabilidad media del mes siguiente de cada uno, con la recta ajustada y, discontinua, la de pendiente 0,5 que se vería si todo el carry fuera exógeno. La relación se ve, pero también su ruido: cada punto es la media de unos 360 meses-mercado y aun así se separa de la recta varios puntos porcentuales.

Una cartera de carry en futuros con costes por tick

La cartera compra los ocho mercados de carry más alto y vende los ocho de carry más bajo, con un peso inverso a su volatilidad de 63 sesiones para que cada posición aporte un riesgo parecido (un 2,5 % anual). Se rehace al cierre de cada mes y entra en la sesión siguiente. Los costes salen de las especificaciones: coste_tipico_ticks ticks de deslizamiento más la comisión, por contrato y lado, divididos por el nominal del contrato (precio × multiplicador). Además, cada roll (el cambio de contrato) paga dos lados sobre toda la posición.

IN [08]python
precio = cont.pivot(index="fecha", columns="mercado", values="cierre")
contrato = cont.pivot(index="fecha", columns="mercado",
                      values="contrato")
coste_pb = ((spec["coste_tipico_ticks"] * spec["valor_tick"]
             + spec["comision_usd"])
            / (precio * spec["multiplicador"]) * 1e4)
coste_pb.median().sort_values().round(1).iloc[[0, 1, 2, -3, -2, -1]]
OUT [08]Coste por lado en puntos básicos del nominal
mercado
IDB     0.7
DIA     0.8
BOA     0.9
AGA    10.9
AGB    11.3
MEB    13.2
dtype: float64

En los mercados financieros, un lado cuesta menos de un punto básico del nominal: 0,7 en el índice IDB, 0,8 en la divisa DIA y 0,9 en el bono a 2 años BOA. En los contratos cuyo tick y comisión pesan más frente al nominal, el coste se multiplica por más de diez: 10,9 puntos básicos en el maíz AGA, 11,3 en el trigo AGB y 13,2 en la plata MEB. Además, un coste que se mide en ticks depende del precio: si el precio de un contrato cae a la mitad, su coste en porcentaje se duplica. Es un detalle que un backtest con un coste fijo en puntos básicos no ve (lección 2.4.7).

IN [09]python
vol = r_fut.rolling(63).std() * np.sqrt(252)
puesto_f = c_anual.loc[fin_f].rank(axis=1)
n_f = puesto_f.notna().sum(axis=1)
lado = ((puesto_f > n_f.to_numpy()[:, None] - 8).astype(float)
        - (puesto_f <= 8).astype(float))
pesos_f = (lado * 0.025 / vol.loc[fin_f]).fillna(0)
pesos_f = pesos_f.reindex(px.index, method="ffill").shift(1)

roll = contrato.ne(contrato.shift(1)) & contrato.shift(1).notna()
coste = (pesos_f.diff().abs() * coste_pb
         + 2 * pesos_f.abs() * coste_pb * roll) / 1e4
bruto_f = (pesos_f * r_fut).sum(axis=1)["2001":]
neto_f = bruto_f - coste.sum(axis=1)["2001":]
pd.DataFrame({"bruto": resumen(bruto_f, 252),
              "neto": resumen(neto_f, 252)}).round(2)
OUT [09]Cartera de carry en futuros, ocho contra ocho
                   bruto   neto
rent_anual_pct      7.36   5.71
vol_anual_pct      11.64  11.64
sharpe              0.63   0.49
asimetria_mensual   0.01   0.01
peor_mes_pct      -12.67 -12.78
max_dd_pct        -32.03 -33.71

Bruta, la cartera rinde un 7,36 % anual con un Sharpe de 0,63; neta, un 5,71 % y 0,49. Los costes, 1,65 puntos al año, se llevan algo más de una quinta parte de la prima: el rebalanceo mensual cambia pocas posiciones, pero cada roll paga dos lados sobre toda la posición, y en los mercados caros de la celda anterior eso suma. A diferencia del carry de divisas, la asimetría mensual es casi cero (0,01): en estos futuros, los mercados de carry alto y bajo no caen todos a la vez en las crisis del guion. La caída máxima es del 33,7 %, y el resultado no es estable en el tiempo:

IN [10]python
periodos = [("2001", "2009"), ("2010", "2019"), ("2020", "2025")]
sh = {f"{a}-{b}": resumen(neto_f[a:b], 252)["sharpe"]
      for a, b in periodos}
print(pd.Series(sh).round(2).to_dict())
sector = spec["sector"].reindex(px.columns)
peso_22 = pesos_f.loc["2022"].mean().groupby(sector).sum()
res_22 = (pesos_f * r_fut).loc["2022"].sum().groupby(sector).sum()
pd.DataFrame({"peso_medio_2022": peso_22,
              "resultado_2022_pct": 100 * res_22}).round(2)
OUT [10]Sharpe por periodos y la cartera en 2022
{'2001-2009': 0.79, '2010-2019': 0.58, '2020-2025': -0.06}
                peso_medio_2022  resultado_2022_pct
sector
agricolas                 -0.08                0.50
bonos                      1.35              -23.90
divisas                   -0.15                2.23
energia                    0.03               -4.42
metales                   -0.21               -1.56
renta_variable             0.06                0.31

El Sharpe neto es de 0,79 en 2001-2009, de 0,58 en 2010-2019 y de −0,06 en 2020-2025. El último tramo tiene un culpable claro: en 2022 la cartera está larga de bonos con un peso medio del 135 % del capital, y los bonos pierden 23,9 puntos ese año (el generador planta una caída de los bonos en 2022, como la de los mercados reales). Ese peso no lo eligió nadie: sale de ponderar por la inversa de la volatilidad. Un bono a 2 años con una volatilidad del 2 % recibe un nominal unas diecisiete veces mayor que un crudo con un 35 % para aportar el mismo riesgo en calma, y cuando los bonos caen a la vez, como en 2022, el riesgo que se suponía repartido estaba concentrado. El README de los datos mide una cartera algo distinta (la mitad de los mercados contra la otra mitad, pesos del 10 % entre la volatilidad) y encuentra lo mismo: Sharpe de 0,45 en toda la muestra y negativo en 2020-2025.

La cartera, además, no es una apuesta pura por el carry. Con la reversión «justa» dentro de la señal y una correlación de 0,49 con la tendencia, parte de lo que gana es momentum disfrazado, y parte de lo que paga es reversión que la curva ya había descontado. Saber qué prima se está cobrando importa para combinarla con otras estrategias (lección 2.3.1).

Bonos: carry y roll-down

En un bono financiado, el carry tiene dos partes. La primera es el rendimiento menos el tipo al que se financia la posición. La segunda, el roll-down: con una curva de pendiente positiva, un bono a 10 años es al cabo de un año un bono a 9 años, que se valora con un rendimiento más bajo, y su precio sube aunque la curva no se haya movido. Para un horizonte hh (en años), con la curva quieta y la duración modificada DD:

carry≈(yT−r) h+DT−h (yT−yT−h)\text{carry} \approx (y_T - r)\,h + D_{T-h}\,\left(y_T - y_{T-h}\right)

Los futuros de bonos del nivel no traen una curva de rendimientos, así que el cálculo se hace con una curva de ejemplo: un bono a 10 años con cupón igual a su rendimiento, valorado hoy y dentro de un año con la misma curva.

IN [11]python
plazos = np.array([1, 2, 5, 7, 9, 10, 30])
curva = np.array([3.50, 3.55, 3.80, 3.98, 4.16, 4.25, 4.70]) / 100
r_fin = 0.034                         # financiación a un año

def precio_bono(cupon, rend, anos):
    t = np.arange(1, anos + 1)
    return (cupon / (1 + rend) ** t).sum() + 1 / (1 + rend) ** anos

y10 = np.interp(10, plazos, curva)
y9 = np.interp(9, plazos, curva)
hoy = precio_bono(y10, y10, 10)                  # = 1 (a la par)
en_un_ano = precio_bono(y10, y9, 9)              # misma curva
total = (en_un_ano + y10) / hoy - 1
print(f"cupón {100 * y10:.2f} %, roll-down "
      f"{100 * (en_un_ano / hoy - 1):.2f} %, "
      f"menos financiación {100 * r_fin:.2f} %")
print(f"carry total a un año: {100 * (total - r_fin):.2f} %")
OUT [11]Carry y roll-down de un bono a 10 años con la curva quieta
cupón 4.25 %, roll-down 0.66 %, menos financiación 3.40 %
carry total a un año: 1.51 %

El bono cobra su cupón del 4,25 % y gana un 0,66 % de precio al rodar de 10 a 9 años; financiado al 3,40 %, el carry total a un año es del 1,51 %. La aproximación de la fórmula da lo mismo: (4,25 − 3,40) % por un año, más una duración cercana a 7,4 por los 9 puntos básicos que separan los rendimientos a 10 y a 9 años.

Fig. — Roll-down de un bono a 10 años: con la curva quieta, en un año pasa a valorarse con el rendimiento a 9 años (esquema)

La figura lo dibuja sobre la curva de ejemplo: el bono empieza en el plazo de 10 años y, con la curva quieta, termina el año en el de 9, con un rendimiento más bajo. Cuanto más empinado el tramo por el que rueda, mayor el roll-down, y cuanto más larga la duración, más precio da cada punto básico. Una estrategia de carry en bonos elige plazos con el mayor carry más roll-down por unidad de duración. En los futuros de bonos ese carry ya está en la pendiente de la curva de futuros: es lo que miden las filas bonos del carry por sector.

Estacionalidad y efectos calendario: el control

La lección 1.6.3 midió los efectos calendario clásicos (día de la semana, mes, cambio de mes) y enseñó por qué casi ninguno resiste. Aquí sirven de control: el generador del nivel 2 no planta ningún efecto calendario en los índices de renta variable. Todo lo que aparezca es azar o un artefacto de los datos. Se prueban los cinco futuros de índices (IDA a IDE), comparando cada día con el resto, no con cero:

IN [12]python
from scipy import stats

indices = ["IDA", "IDB", "IDC", "IDD", "IDE"]
ri = r_fut[indices].dropna()
dia = ri.index.dayofweek
filas = []
for m in indices:
    for d, nombre in enumerate(["lun", "mar", "mié", "jue", "vie"]):
        t, p = stats.ttest_ind(ri[m][dia == d], ri[m][dia != d],
                               equal_var=False)
        filas.append({"indice": m, "dia": nombre, "t": t, "p": p})
dow = pd.DataFrame(filas)
print("p < 0,05:", (dow["p"] < 0.05).sum(), "de", len(dow),
      "| esperados por azar:", 0.05 * len(dow))
print(dow.nsmallest(3, "p").round(3).to_string(index=False))
print("correlación media entre índices:",
      round(ri.corr().to_numpy()[np.triu_indices(5, 1)].mean(), 2))
OUT [12]Día de la semana en cinco índices: 25 contrastes
p < 0,05: 1 de 25 | esperados por azar: 1.25
indice dia      t     p
   IDD jue  2.132 0.033
   IDE jue  1.571 0.116
   IDD lun -1.402 0.161
correlación media entre índices: 0.81

Uno de los 25 contrastes tiene p < 0,05 (IDD los jueves, p = 0,033), donde el azar espera 1,25. Y los 25 no son independientes: los cinco índices tienen una correlación media de 0,81, así que cuando uno sale «casi significativo» un día, los otros suelen apuntar en la misma dirección. El número efectivo de pruebas es menor de lo que parece, y el de falsos positivos, más variable.

IN [13]python
g = ri.groupby(ri.index.to_period("M"))
cambio = (g.cumcount() < 3) | (g.cumcount(ascending=False) == 0)
estres = pd.Series(False, index=ri.index)
for a, b in [("2000-09-01", "2002-10-09"), ("2008-09-02", "2009-03-09"),
             ("2010-04-26", "2010-07-05"), ("2011-07-25", "2011-10-03"),
             ("2015-08-17", "2016-02-11"), ("2018-10-01", "2018-12-25"),
             ("2020-02-20", "2020-03-23"), ("2022-01-04", "2022-10-12"),
             ("2025-02-20", "2025-04-08")]:
    estres[a:b] = True

def tom(r, sel):
    a, b = r[cambio & sel], r[~cambio & sel]
    p = stats.ttest_ind(a, b, equal_var=False).pvalue
    return 1e4 * a.mean(), 1e4 * b.mean(), p

filas = {}
for m in indices:
    for nombre, sel in [("todo", estres | ~estres),
                        ("calma", ~estres), ("estrés", estres)]:
        filas[(m, nombre)] = tom(ri[m], sel)
pd.DataFrame(filas, index=["cambio_pb", "resto_pb", "p"]).T.round(3)
OUT [13]Cambio de mes, en calma y en estrés
            cambio_pb  resto_pb      p
IDA todo       -3.918     4.029  0.061
    calma       3.925     8.931  0.192
    estrés    -37.550   -18.249  0.202
IDB todo       -3.288     4.062  0.146
    calma       6.372     7.828  0.757
    estrés    -44.710   -13.054  0.069
IDC todo       -1.426     3.165  0.337
    calma       8.367     8.104  0.954
    estrés    -43.421   -19.280  0.122
IDD todo       -4.112     4.007  0.079
    calma       3.014     9.480  0.126
    estrés    -34.670   -20.870  0.400
IDE todo       -2.185     3.622  0.208
    calma       7.813     7.804  0.998
    estrés    -45.058   -15.388  0.064

El cambio de mes (el último día y los tres primeros de cada mes) rinde menos que el resto en los cinco índices, aunque en ninguno con p < 0,05 (el menor, IDA, con 0,061). Separado por tramos, la diferencia casi desaparece en calma (ningún p baja de 0,12) y se concentra en los tramos de estrés, donde las sesiones de cambio de mes caen de media entre 35 y 45 puntos básicos, de 1,7 a 3,4 veces lo que caen las demás. Son unas pocas sesiones de crisis con caídas grandes, y varios tramos de estrés del guion empiezan el primer día de un mes. Cinco diferencias del mismo signo parecen una confirmación, pero con índices correlados en 0,81 son casi la misma prueba repetida cinco veces. Un artefacto de los datos con aspecto de efecto calendario: justo lo que hay que saber reconocer.

Lo que el carry exige en real

  • Ejecución y costes. La señal se conoce al cierre y la posición entra en la sesión siguiente. En divisas, la horquilla de las de tipo alto se abre justo en los crashes; en futuros, los contratos de precio bajo pagan mucho por tick, y cada roll es un coste fijo que el carry tiene que pagar (lección 2.4.7).
  • Financiación real. El diferencial que se cobra es el de los tipos a los que el bróker o el banco remunera y cobra, no el oficial. En un CFD o una cuenta de forex minorista, el rollover descuenta un margen sobre los dos tipos (lección 1.2.4) que puede comerse buena parte del carry.
  • Riesgo de cola. El resultado medio esconde una distribución con asimetría negativa. Una cartera de carry tiene que dimensionarse por su peor mes, no por su volatilidad, y conviene combinarla con estrategias que ganen en las crisis (la tendencia de la lección 2.3.1 lo hace en estos datos).
  • Concentración por sector y por nominal. El carry de futuros ordenado sin más es en parte una apuesta por sectores, y con pesos inversos a la volatilidad los bonos acaparan el nominal: en 2022, la cartera de la lección tenía de media el 135 % del capital en bonos. Neutralizar por sector (ejercicio 1) y limitar el nominal por sector cambian mucho la cartera.

Ejercicios

  1. Repite la cartera de carry en futuros ordenando el carry dentro de cada sector (resta la media del sector en cada fecha antes de ordenar). ¿Cambian el Sharpe y la asimetría?
Solución
IN [14]python
sector = spec["sector"].reindex(c_anual.columns)
c_rel = c_anual.loc[fin_f] - c_anual.loc[fin_f].T.groupby(
    sector).transform("mean").T
puesto_s = c_rel.rank(axis=1)
lado_s = ((puesto_s > n_f.to_numpy()[:, None] - 8).astype(float)
          - (puesto_s <= 8).astype(float))
pesos_s = (lado_s * 0.025 / vol.loc[fin_f]).fillna(0)
pesos_s = pesos_s.reindex(px.index, method="ffill").shift(1)
coste_s = (pesos_s.diff().abs() * coste_pb
           + 2 * pesos_s.abs() * coste_pb * roll) / 1e4
neto_s = ((pesos_s * r_fut).sum(axis=1)
          - coste_s.sum(axis=1))["2001":]
pd.DataFrame({"global": resumen(neto_f, 252),
              "por_sector": resumen(neto_s, 252)}).round(2)
OUT [14]Carry neutral por sector
                   global  por_sector
rent_anual_pct       5.71        2.33
vol_anual_pct       11.64        8.99
sharpe               0.49        0.26
asimetria_mensual    0.01        0.21
peor_mes_pct       -12.78       -7.17
max_dd_pct         -33.71      -34.07

Neutral por sector, el Sharpe baja de 0,49 a 0,26 y la rentabilidad, del 5,71 % al 2,33 % anual. Algo más de la mitad de la prima de estos datos está entre sectores: los carry exógenos medios son distintos (el gas en contango profundo, los bonos con carry positivo) y la cartera global los aprovecha. El resto está dentro de cada sector, donde el carry de cada mercado se mueve con su precio. Baja la volatilidad (del 11,64 % al 8,99 %) y el peor mes (del −12,78 % al −7,17 %), pero no la caída máxima (34,07 %), y la asimetría mensual pasa a ser positiva (0,21). En mercados reales, Koijen y coautores (2018) encuentran la prima del carry también dentro de cada clase de activo.

  1. En la cartera de carry en divisas, sube el coste a 10 puntos básicos por lado y cambia el rebalanceo a semanal (último día de cada semana). ¿Cuánto Sharpe se pierde en cada caso?
Solución
IN [15]python
def cartera_fx(fechas, coste):
    pt = dif.loc[fechas].rank(axis=1)
    pm = ((pt >= 8).astype(float) - (pt <= 3).astype(float)) / 3
    w = pm.reindex(spot.index, method="ffill").shift(1)
    giro = w.diff().abs().sum(axis=1)
    r = (w * r_fx).sum(axis=1) - coste / 1e4 * giro
    return r[w.abs().sum(axis=1) > 0]

fin_sem = (spot.index.to_series()
           .groupby(spot.index.to_period("W")).max())
casos = {"mensual, 3 pb": cartera_fx(fin_mes, 3),
         "mensual, 10 pb": cartera_fx(fin_mes, 10),
         "semanal, 3 pb": cartera_fx(fin_sem, 3),
         "semanal, 10 pb": cartera_fx(fin_sem, 10)}
pd.Series({k: resumen(v)["sharpe"] for k, v in casos.items()}).round(2)
OUT [15]Sensibilidad a costes y frecuencia
mensual, 3 pb     0.38
mensual, 10 pb    0.37
semanal, 3 pb     0.35
semanal, 10 pb    0.33
dtype: float64

El Sharpe apenas se mueve: de 0,38 a 0,37 con 10 puntos básicos, y a 0,35 o 0,33 con rebalanceo semanal. La cartera cambia de divisas tan pocas veces que los costes no la deciden; el rebalanceo semanal añade giro sin información nueva, porque los tipos solo cambian una vez al mes. En una estrategia de carry, la frecuencia natural es la de la señal: rebalancear más rápido que ella solo paga costes.

  1. Un compañero encuentra que IDA sube de media un 3 % en noviembre (t = 2,5) y propone comprar el índice solo ese mes. Explica qué falta antes de tomárselo en serio.
Solución

Es uno de doce meses probados en un índice, y el mismo contraste en los otros cuatro índices, que tienen una correlación de 0,8 con él, no es una prueba independiente: el número efectivo de contrastes es grande y uno con t = 2,5 es lo esperable por azar (con doce contrastes al 5 %, la probabilidad de al menos uno significativo es del 46 %). Un efecto mensual se mide con un dato por año: 26 noviembres, de los que uno o dos años de rebote tras una crisis bastan para mover la media. Falta una hipótesis previa con mecanismo, la corrección por pruebas múltiples (lección 2.1.8) y un contraste fuera de la muestra. En estos datos, además, se sabe la respuesta: el generador no planta ningún efecto calendario.

Footnotes

  1. Eduardo S. Schwartz, «The Stochastic Behavior of Commodity Prices: Implications for Valuation and Hedging», The Journal of Finance 52(3), 1997, https://doi.org/10.1111/j.1540-6261.1997.tb02721.x. ↩

Respuesta plegada en cada pregunta

Autoevaluación

  1. En la regresión de Fama de los datos, el cambio del tipo de cambio sobre el diferencial de tipos da una pendiente de −0,53 con un error típico de 0,36. ¿Qué concluyes?

    • AQue se cumple la paridad descubierta de tipos (pendiente −1)
    • BQue el tipo de cambio es un paseo aleatorio (pendiente 0)
    • CQue la regresión es demasiado imprecisa para separar −1, −0,3 y 0 con 21 años de datos; la rentabilidad de la cartera es una medida más directa
    • DQue el carry no gana dinero
    Ver respuesta

    Respuesta C. Que la regresión es demasiado imprecisa para separar −1, −0,3 y 0 con 21 años de datos; la rentabilidad de la cartera es una medida más directa

    Con un error típico de 0,36, el intervalo al 95 % va de −1,24 a +0,18: incluye la paridad (−1), la respuesta conocida (−0,3) y el paseo aleatorio (0). Los crashes, además, empujan la pendiente hacia valores más negativos. La regresión de Fama es la referencia académica, pero con diez divisas y veinte años no decide nada por sí sola.

  2. La cartera de carry en divisas tiene una asimetría mensual de −1,8. ¿Qué significa para quien la opera?

    • AQue gana poco y a menudo y pierde mucho de golpe: los peores meses coinciden con las huidas hacia la calidad
    • BQue pierde dinero casi todos los meses
    • CQue el Sharpe está sobrestimado por un error de cálculo
    • DQue sus rentabilidades son normales
    Ver respuesta

    Respuesta A. Que gana poco y a menudo y pierde mucho de golpe: los peores meses coinciden con las huidas hacia la calidad

    Una asimetría negativa grande es la firma del carry: el diferencial se cobra día a día y las divisas de tipo alto caen todas a la vez cuando el mercado busca refugio. En los datos, el último trimestre de 2008 y febrero de 2009 se llevan varios años de ganancias.

  3. Un futuro cotiza a 100 con vencimiento en 2 meses y el siguiente a 101 con vencimiento en 5 meses. ¿Cuál es su carry anual con la definición de la lección?

    • A+4 % (backwardation)
    • B+1 %
    • C0 %
    • D−4 % (contango: el largo pierde si la curva no cambia)
    Ver respuesta

    Respuesta D. −4 % (contango: el largo pierde si la curva no cambia)

    c = ln(100/101) / (5/12 − 2/12) = −0,00995 / 0,25 ≈ −4 % anual. La curva sube con el plazo (contango): si no se mueve, el contrato que se tiene pasa a valorarse en un plazo más corto, más barato, y el largo pierde ese 4 % anual.

  4. En cinco índices bursátiles se contrasta el efecto día de la semana: 25 contrastes y uno sale con p = 0,04. ¿Qué haces?

    • AOperar ese día
    • BNada: con 25 contrastes al 5 % se esperan 1,25 significativos por azar, y además los cinco índices tienen una correlación de 0,8, así que no son 25 pruebas independientes
    • CRepetir el contraste con más decimales
    • DQuitar los años malos y volver a probar
    Ver respuesta

    Respuesta B. Nada: con 25 contrastes al 5 % se esperan 1,25 significativos por azar, y además los cinco índices tienen una correlación de 0,8, así que no son 25 pruebas independientes

    Un único p = 0,04 entre 25 contrastes es justo lo que da el azar. En estos datos no hay ningún efecto calendario plantado: es el control. La corrección por pruebas múltiples (lección 2.1.8) lo deja muy lejos de cualquier umbral.

  5. ¿Qué parte del rendimiento de un bono a 10 años es roll-down?

    • AEl cupón
    • BEl cambio de los tipos del banco central
    • CLa ganancia de precio que se obtiene, con la curva sin cambios, porque el bono envejece y pasa a valorarse con el rendimiento más bajo de un plazo más corto
    • DLa diferencia entre el precio limpio y el sucio
    Ver respuesta

    Respuesta C. La ganancia de precio que se obtiene, con la curva sin cambios, porque el bono envejece y pasa a valorarse con el rendimiento más bajo de un plazo más corto

    Con una curva con pendiente positiva, un bono a 10 años es un año después un bono a 9 años. Si la curva no se mueve, su rendimiento baja del de 10 al de 9 años y su precio sube: eso es el roll-down. El cupón menos la financiación es el carry en sentido estricto.

Ideas clave

  • Carry es la rentabilidad de una posición si los precios no cambian: diferencial de tipos en divisas, pendiente de la curva en futuros, cupón menos financiación más roll-down en bonos.
  • En los datos, el carry de divisas gana el 70 % del diferencial (la respuesta conocida); la cartera de tres contra tres rinde un Sharpe de 0,38 neto de costes, con asimetría mensual de −1,85 y una caída máxima del 50 %.
  • La pendiente del rendimiento de los futuros sobre su carry sale 0,27 (error típico 0,13), menos que el 0,5 de la parte exógena: buena parte del carry es reversión a la media que la curva ya descuenta; con la tendencia en la regresión, baja a 0,17.
  • El carry pierde de golpe en las huidas hacia la calidad: el riesgo está en las colas, no en la volatilidad, y el Sharpe lo esconde.
  • La señal se calcula al cierre y la posición empieza en la sesión siguiente. La cartera de carry en futuros da un Sharpe neto de 0,49, pero negativo en 2020-2025: larga de bonos con pesos inversos a la volatilidad, pierde en 2022 cuando los bonos caen.
  • Los efectos calendario de los datos son el control: los pocos significativos que aparecen son los que da el azar entre decenas de contrastes correlados.

Recursos