Q09 · Carry de futuros por estructura temporal¶
| Campo | Valor |
|---|---|
| Familia | Carry: posicionarse según la pendiente de la curva de futuros (backwardation / contango) |
| Universo / panel | Familias de futuros con varios vencimientos por familia |
| Datos | Curvas por vencimiento, precios de contratos negociables, calendarios y multiplicadores, margen y moneda |
| Features | curve_alignment, annualized_carry, roll_schedule, volatility |
| Parámetros y defaults | rebalance_bars = 5, roll_sessions = 5, vol_window = 63 |
| Rejilla | rebalance_bars ∈ {1, 5, 21}, roll_sessions ∈ {5, 10, 20}, vol_window ∈ {20, 63} → 18 candidatos |
| Coste esperado | O(B·S) tras los joins de curvas |
| Estado | Especificada, no implementada (specified_not_implemented, hito H4); la matriz de capacidades da MISSING_DATA: no individual futures contracts |
| Motores implicados | Ninguno cubre curvas de futuros ni rolls. Reutilizaría el sizing por volatilidad de Q01 y el ledger, que necesitaría una extensión de contabilidad de futuros (margen, multiplicador, roll) |
Estado
Q09 no está implementada y, además, no hay datos para ella: la plataforma no tiene contratos de futuros individuales por vencimiento (solo series de acciones, índices y divisas). La matriz de capacidades de la API de backtesting la declara UNSUPPORTED con MISSING_DATA: no individual futures contracts. El ejemplo numérico es didáctico, calculado a mano con precios inventados.
Fuentes: catalog/strategy_catalog.json, finazbench/api/routers/capabilities.py, docs/API.md.
Qué vas a aprender¶
- Qué es la estructura temporal de un futuro y qué significan backwardation y contango.
- Cómo se calcula un carry anualizado con dos vencimientos consecutivos.
- Qué es un roll y por qué hay que pagar costes en las dos patas.
- Por qué no se puede construir la curva a partir de un único "futuro continuo".
- Qué le falta a la plataforma (datos y contabilidad) para ejecutarla.
La idea en una frase¶
Comprar los futuros cuya curva baja con el vencimiento (el precio lejano es menor que el cercano) y vender aquellos cuya curva sube, dimensionando por volatilidad y renovando la posición antes de cada vencimiento.
Intuición y evidencia académica¶
Intuición. Si el futuro a tres meses cotiza por debajo del de un mes, y la curva no cambia, el precio del contrato largo sube hacia el spot a medida que se acerca su vencimiento: quien está largo cobra esa convergencia. Es el "rendimiento de mantener" (carry). La literatura de carry en múltiples clases de activos (materias primas, divisas, bonos, índices) documenta una prima asociada a esta pendiente, con riesgo de caídas bruscas en crisis.
El catálogo es tajante: el carry no es un beneficio garantizado. La curva se mueve y la convergencia puede no ocurrir.
Cuándo falla.
- Cambios de curva: un contango que se profundiza borra el carry esperado.
- Crisis de liquidez: las posiciones de carry tienden a deshacerse a la vez.
- Rolls caros: en contratos poco líquidos, el coste de cambiar de vencimiento se come el carry.
El modelo matemático¶
Por familia, con dos vencimientos consecutivos elegibles (near y far), tiempos a vencimiento en años:
carry = ( ln F_near − ln F_far ) / ( tau_far − tau_near )
objetivo direccional = sign(carry)
peso = sign(carry) · min(cap_individual, vol_target / (S · max(vol, vol_floor))) (sizing de Q01)
se negocia el contrato near
carry > 0(backwardation: el lejano es más barato) → largo.carry < 0(contango) → corto.F <= 0hace la fórmula no evaluable: resultadono_evaluable_para_esta_formula, sin borrar la fila en silencio.
Roll: si el contrato near entra en la ventana de roll_sessions sesiones antes del vencimiento, se cierra y se abre el siguiente según el calendario fijado, pagando costes en las dos patas.
Pseudocódigo causal¶
para cada sesión t (tras el watermark de todas las curvas):
para cada familia:
elegir near y far elegibles con precios PUBLICADOS en t (timestamps de settlement)
carry, vol del contrato negociado
si near está a <= roll_sessions del vencimiento: programar roll near → siguiente
si t es rebalanceo: pesos por sizing de Q01; cantidades con multiplicador
ejecutar deltas y rolls en el siguiente evento negociable; margen y moneda en el ledger
Cómo lo haría la plataforma¶
| Pieza | Quién la cubriría | Estado |
|---|---|---|
| Curvas por vencimiento | Nueva fuente de datos con contratos individuales | No existe (MISSING_DATA) |
| Calendario de vencimientos y rolls | finaz_calendars + tabla de vencimientos por familia |
Calendarios de sesión existen; vencimientos, no |
| Instrumentos con multiplicador | finaz_instruments / catalog/instruments.json (tick, lote, multiplicador, moneda) |
Existe para contado; no para futuros por vencimiento |
| Sizing por volatilidad | Fórmula de Q01 (finazbench/policy/q01_tsmom.py) |
Existe |
| Volatilidad de cartera | finaz_risk.volatilidad_cartera, anualizar_volatilidad |
Existe |
| Lotes enteros de contratos | finaz_discrete.proyectar_cpsat (tamaños de lote arbitrarios) |
Existe |
| Contabilidad de futuros (margen, variación diaria, roll) | Extensión del ledger en ambos adaptadores | No existe |
flowchart LR
D["Curvas por vencimiento<br/>(sin datos: MISSING_DATA)"] --> A["curve_alignment<br/>near / far elegibles"]
A --> C["annualized_carry<br/>(ln F_near − ln F_far)/(tau_far − tau_near)"]
C --> S["sign(carry)"]
V["Volatilidad del contrato<br/>vol_window 63"] --> W
S --> W["Sizing de Q01<br/>vol_target · caps"]
W --> X["finaz_discrete<br/>contratos enteros"]
R["roll_schedule<br/>5 sesiones"] --> L
X --> L["Ledger con contabilidad de futuros<br/>(no implementada)"]
Ejemplo numérico¶
Ejemplo didáctico
Precios, vencimientos y volatilidad inventados. No hay datos de futuros en la plataforma.
Una familia, dos vencimientos.
F_near = 80.00 tau_near = 0.10 años (≈ 5 semanas)
F_far = 78.00 tau_far = 0.35 años (≈ 4 meses)
ln F_near = 4.382027 ln F_far = 4.356709
carry = (4.382027 − 4.356709) / (0.35 − 0.10) = 0.025318 / 0.25 = 0.1013 (10,1 % anual)
carry > 0 → backwardation → objetivo +1 (largo el near)
Sizing con los parámetros de Q01 (vol_target = 0.10, cap_individual = 0.25, vol_floor = 0.02), una sola familia (S = 1) y volatilidad anual del contrato del 30 %:
Cantidad con capital 1.000.000 y multiplicador 1.000 (nocional por contrato 80 · 1000 = 80.000):
Roll. Cinco sesiones antes del vencimiento del near se venden los 3 contratos near y se compran 3 del siguiente vencimiento. Si cada pata paga 2 ticks de 0,01 con multiplicador 1.000, el roll cuesta 3 · 2 · 2 · 0,01 · 1.000 = 120 por cada roll, que hay que restar del carry cobrado.
Contango (contraejemplo): con F_near = 78 y F_far = 80, el carry sería −0,1013 y el objetivo −1 (corto el near).
Cómo lanzarla¶
Hoy no se puede lanzar. Lo que devuelve la API de backtesting:
GET /v1/capabilities
{ "template_id": "Q09", "VTA_CPU_LEDGER": "UNSUPPORTED", "NT_FEATURES": "UNSUPPORTED",
"NT_INTENT_REPLAY": "UNSUPPORTED", "NT_ONLINE": "UNSUPPORTED",
"unsupported_reason": "MISSING_DATA: no individual futures contracts." }
POST /v1/backtest con una instancia de Q09 → 501 STRATEGY_UNSUPPORTED_BY_ADAPTER
Tampoco hay un job S7 que cubra su pieza central (la curva). Las piezas reutilizables (sizing, volatilidad, discretización) se pueden ejercitar con los jobs de las imágenes opt y con la propia Q01, como se explica en Q01 y Q06.
Qué haría falta para implementarla¶
- Datos: contratos individuales por vencimiento con timestamps de publicación y de settlement, multiplicador, tick, moneda y fecha de vencimiento. La receta prohíbe derivar la curva de un único futuro continuo.
- Calendario de rolls fijado y versionado por familia.
- Contabilidad de futuros en el ledger de cartera y en los carriles Nautilus: margen, liquidación diaria, conversión de moneda, roll con dos patas.
- Política con sizing de Q01 y paridad.
- Declarar que datos sintéticos validan el software, no la rentabilidad.
Riesgos, límites y qué no hace¶
- Sin datos en la plataforma: es la receta más lejana a la ejecución junto con Q10.
- No suma el carry como beneficio garantizado: el resultado depende de cómo se mueva la curva.
- Timestamps: usar un precio de settlement antes de su publicación es una fuga.
- Precio no positivo:
lnno está definido; se marcano_evaluable_para_esta_formula. - Margen y apalancamiento: un futuro requiere solo una fracción del nocional como margen; el sizing es sobre el nocional, no sobre el margen.
Resumen¶
- Carry anualizado
(ln F_near − ln F_far) / (tau_far − tau_near); objetivosign(carry)con sizing de Q01. - Se negocia el near y se rueda
roll_sessionssesiones antes del vencimiento, con costes en ambas patas. - Especificada, no implementada y sin datos (
MISSING_DATA). - La plataforma aporta el sizing, la volatilidad y la discretización; faltan curvas y contabilidad de futuros.
Para practicar¶
- Calcula el carry con
F_near = 100,F_far = 97,tau_near = 0.05,tau_far = 0.30. ¿Largo o corto? - ¿Por qué no se puede calcular el carry con una serie de "futuro continuo" ajustada por rolls?
- Si el carry anual es 10 % y cada roll cuesta el 0,3 % del nocional, ¿cuántos rolls al año se pueden permitir antes de que el carry neto sea negativo?
- Explica la diferencia entre el peso sobre nocional y el margen exigido.