---
title: "3.5.1 Opciones direccionales y verticales"
description: "Call y put compradas, covered call, protective put, collar y verticales de débito y crédito, al bid/ask sobre la cadena y con doce años de historia."
url: "https://pythonparatrading.com/curso-python-trading/nivel-3/opciones-direccionales-y-verticales/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-3/opciones-direccionales-y-verticales.png"
---

# 3.5.1 · Estructuras direccionales y verticales: call, put, covered call, collar y spreads

> Una estructura de opciones es una suma de patas, y todo lo que importa de ella sale de esa suma: lo que cuesta abrirla, lo que puede ganar o perder, dónde están sus puntos muertos y cómo responde al precio, al tiempo y a la volatilidad. Esta lección construye las estructuras direccionales y las verticales con la cadena sintética del índice ORX y las sigue durante 143 vencimientos.

- Curso: [Nivel 3: Derivados: futuros, spreads, forex y opciones](https://pythonparatrading.com/curso-python-trading/nivel-3/)
- Módulo: 3.5 · Estructuras de opciones en Python
- Duración: 75 min
- Requisitos: [3.4.1 · Payoffs, paridad put-call y límites de arbitraje](https://pythonparatrading.com/curso-python-trading/nivel-3/payoffs-paridad-put-call-y-limites-de-arbitraje/), [3.4.2 · Árboles binomiales, Black-Scholes-Merton, Black-76 y Monte Carlo](https://pythonparatrading.com/curso-python-trading/nivel-3/binomial-black-scholes-black-76-y-monte-carlo/), [3.4.3 · Griegas: delta, gamma, vega, theta, rho, vanna, volga y charm](https://pythonparatrading.com/curso-python-trading/nivel-3/griegas-de-primer-y-segundo-orden/)

## Al terminar esta lección

- Representar una estructura como una lista de patas y calcular su coste de apertura al medio y cruzando la horquilla (compras al ask, ventas al bid).
- Obtener el máximo, el mínimo y los puntos muertos al vencimiento, y el P&L antes del vencimiento con BSM y la volatilidad implícita de cada pata.
- Agregar las griegas de una estructura con sus unidades (theta por día natural, vega por punto de volatilidad, por unidad y por contrato) y contrastarlas con QuantLib.
- Distinguir covered call, protective put y collar, y verticales de débito y de crédito, por su riesgo real y no por el signo de la prima.
- Medir el comportamiento histórico de cada estructura con entradas mensuales y su peor episodio.

## Una estructura es una suma de patas

Una call comprada es una apuesta direccional con la pérdida limitada a la prima. Casi todo lo demás que se hace con
opciones son combinaciones: una call comprada y otra vendida de strike mayor, una acción con una call vendida encima,
una put comprada para poner un suelo. En el módulo 3.4 se valoró cada opción por separado; este módulo las junta. La
idea que hace manejable cualquier estructura es la linealidad: el payoff, el valor antes del vencimiento y cada griega
de una estructura son la suma de los de sus patas, cada una con su signo (comprada o vendida) y su cantidad.

$$
V_{\text{estructura}}(S, t) = \sum_i n_i \, V_i(S, t), \qquad
\Delta_{\text{estructura}} = \sum_i n_i \, \Delta_i, \quad \ldots
$$

Las estructuras de esta lección se agrupan por lo que necesitan que pase:

```mermaid
flowchart LR
  V[Visión] --> A[Alcista]
  V --> B[Bajista]
  V --> C[Ya tengo el índice]
  A --> A1[Call comprada]
  A --> A2[Bull call o put]
  B --> B1[Put comprada]
  B --> B2[Bear put o call]
  C --> C1[Covered call]
  C --> C2[Protective put]
  C --> C3[Collar]
```

- **Direccionales simples**: una call o una put compradas. Riesgo limitado a la prima, ganancia sin tope (la put, hasta
  que el índice llega a cero).
- **Sobre el subyacente**: el índice (en la práctica, un ETF o un futuro que lo replica) con una opción encima. La
  **covered call** vende una call y cambia la subida por encima del strike por una prima; la **protective put** compra
  una put y paga por un suelo; el **collar** hace las dos cosas y usa la prima de la call para pagar la put.
- **Verticales**: dos opciones del mismo tipo y vencimiento con strikes distintos, una comprada y otra vendida. Acotan
  la ganancia y la pérdida. Según qué pata sea más cara, se abren con **débito** (se paga) o con **crédito** (se cobra).

El resto del módulo sigue la misma plantilla con estructuras de volatilidad (3.5.2) y de varios vencimientos (3.5.3);
la lección 3.5.4 reúne estas funciones en una herramienta y la 3.5.5 trata la gestión de las posiciones abiertas.

## La cadena del 31 de diciembre de 2025

Los datos son la cadena diaria del índice ficticio **ORX** (`opciones3_cadena.parquet`), que imita a las opciones SPX:
europeas, liquidación en efectivo, multiplicador de 100 USD por punto (el mismo que el de las SPX según la ficha de
Cboe), tres vencimientos mensuales listados cada día. Son datos sintéticos con una superficie de volatilidad conocida y
una prima de riesgo de volatilidad plantada (la implícita cotiza de media por encima de la volatilidad que se realiza
después); nada de lo que se mida aquí es evidencia de que una estructura funcione en el mercado real.

Antes de valorar nada conviene fijar las convenciones, porque cada librería y cada bróker usan las suyas:

| Magnitud | Convención de la lección |
|---|---|
| Precio de la opción | En puntos de índice por unidad; por contrato, × 100 USD |
| Plazo T | Días naturales hasta el vencimiento / 365 (las opciones vencen al cierre) |
| Tipo r | Continuo, en tanto por uno, de la curva interpolada en T (`tipo_libre` de `opciones3_verdad`) |
| Dividendo q | Rendimiento continuo, implícito en el forward: q = r − ln(F/S)/T |
| Volatilidad $\sigma$ | Anual, en tanto por uno (0,1258 = 12,58 %) |
| Delta | Puntos de opción por punto de índice; por contrato, × 100 = USD por punto |
| Gamma | Cambio de delta por punto de índice |
| Vega | Puntos de opción por punto de volatilidad ($\sigma$ de 0,1258 a 0,1358) |
| Theta | Puntos de opción por día natural |

```python
import numpy as np
import pandas as pd
from scipy.stats import norm

cadena = pd.read_parquet("opciones3_cadena.parquet")
indice = pd.read_csv("opciones3_indice.csv", parse_dates=["fecha"],
                     index_col="fecha")
verdad = pd.read_parquet("opciones3_verdad.parquet")

HOY = pd.Timestamp("2025-12-31")
VTO = pd.Timestamp("2026-02-20")
S0 = indice.loc[HOY, "cierre"]


def mercado(vto, fecha=HOY):
    """Tipo r y dividendo q continuos (tanto por uno) de un
    vencimiento: r de la curva; q implícito en el forward."""
    v = verdad[(verdad.fecha == fecha)
               & (verdad.vencimiento == vto)].iloc[0]
    T = v.dias / 365                   # días naturales / 365
    S = indice.loc[fecha, "cierre"]
    return v.tipo_libre, v.tipo_libre - np.log(v.forward / S) / T


r, q = mercado(VTO)
dias = (VTO - HOY).days
print(f"ORX {S0}  días {dias}  r {r:.4f}  q {q:.4f}")
print("q publicada:", indice.loc[HOY, "rentabilidad_dividendo"] / 100)
```
```output
ORX 6089.45  días 51  r 0.0368  q 0.0117
q publicada: 0.011732
```

El índice cierra en 6.089,45 y el vencimiento de febrero queda a 51 días naturales. El dividendo implícito en el
forward (0,0117) coincide con la rentabilidad por dividendo publicada en `opciones3_indice.csv` (1,1732 % anual): el
forward de la verdad se construyó con ella, así que las dos vías dan lo mismo. En una cadena real no existe esa
columna de verdad y q (o directamente el forward) se saca de la paridad put-call de los medios (lección 3.4.1).

La valoración es la de Black-Scholes-Merton con dividendo continuo de la lección 3.4.2, con las griegas analíticas de
la 3.4.3, escritas para que acepten un vector de precios del índice (lo que hace falta para dibujar un payoff) y para
que, con plazo cero, devuelvan el valor al vencimiento:

```python
def bsm(S, K, T, sig, tipo, r, q):
    """Precio (puntos), delta, gamma (por punto), vega (por
    punto de volatilidad) y theta (por día natural).
    S puede ser un array; con T = 0 devuelve el payoff."""
    S = np.asarray(S, dtype=float)
    if T <= 0:
        pago = np.maximum(S - K, 0) if tipo == "C" else \
            np.maximum(K - S, 0)
        signo = 1.0 if tipo == "C" else -1.0
        delta = np.where(signo * (S - K) > 0, signo, 0.0)
        cero = np.zeros_like(S)
        return dict(precio=pago, delta=delta, gamma=cero,
                    vega=cero, theta=cero)
    raiz = sig * np.sqrt(T)
    d1 = (np.log(S / K) + (r - q + sig**2 / 2) * T) / raiz
    d2 = d1 - raiz
    dq, dr = np.exp(-q * T), np.exp(-r * T)
    gamma = dq * norm.pdf(d1) / (S * raiz)
    vega = S * dq * norm.pdf(d1) * np.sqrt(T)
    decay = -S * dq * norm.pdf(d1) * sig / (2 * np.sqrt(T))
    if tipo == "C":
        precio = S * dq * norm.cdf(d1) - K * dr * norm.cdf(d2)
        delta = dq * norm.cdf(d1)
        theta = (decay - r * K * dr * norm.cdf(d2)
                 + q * S * dq * norm.cdf(d1))
    else:
        precio = K * dr * norm.cdf(-d2) - S * dq * norm.cdf(-d1)
        delta = -dq * norm.cdf(-d1)
        theta = (decay + r * K * dr * norm.cdf(-d2)
                 - q * S * dq * norm.cdf(-d1))
    return dict(precio=precio, delta=delta, gamma=gamma,
                vega=vega / 100, theta=theta / 365)


fila = cadena[(cadena.fecha == HOY) & (cadena.vencimiento == VTO)
              & (cadena.tipo == "C") & (cadena.strike == 6100)]
fila = fila.iloc[0]
g = bsm(S0, 6100, dias / 365, fila.iv_modelo, "C", r, q)
print(f"bid {fila.bid}  ask {fila.ask}  iv {fila.iv_modelo}")
{k: round(float(x), 4) for k, x in g.items()}
```
```output
bid 118.8  ask 119.8  iv 0.1258
{'precio': 119.3813, 'delta': 0.5235, 'gamma': 0.0014, 'vega': 9.0491, 'theta': -1.3226}
```

La call 6.100 cotiza a 118,8-119,8 y BSM con su volatilidad implícita da 119,38, dentro de la horquilla. La columna
`iv_modelo` de los datos es la implícita verdadera, sin ruido; en una cadena real se calcula invirtiendo el medio
(lección 3.4.4) y la diferencia es pequeña frente a la horquilla. Las griegas, con las unidades de la tabla: delta
0,5235 (52 USD por punto y contrato), vega 9,05 puntos por punto de volatilidad (905 USD por contrato) y theta −1,32
puntos por día natural (132 USD diarios por contrato). La comprobación con QuantLib, con curvas planas al mismo r y q y
el mismo calendario Actual/365, coincide en las cuatro cifras decimales; `vega()` de QuantLib es por unidad de
volatilidad (hay que dividir entre 100) y `thetaPerDay()` divide la theta anual entre 365:

```python
import QuantLib as ql

hoy = ql.Date(31, 12, 2025)
ql.Settings.instance().evaluationDate = hoy
dc = ql.Actual365Fixed()
proceso = ql.BlackScholesMertonProcess(
    ql.QuoteHandle(ql.SimpleQuote(S0)),
    ql.YieldTermStructureHandle(ql.FlatForward(hoy, q, dc)),
    ql.YieldTermStructureHandle(ql.FlatForward(hoy, r, dc)),
    ql.BlackVolTermStructureHandle(
        ql.BlackConstantVol(hoy, ql.TARGET(), fila.iv_modelo, dc)))
opcion = ql.EuropeanOption(
    ql.PlainVanillaPayoff(ql.Option.Call, 6100),
    ql.EuropeanExercise(ql.Date(20, 2, 2026)))
opcion.setPricingEngine(ql.AnalyticEuropeanEngine(proceso))
print(f"precio {opcion.NPV():.4f}  delta {opcion.delta():.4f}"
      f"  gamma {opcion.gamma():.4f}")
print(f"vega/100 {opcion.vega() / 100:.4f}"
      f"  theta/día {opcion.thetaPerDay():.4f}")
```
```output
precio 119.3813  delta 0.5235  gamma 0.0014
vega/100 9.0491  theta/día -1.3226
```

## Patas, apertura y valoración

Una pata es un diccionario con el tipo, el strike, la cantidad (positiva comprada, negativa vendida), el bid y el ask
del día, la volatilidad implícita, el vencimiento y su r y su q. El índice se representa como una pata más, de tipo
`"S"`, con delta 1 y sin opcionalidad. Con eso bastan tres funciones:

- `apertura`: lo que cuesta abrir la estructura, al medio y **cruzando la horquilla** (cada compra al ask, cada venta al
  bid). Esta segunda cifra es la que cuenta: es la que pagaría una orden que se ejecuta ya. Un precio positivo es un
  débito; uno negativo, un crédito.
- `valor`: el valor de la estructura (o cualquiera de sus griegas) si el índice valiera `S` en una fecha. Para fechas
  anteriores al vencimiento supone que la volatilidad implícita de cada pata no cambia (*sticky strike*); qué pasa
  cuando sí cambia se ve en la 3.5.3 y, con escenarios de precio × volatilidad × tiempo, en la 3.5.4.
- `resumen`: el P&L al vencimiento sobre una rejilla de 1 a 3 veces el índice, con el máximo, el mínimo y los puntos
  muertos (los cruces por cero, interpolados). Si la pendiente al final de la rejilla no es cero, el máximo o el mínimo
  son ilimitados.

```python
def pata(tipo, K, n, vto=VTO, fecha=HOY):
    """Una pata: n > 0 comprada, n < 0 vendida. tipo "S" es
    el propio índice (una cartera que lo replica)."""
    if tipo == "S":
        return dict(tipo="S", K=0.0, n=n, bid=S0, ask=S0,
                    iv=0.0, vto=vto, r=0.0, q=0.0)
    o = cadena[(cadena.fecha == fecha)
               & (cadena.vencimiento == vto)
               & (cadena.tipo == tipo)
               & (cadena.strike == K)].iloc[0]
    rr, qq = mercado(vto, fecha)
    return dict(tipo=tipo, K=K, n=n, bid=o.bid, ask=o.ask,
                iv=o.iv_modelo, vto=vto, r=rr, q=qq)


def apertura(patas):
    """Coste en puntos al medio y al cruzar la horquilla:
    las compradas al ask, las vendidas al bid (> 0 = débito)."""
    medio = sum(p["n"] * (p["bid"] + p["ask"]) / 2 for p in patas)
    real = sum(p["n"] * (p["ask"] if p["n"] > 0 else p["bid"])
               for p in patas)
    return medio, real


def valor(patas, S, fecha, griega="precio"):
    """Valor (o griega) de la estructura si el índice vale S
    en `fecha`, con la IV de cada pata congelada."""
    S = np.asarray(S, dtype=float)
    total = np.zeros_like(S)
    for p in patas:
        if p["tipo"] == "S":
            x = {"precio": S, "delta": np.ones_like(S)}
            total += p["n"] * x.get(griega, np.zeros_like(S))
            continue
        T = (p["vto"] - fecha).days / 365
        g = bsm(S, p["K"], T, p["iv"], p["tipo"], p["r"], p["q"])
        total += p["n"] * g[griega]
    return total
```

```python
REJILLA = np.arange(1.0, 3 * S0, 1.0)   # de 1 punto a 3 veces S0


def resumen(patas):
    """Coste, máximo, mínimo y puntos muertos al vencimiento
    (el primero de la estructura), en puntos por unidad."""
    medio, real = apertura(patas)
    fin = min(p["vto"] for p in patas)
    pnl = valor(patas, REJILLA, fin) - real
    i = np.nonzero(np.diff(np.sign(pnl)))[0]
    muertos = REJILLA[i] - pnl[i] / (pnl[i + 1] - pnl[i])
    muertos = np.unique(np.round(muertos, 1))
    final = pnl[-1] - pnl[-2]          # pendiente hacia S grande
    return {"medio": round(float(medio), 2),
            "real": round(float(real), 2),
            "horquilla": round(float(real - medio), 2),
            "maximo": "ilimitado" if final > 1e-9
            else round(float(pnl.max()), 2),
            "minimo": "ilimitado" if final < -1e-9
            else round(float(pnl.min()), 2),
            "muertos": [round(float(x), 1) for x in muertos]}


def griegas(patas, S=S0, fecha=HOY):
    """Griegas agregadas por unidad (× 100 USD por contrato)."""
    g = {k: float(valor(patas, S, fecha, k))
         for k in ["delta", "gamma", "vega", "theta"]}
    return {"delta": round(g["delta"], 3),
            "gamma": round(g["gamma"], 5),
            "vega": round(g["vega"], 2),
            "theta": round(g["theta"], 2)}


call = [pata("C", 6100, 1)]
put = [pata("P", 6100, 1)]
for nombre, e in [("call 6100", call), ("put 6100", put)]:
    print(nombre, resumen(e))
    print("   ", griegas(e))
```
```output
call 6100 {'medio': 119.3, 'real': 119.8, 'horquilla': 0.5, 'maximo': 'ilimitado', 'minimo': -119.8, 'muertos': [6219.8]}
    {'delta': 0.523, 'gamma': 0.00139, 'vega': 9.05, 'theta': -1.32}
put 6100 {'medio': 108.8, 'real': 109.3, 'horquilla': 0.5, 'maximo': 5989.7, 'minimo': -109.3, 'muertos': [5990.7]}
    {'delta': -0.475, 'gamma': 0.00139, 'vega': 9.05, 'theta': -0.91}
```

La call comprada cuesta 119,8 al ask (medio punto más que al medio) y esa es su pérdida máxima; su punto muerto es el
strike más lo pagado, 6.219,8, un 2,1 % por encima del índice. La put cuesta 109,3 y su punto muerto está en 5.990,7;
su ganancia máxima no es ilimitada sino el strike menos la prima si el índice fuera a cero (la rejilla empieza en 1
punto, de ahí el 5.989,7). Las dos tienen la misma gamma y la misma vega (es la paridad: call − put es lineal en S) y
deltas que se separan exactamente en $e^{-qT}$: 0,523 − (−0,475) = 0,998. La theta de la put (−0,91) es menor en valor
absoluto que la de la call (−1,32) porque con r > q el término de financiación juega a su favor.

## El P&L antes del vencimiento

El payoff al vencimiento es una línea quebrada; antes, la estructura vale el payoff más el valor temporal, y la curva
es suave. La figura de la cabecera muestra las tres curvas del bull call spread de la sección siguiente; con la call
sola se ve en una tabla:

```python
coste = apertura(call)[1]
S = np.array([5700.0, 5900, 6100, 6300, 6500])
antes = pd.DataFrame({
    "hoy": valor(call, S, HOY) - coste,
    "en 25 días": valor(call, S, HOY + pd.Timedelta(days=25))
    - coste,
    "vencimiento": valor(call, S, VTO) - coste}, index=S)
antes.index.name = "ORX"
antes.round(1)
```
```output
          hoy  en 25 días  vencimiento
ORX
5700.0 -108.9      -118.0       -119.8
5900.0  -75.0      -101.0       -119.8
6100.0    5.2       -32.7       -119.8
6300.0  138.5       107.7         80.2
6500.0  311.0       292.8        280.2
```

Con el índice en 6.100 la call ganaría 5,2 puntos hoy (está a 10 puntos de S0 y su delta es 0,52), perdería 32,7 si se
llega a mediados de enero en el mismo nivel y perdería toda la prima al vencimiento. Esa diferencia es la theta
acumulada: en 25 días se pierden 38 puntos a precio constante, algo más de lo que dice 25 × 1,32 porque la theta de una
opción en el dinero crece a medida que se acerca el vencimiento (lección 1.2.5). En 6.300 la call gana 138,5 hoy y 80,2
al vencimiento: subir rápido vale más que subir tarde.

## Covered call, protective put y collar

Con el índice en cartera hay tres estructuras clásicas. Los strikes se eligen por delta (la convención de los
operadores: una call de «25 delta», 25D en las tablas), con una función que añade a la cadena la delta BSM de cada fila. Con una
separación de 100 puntos entre strikes, la delta que se obtiene es la más cercana a la buscada, no la exacta:

```python
def con_delta(fecha=HOY, vto=VTO):
    """La cadena de un vencimiento con la delta BSM de cada fila."""
    d = cadena[(cadena.fecha == fecha)
               & (cadena.vencimiento == vto)].copy()
    rr, qq = mercado(vto, fecha)
    S, T = indice.loc[fecha, "cierre"], (vto - fecha).days / 365
    for t in ("C", "P"):
        m = d.tipo == t
        d.loc[m, "delta"] = bsm(S, d.strike[m].to_numpy(), T,
                                d.iv_modelo[m].to_numpy(), t,
                                rr, qq)["delta"]
    return d


def strike_delta(d, tipo, objetivo):
    x = d[d.tipo == tipo]
    return float(x.strike.iloc[(x.delta - objetivo).abs().argmin()])


hoy = con_delta()
for t, obj in [("C", 0.25), ("P", -0.25), ("P", -0.10)]:
    k = strike_delta(hoy, t, obj)
    fila = hoy[(hoy.tipo == t) & (hoy.strike == k)].iloc[0]
    print(t, obj, "->", k, f"delta {fila.delta:.3f}",
          f"bid {fila.bid} ask {fila.ask}")
```
```output
C 0.25 -> 6300.0 delta 0.214 bid 27.1 ask 27.7
P -0.25 -> 5900.0 delta -0.261 bid 56.5 ask 57.3
P -0.1 -> 5600.0 delta -0.105 bid 22.5 ask 22.9
```

La call de 25D es la 6.300 (delta 0,214, a un 3,5 % del índice) y la put de 25D es la 5.900 (−0,261, a un 3,1 %).
Las dos alas no están a la misma distancia aunque tengan la misma delta: la sonrisa del índice tiene skew (la
volatilidad de la put 5.900 es mayor que la de la call 6.300), y la deriva r − q mueve el forward hacia arriba.

```python
cubierta = [pata("S", 0, 1), pata("C", 6300, -1)]
protegida = [pata("S", 0, 1), pata("P", 5900, 1)]
collar = [pata("S", 0, 1), pata("P", 5900, 1), pata("C", 6300, -1)]
for nombre, e in [("covered call", cubierta),
                  ("protective put", protegida), ("collar", collar)]:
    res = resumen(e)
    res["real"] = round(float(res["real"] - S0), 2)  # sin S0
    res["medio"] = round(float(res["medio"] - S0), 2)
    print(nombre, res)
    print("   ", griegas(e))
```
```output
covered call {'medio': -27.4, 'real': -27.1, 'horquilla': 0.3, 'maximo': 237.65, 'minimo': -6061.35, 'muertos': [6062.3]}
    {'delta': 0.786, 'gamma': -0.00127, 'vega': -6.63, 'theta': 0.74}
protective put {'medio': 56.9, 'real': 57.3, 'horquilla': 0.4, 'maximo': 'ilimitado', 'minimo': -246.75, 'muertos': [6146.8]}
    {'delta': 0.739, 'gamma': 0.00093, 'vega': 7.39, 'theta': -1.0}
collar {'medio': 29.5, 'real': 30.2, 'horquilla': 0.7, 'maximo': 180.35, 'minimo': -219.65, 'muertos': [6119.6]}
    {'delta': 0.525, 'gamma': -0.00034, 'vega': 0.76, 'theta': -0.26}
```

*Fig. — Índice solo, covered call 6.300, protective put 5.900 y collar 5.900/6.300 de febrero de 2026: P&L al vencimiento con la apertura al bid y al ask.* Cuatro líneas de P&L frente al ORX al vencimiento, de 5.400 a 6.800. El índice solo es una recta. La covered call sigue al índice por abajo y se aplana por encima de 6.300. La protective put se aplana por debajo de 5.900 en un suelo de -247 puntos y sigue al índice por arriba, algo por debajo. El collar, destacado, queda acotado por los dos lados.

- **Covered call 6.300.** Se cobran 27,1 puntos (al bid). La ganancia queda topada en 237,65 (los 210,55 puntos hasta
  el strike más la prima); por debajo, se pierde lo mismo que con el índice menos 27,1. El punto muerto baja de 6.089,45
  a 6.062,3, un 0,4 %. Sus griegas lo dicen todo: delta 0,786 (menos que el índice solo), gamma y vega negativas y theta
  positiva (+0,74 puntos al día). Es una posición corta en volatilidad.
- **Protective put 5.900.** Se pagan 57,3. Por debajo de 5.900 la pérdida se queda en un suelo de 246,75 puntos (un
  4,1 % del índice: los 189,45 hasta el strike más la prima); por encima, se gana como el índice menos 57,3. Es una
  posición larga en volatilidad: gamma y vega positivas, theta de −1,0.
- **Collar 5.900/6.300.** Las dos cosas a la vez. Cuesta 30,2 puntos (57,3 − 27,1), pierde como mucho 219,65 y gana como
  mucho 180,35. La vega casi desaparece (0,76): la put comprada y la call vendida se compensan.

La paridad put-call ordena las tres. Como $C - P = e^{-qT}S - e^{-rT}K$, el índice más una call vendida es, con el mismo
strike, una put vendida más un bono: la covered call es una venta de put con otro nombre. Del mismo modo, el índice más
una put comprada es una call comprada más un bono, y el collar es un bull spread más un bono:

```mermaid
flowchart LR
  CC[Covered call] --- PV[Put corta + bono]
  PP[Protective put] --- CCo[Call larga + bono]
  CO[Collar] --- BS[Vertical + bono]
```

<aside class="callout" data-kind="nota">

La pata del índice de los diagramas no cobra dividendos: con q = 1,17 % anual, en 51 días son unos 10 puntos por unidad
que mejoran todas las estructuras con el índice en cartera. En la historia de más abajo se incluyen (el índice de
rentabilidad total, `cierre_rt`). En la práctica la pata «índice» es un ETF (con su propia horquilla y comisiones) o un
futuro (que no paga dividendos pero los descuenta en su precio, lección 3.1.2).

</aside>

Un **collar de coste cero** es el que elige la call para que su bid pague el ask de la put:

```python
puts = hoy[(hoy.tipo == "P") & (hoy.strike == 5900)].iloc[0]
calls = hoy[hoy.tipo == "C"].set_index("strike")
print("ask de la put 5900:", puts.ask)
calls.loc[6200:6600, ["bid", "ask", "delta"]].round(3)
```
```output
ask de la put 5900: 57.3
          bid    ask  delta
strike
6200.0  63.60  64.50  0.372
6300.0  27.10  27.70  0.214
6400.0   9.30   9.70  0.096
6600.0   0.85   0.95  0.013
```

La put 5.900 cuesta 57,3. La call 6.300 solo paga 27,1; la 6.200 paga 63,6. Un collar 5.900/6.200 se abre con un
crédito de 6,3 puntos: protege por debajo de un 3,1 % de caída a cambio de renunciar a todo lo que pase de un 1,8 % de
subida. El skew es lo que encarece la protección: a la misma distancia, la put cuesta más que la call, y para pagarla
hay que vender una call más cercana.

## Verticales: débito y crédito

Un vertical alcista se puede montar con calls (comprar la de strike bajo, vender la de strike alto: se paga) o con puts
(comprar la de strike bajo, vender la de strike alto: se cobra). Con los mismos strikes, los dos pagan lo mismo al
vencimiento salvo una constante: el bull put es el bull call menos el ancho, $K_2 - K_1$.

```python
bull_call = [pata("C", 6100, 1), pata("C", 6300, -1)]
bull_put = [pata("P", 6100, 1), pata("P", 6300, -1)]
for nombre, e in [("bull call 6100/6300", bull_call),
                  ("bull put 6100/6300", bull_put)]:
    print(nombre, resumen(e))
    print("   ", griegas(e))
ancho = 200 * np.exp(-r * dias / 365)
m_call, m_put = apertura(bull_call)[0], apertura(bull_put)[0]
print(f"paridad: débito {m_call:.2f}"
      f"  ancho descontado − crédito {ancho + m_put:.2f}")
```
```output
bull call 6100/6300 {'medio': 91.9, 'real': 92.7, 'horquilla': 0.8, 'maximo': 107.3, 'minimo': -92.7, 'muertos': [6192.7]}
    {'delta': 0.309, 'gamma': 0.00012, 'vega': 2.42, 'theta': -0.58}
bull put 6100/6300 {'medio': -106.9, 'real': -105.7, 'horquilla': 1.2, 'maximo': 105.7, 'minimo': -94.3, 'muertos': [6194.3]}
    {'delta': 0.309, 'gamma': 0.00012, 'vega': 2.42, 'theta': -0.6}
paridad: débito 91.90  ancho descontado − crédito 92.08
```

Los dos verticales 6.100/6.300 tienen las mismas griegas (delta 0,309, vega 2,42; la theta difiere en 0,02 por la
financiación de la put dentro del dinero) y casi el mismo perfil: el de calls cuesta 92,7 y gana como mucho 107,3; el
de puts cobra 105,7, gana como mucho eso y pierde como mucho 94,3. La paridad se cumple al medio: el débito de las
calls (91,90) es el ancho descontado menos el crédito de las puts (92,08), con una diferencia de 0,18 puntos, dentro de
las horquillas. Que uno «cobre» y el otro «pague» es contabilidad: quien vende el bull put no recibe un regalo, recibe
una prima que tiene que devolver con una probabilidad alta. La diferencia real está en la horquilla: el bull put pierde
1,2 puntos al cruzarla y el bull call 0,8, porque la put 6.300 está dentro del dinero y su horquilla es más ancha en
puntos.

La figura de la cabecera muestra el bull call spread: al vencimiento, la línea quebrada entre −92,7 y +107,3 con el punto
muerto en 6.192,7 (el strike bajo más el débito); hoy, una curva suave y aplanada, porque las dos patas se compensan. Las
griegas de un vertical son pequeñas comparadas con las de cada pata: la vega de la estructura es 2,42 frente a 9,05 de la
call comprada. Es una posición sobre la dirección, con poco de volatilidad.

Los verticales bajistas son el espejo, y lo habitual en la operativa es el **vertical de crédito fuera del dinero**:
vender una put de 25D y comprar otra de 10D para acotar la pérdida.

```python
bear_put = [pata("P", 6100, 1), pata("P", 5900, -1)]
bear_call = [pata("C", 5900, -1), pata("C", 6100, 1)]
put_credito = [pata("P", 5900, -1), pata("P", 5600, 1)]
for nombre, e in [("bear put 6100/5900", bear_put),
                  ("bear call 5900/6100", bear_call),
                  ("bull put 5900/5600", put_credito)]:
    print(nombre, resumen(e))
    print("   ", griegas(e))
```
```output
bear put 6100/5900 {'medio': 51.9, 'real': 52.8, 'horquilla': 0.9, 'maximo': 147.2, 'minimo': -52.8, 'muertos': [6047.2]}
    {'delta': -0.214, 'gamma': 0.00046, 'vega': 1.66, 'theta': 0.09}
bear call 5900/6100 {'medio': -147.35, 'real': -146.0, 'horquilla': 1.35, 'maximo': 146.0, 'minimo': -54.0, 'muertos': [6046.0]}
    {'delta': -0.214, 'gamma': 0.00046, 'vega': 1.66, 'theta': 0.07}
bull put 5900/5600 {'medio': -34.2, 'real': -33.6, 'horquilla': 0.6, 'maximo': 33.6, 'minimo': -266.4, 'muertos': [5866.4]}
    {'delta': 0.156, 'gamma': -0.00051, 'vega': -3.25, 'theta': 0.27}
```

El bear put 6.100/5.900 cuesta 52,8 y gana hasta 147,2; el bear call 5.900/6.100 es su gemelo de crédito (cobra 146,0 y
pierde como mucho 54,0). El bull put 5.900/5.600 es otro animal: cobra 33,6 y puede perder 266,4, casi ocho veces más.
Gana si el índice no cae más de un 3,7 % en 51 días (punto muerto 5.866,4). Sus griegas son las de una venta de
volatilidad acotada: gamma y vega negativas (−3,25), theta positiva (+0,27).

## Lo que cuesta cruzar la horquilla

Cada pata se abre cruzando su horquilla y, si se cierra antes del vencimiento, se vuelve a cruzar. En el índice, con
horquillas del 1-3 % del medio cerca del dinero, una pata cuesta poco; en una estructura de varias patas y prima neta
pequeña, el coste relativo se multiplica:

```python
estructuras = {"call 6100": call, "put 6100": put,
               "covered call": cubierta, "collar": collar,
               "bull call 6100/6300": bull_call,
               "bull put 6100/6300": bull_put,
               "bull put 5900/5600": put_credito}
filas = []
for nombre, e in estructuras.items():
    opciones = [p for p in e if p["tipo"] != "S"]
    medio, real = apertura(opciones)
    tope = resumen(e)["maximo"]
    tope = np.nan if tope == "ilimitado" or tope > 1000 else tope
    filas.append({"estructura": nombre, "patas": len(opciones),
                  "prima_medio": medio, "horquilla": real - medio,
                  "usd_contrato": 100 * (real - medio),
                  "pct_prima": 100 * (real - medio) / abs(medio),
                  "pct_max_ganancia": 100 * (real - medio) / tope})
pd.DataFrame(filas).set_index("estructura").round(2)
```
```output
                     patas  prima_medio  horquilla  usd_contrato  pct_prima  pct_max_ganancia
estructura
call 6100                1        119.3        0.5          50.0       0.42               NaN
put 6100                 1        108.8        0.5          50.0       0.46               NaN
covered call             1        -27.4        0.3          30.0       1.09              0.13
collar                   2         29.5        0.7          70.0       2.37              0.39
bull call 6100/6300      2         91.9        0.8          80.0       0.87              0.75
bull put 6100/6300       2       -106.9        1.2         120.0       1.12              1.14
bull put 5900/5600       2        -34.2        0.6          60.0       1.75              1.79
```

La call en el dinero pierde un 0,42 % de su prima al abrirse; el collar, que paga la diferencia entre dos primas, un
2,4 %; el vertical de crédito fuera del dinero, un 1,75 % de lo que cobra y un 1,79 % de lo que puede ganar. Son cifras
del 31 de diciembre de 2025, un día tranquilo. Con estrés las horquillas de los datos se ensanchan (por un factor 1 + 2,5 × estrés en
la fórmula del generador) y en las estructuras de cuatro patas de la lección 3.5.2 el coste relativo es mayor. Abrir y
cerrar antes del vencimiento lo duplica; una orden de spread al medio (las combinaciones cotizan como un solo
instrumento en los mercados reales) recupera parte, sin garantía de ejecución.

## Doce años de cada estructura

¿Cómo se comportan estas estructuras si se abren todos los meses? La historia es la más sencilla posible: la sesión
siguiente a cada vencimiento mensual se abre la estructura con el vencimiento siguiente (unos 28-35 días), con los
strikes elegidos por delta, compras al ask y ventas al bid; se mantiene hasta el vencimiento y se liquida al cierre del
índice. El P&L se mide en % del índice el día de la entrada, sin intereses sobre la prima. Las patas de índice usan el
de rentabilidad total, con dividendos.

```python
vtos = np.sort(cadena.vencimiento.unique())
sesiones = indice.index
por_dia = dict(tuple(cadena.groupby(["fecha", "vencimiento"])))


entradas = []                  # (sesión, vencimiento, cadena)
for ant, vto in zip(vtos[:-1], vtos[1:]):
    if vto > sesiones[-1]:
        break
    f = sesiones[sesiones.searchsorted(ant, side="right")]
    if (f, vto) in por_dia:
        entradas.append((f, vto, con_delta(f, vto)))


def historia(receta):
    """Abre la estructura la sesión siguiente a cada vencimiento
    mensual con el vencimiento siguiente, al bid/ask, y la
    liquida al cierre del vencimiento. P&L en % del índice."""
    filas = []
    for f, vto, d in entradas:
        S, ST = indice.loc[f, "cierre"], indice.loc[vto, "cierre"]
        crece = (indice.loc[vto, "cierre_rt"]
                 / indice.loc[f, "cierre_rt"])
        coste = pago = 0.0
        for tipo, K, n in receta(d):
            if tipo == "S":                # índice con dividendos
                coste, pago = coste + n * S, pago + n * S * crece
                continue
            o = d[(d.tipo == tipo) & (d.strike == K)].iloc[0]
            coste += n * (o.ask if n > 0 else o.bid)
            pago += n * (max(ST - K, 0) if tipo == "C"
                         else max(K - ST, 0))
        filas.append({"entrada": f, "vto": vto,
                      "pnl": 100 * (pago - coste) / S})
    return pd.DataFrame(filas).set_index("entrada")


def atm(d):
    return strike_delta(d, "C", 0.50)


recetas = {
    "índice": lambda d: [("S", 0, 1)],
    "call ATM": lambda d: [("C", atm(d), 1)],
    "put ATM": lambda d: [("P", atm(d), 1)],
    "covered call 25D": lambda d: [
        ("S", 0, 1), ("C", strike_delta(d, "C", 0.25), -1)],
    "protective put 25D": lambda d: [
        ("S", 0, 1), ("P", strike_delta(d, "P", -0.25), 1)],
    "collar 25D": lambda d: [
        ("S", 0, 1), ("P", strike_delta(d, "P", -0.25), 1),
        ("C", strike_delta(d, "C", 0.25), -1)],
    "bull call ATM/25D": lambda d: [
        ("C", atm(d), 1), ("C", strike_delta(d, "C", 0.25), -1)],
    "bull put, mismos strikes": lambda d: [
        ("P", atm(d), 1), ("P", strike_delta(d, "C", 0.25), -1)],
    "bull put 25D/10D": lambda d: [
        ("P", strike_delta(d, "P", -0.25), -1),
        ("P", strike_delta(d, "P", -0.10), 1)],
}
hist = pd.DataFrame({k: historia(v)["pnl"]
                     for k, v in recetas.items()})
print(len(hist), "entradas", hist.index[0].date(), "a",
      hist.index[-1].date())
```
```output
143 entradas 2014-01-21 a 2025-11-24
```

```python
tabla = pd.DataFrame({
    "media": hist.mean(), "mediana": hist.median(),
    "pct_pos": 100 * (hist > 0).mean(), "desv": hist.std(),
    "peor": hist.min(),
    "fecha_peor": hist.idxmin().dt.strftime("%Y-%m-%d"),
    "mejor": hist.max()})
tabla.round(2)
```
```output
                          media  mediana  pct_pos  desv   peor  fecha_peor  mejor
índice                     1.05     1.33    63.64  5.91 -28.13  2020-02-24  30.06
call ATM                   0.51    -0.44    46.15  3.58  -5.05  2020-05-18  22.43
put ATM                   -0.40    -1.38    27.27  3.47  -7.60  2020-03-23  26.49
covered call 25D           0.65     1.72    68.53  4.38 -27.41  2020-02-24  13.57
protective put 25D         0.67     0.56    56.64  4.69 -11.46  2020-04-20  26.86
collar 25D                 0.27     1.07    62.24  2.84 -10.02  2020-04-20  10.37
bull call ATM/25D          0.11     0.06    50.35  1.42  -3.52  2020-05-18   5.94
bull put, mismos strikes   0.09     0.05    50.35  1.41  -3.58  2020-04-20   5.85
bull put 25D/10D           0.23     0.42    88.11  1.08  -8.50  2020-04-20   1.97
```

*Fig. — 143 entradas mensuales de 2014 a 2025 (apertura al bid y al ask, liquidación al vencimiento): media y peor entrada de cada estructura, en % del índice.* Dos paneles de barras horizontales, una fila por estructura. Izquierda, la media por entrada: el índice gana 1,05 % por mes, la covered call 0,65 %, las verticales alrededor de 0,1 % y la put ATM pierde 0,40 %. Derecha, la peor entrada: el índice pierde 28,1 % y la covered call, destacada, 27,4 %, casi lo mismo; la protective put y el collar se quedan en 11,5 y 10,0 %; las verticales, por debajo del 9 %.

Con 143 entradas, y recordando que son datos sintéticos con una prima de volatilidad plantada:

- **Comprar opciones pierde de media lo que se paga por la volatilidad.** La put ATM pierde un 0,40 % del índice por
  entrada y solo gana en el 27 % de los meses. La call ATM gana de media un 0,51 % porque el índice sube (un 1,05 % al
  mes con dividendos), pero su mediana es negativa (−0,44 %): gana poco a menudo y mucho de vez en cuando.
- **La covered call cambia la cola derecha por frecuencia.** Gana en el 69 % de los meses (el índice, en el 64 %), con
  una media algo menor que el índice (0,65 % frente a 1,05 %) y una mejor entrada de +13,6 % frente a +30,1 %. Su peor
  entrada, la del 24 de febrero de 2020, pierde un 27,4 %: casi lo mismo que el índice (−28,1 %). Es la paridad en
  acción: una put vendida no protege de nada.
- **La protective put y el collar sí recortan la cola**, a −11,5 % y −10,0 %, pero su peor entrada no es la del crash de
  marzo sino la del 20 de abril de 2020: tras el rebote, con la volatilidad todavía muy alta, la put de 25D quedó lejos
  del índice y la caída del 19 % hasta el vencimiento de mayo cayó casi entera en la zona sin cubrir.
- **El bull call y el bull put con los mismos strikes son la misma posición**: medias de 0,11 % y 0,09 %, el mismo
  porcentaje de meses positivos (50,35 %) y peores entradas de −3,5 % y −3,6 %. La pequeña diferencia de media es la
  horquilla de la put dentro del dinero.
- **El vertical de crédito 25D/10D es la venta de prima con red.** Gana en el 88 % de las entradas, 0,23 % de media, y su
  peor entrada pierde un 8,5 %: casi cuarenta meses de ganancia media en uno. Su mejor entrada no pasa del 1,97 %.

La peor entrada del vertical de crédito enseña algo más que la cola. Con strikes elegidos por delta, el ancho entre las
dos puts depende de la volatilidad del día:

```python
for dia in ["2020-02-24", "2020-04-20"]:
    f, vto, d = next(e for e in entradas
                     if e[0] == pd.Timestamp(dia))
    k1 = strike_delta(d, "P", -0.25)
    k2 = strike_delta(d, "P", -0.10)
    x = d[d.tipo == "P"].set_index("strike")
    S = indice.loc[f, "cierre"]
    iv_atm = d.iv_modelo[d.strike == atm(d)].iloc[0]
    credito = x.loc[k1, "bid"] - x.loc[k2, "ask"]
    print(f.date(), f"ORX {S:.0f}  iv ATM {iv_atm:.3f}",
          f"strikes {k1:.0f}/{k2:.0f}",
          f"ancho {100 * (k1 - k2) / S:.1f} %",
          f"crédito {credito:.2f}",
          f"al vto {indice.loc[vto, 'cierre']:.0f}")
```
```output
2020-02-24 ORX 2960  iv ATM 0.147 strikes 2850/2750 ancho 3.4 % crédito 9.60 al vto 2124
2020-04-20 ORX 2667  iv ATM 0.489 strikes 2425/2125 ancho 11.2 % crédito 39.00 al vto 2159
```

El 24 de febrero de 2020, con la volatilidad ATM en 0,147, las puts de 25D y 10D estaban a 100 puntos una de otra (un
3,4 % del índice) y el vertical cobró 9,60. El índice cayó hasta 2.124 y se perdió el máximo: 90,4 puntos, un 3,1 %. El
20 de abril, con la volatilidad en 0,489, las mismas deltas quedaban a 300 puntos (un 11,2 %) y el vertical cobró 39,00;
el índice terminó en 2.159, por debajo de las dos, y la pérdida fue de 227 puntos, un 8,5 %. Una pérdida máxima
«definida» es tan grande como el ancho que se elige, y un ancho fijado por delta se ensancha justo cuando el mercado es
más peligroso. Fijar el ancho en puntos o en % del índice, o dimensionar por la pérdida máxima y no por el número de
contratos, son las respuestas habituales; la 3.6.1 trata el dimensionamiento de la venta sistemática de prima por
margen y por estrés.

<aside class="callout" data-kind="riesgo">

Un vertical de crédito no es una renta. En los datos gana en 126 de 143 meses y devuelve de golpe lo ganado en los
peores. La media positiva sale de la prima de volatilidad plantada en el generador; en el mercado real existe una prima
parecida en las opciones de índice, pero su tamaño varía con el periodo y la cola es la de las crisis reales, que no
avisan.

</aside>

## Errores típicos

- **Valorar al medio.** El backtest que abre al medio gana la horquilla que nunca cobraría. Abrir al ask y al bid es lo
  mínimo; cerrar antes del vencimiento cuesta otra horquilla.
- **Confundir crédito con riesgo bajo.** Con los mismos strikes, débito y crédito son la misma posición. Lo que importa
  es la pérdida máxima y la probabilidad de llegar a ella.
- **Creer que la covered call protege.** Amortigua con la prima, pero la caída del índice se queda entera.
- **Olvidar el multiplicador y las unidades.** Una theta de −1,32 es por unidad y día natural: 132 USD por contrato y
  día, también en sábado y domingo. Una vega de 9,05 es por punto de volatilidad.
- **Elegir strikes por delta sin mirar el ancho.** La misma delta es otra distancia cuando la volatilidad cambia; el
  riesgo de un vertical se mide en puntos, no en deltas.
- **Ignorar los dividendos y el tipo.** El forward de febrero está un 0,35 % por encima del índice; con r y q mal puestos,
  las deltas y la paridad salen mal (lección 3.4.1).
- **Las opciones sobre acciones son americanas.** Una call vendida dentro del dinero antes de un dividendo, o una put
  vendida muy dentro del dinero, pueden asignarse antes del vencimiento (lección 3.5.5); las del ORX son europeas.

## Ejercicios

1. Construye un bear call spread de crédito fuera del dinero con las calls 6.300 (vendida) y 6.400 (comprada) del
   vencimiento de febrero. ¿Cuánto cobra, cuánto puede perder, dónde está su punto muerto y qué griegas tiene?

**Solución.**

```python
bear_call_otm = [pata("C", 6300, -1), pata("C", 6400, 1)]
print(resumen(bear_call_otm))
griegas(bear_call_otm)
```
```output
{'medio': -17.9, 'real': -17.4, 'horquilla': 0.5, 'maximo': 17.4, 'minimo': -82.6, 'muertos': [6317.4]}
{'delta': -0.118, 'gamma': -0.00047, 'vega': -2.75, 'theta': 0.35}
```

Cobra 17,4 puntos (27,1 de la 6.300 al bid menos 9,7 de la 6.400 al ask; al medio serían 17,9) y puede perder
82,6: el ancho de 100 menos el crédito, 4,7 veces lo que gana. Gana mientras el índice no suba más de un 3,7 % hasta
el punto muerto, 6.317,4. Es una posición bajista y vendida en volatilidad: delta −0,118, gamma y vega negativas
(−2,75) y theta positiva, +0,35 puntos al día (35 USD por contrato). La relación entre lo que cobra y lo que arriesga
es la de cualquier vertical de crédito fuera del dinero: probable y pequeño contra improbable y grande.

2. Repite la historia de la covered call con calls de 10D, 25D y 40D. ¿Cómo cambian la media, el porcentaje de meses
   positivos y la peor entrada?

**Solución.**

```python
cc = {f"cc {int(100 * x)}D": historia(
          lambda d, x=x: [("S", 0, 1),
                          ("C", strike_delta(d, "C", x), -1)])["pnl"]
      for x in (0.10, 0.25, 0.40)}
cc = pd.DataFrame(cc)
pd.DataFrame({"media": cc.mean(), "pct_pos": 100 * (cc > 0).mean(),
              "peor": cc.min(), "mejor": cc.max()}).round(2)
```
```output
        media  pct_pos   peor  mejor
cc 10D   0.78    65.03 -27.91  20.83
cc 25D   0.65    68.53 -27.41  13.57
cc 40D   0.51    70.63 -27.41   9.45
```

Cuanto más cerca del dinero se vende la call (40D), más meses positivos (70,6 %) y menos media (0,51 %): se cobra más
prima, pero se renuncia antes a la subida, y en un índice que sube eso pesa más. La de 10D se parece al índice solo
(media 0,78 %, mejor entrada +20,8 %). La peor entrada apenas cambia con la delta: −27,9 %, −27,4 % y −27,4 %. Ninguna
prima de una call cubre una caída del 28 %: el strike de la call vendida decide cuánta subida se cede, no cuánta bajada
se evita.

3. Un compañero dice que su covered call «no puede perder mucho porque ya cobró la prima» y que la protective put «es
   dinero tirado porque casi nunca se usa». Con los resultados de la lección, ¿qué le contestarías?

**Solución.**

Que la covered call es, por paridad, una put vendida: su pérdida al bajar el índice es la del índice menos la prima, y
la prima de una call de 25D es un 0,4 % del índice. Su peor mes en los datos pierde un 27,4 %, siete décimas menos que
el índice. La protective put, en cambio, cuesta de media algo de rentabilidad (es una compra de volatilidad, que tiene
una prima en contra) pero recorta la peor entrada a −11,5 %. Ninguna de las dos es «mejor»: una vende cola derecha y
cobra por ello, la otra compra protección de la cola izquierda y paga por ella. Lo que no se puede decir es que la
covered call proteja. Y la protección de una put de 25D depende de la volatilidad del día: tras el crash de 2020 quedaba
tan lejos que la peor entrada llegó con la cobertura puesta.

## Autoevaluación

1. Un bull call spread 6.100/6.300 se abre pagando 119,8 por la call comprada y cobrando 27,1 por la vendida. ¿Cuál es su pérdida máxima por contrato de multiplicador 100?

   - A. 11.980 USD, la prima de la call comprada
   - B. 9.270 USD, el débito neto
   - C. 20.000 USD, el ancho entre strikes
   - D. Ilimitada, porque hay una call vendida

   *Respuesta B: 9.270 USD, el débito neto.* La pérdida máxima de un vertical de débito es lo pagado: 119,8 − 27,1 = 92,7 puntos, 9.270 USD por contrato. La call vendida está cubierta por la comprada de strike menor, así que no hay riesgo ilimitado; la ganancia máxima es el ancho menos el débito, 107,3 puntos.

2. Con los mismos strikes 6.100 y 6.300, el bull call spread es de débito y el bull put spread de crédito. ¿Qué los diferencia de verdad?

   - A. El de crédito es más seguro porque cobra al abrir
   - B. El de débito no puede perder más que lo pagado y el de crédito sí
   - C. Casi nada: por la paridad put-call tienen el mismo payoff salvo el ancho descontado; cambian la horquilla que se paga y la financiación de la prima
   - D. El de crédito tiene vega positiva

   *Respuesta C: Casi nada: por la paridad put-call tienen el mismo payoff salvo el ancho descontado; cambian la horquilla que se paga y la financiación de la prima.* Bull put = bull call − (K2 − K1), y el ancho descontado (200·e^(−rT)) iguala las primas: al medio, 91,90 frente a 92,08. Griegas y riesgo coinciden. En los datos, el de puts cuesta más horquilla (1,2 frente a 0,8 puntos) porque su put vendida está dentro del dinero.

3. En la historia de 2014-2025, la peor entrada de la covered call de 25D pierde un 27,4 % y la del índice solo un 28,1 %. ¿Por qué tan parecidas?

   - A. Porque la call vendida se ejerció
   - B. Porque una covered call es, por paridad, una put vendida: conserva toda la caída del índice y solo la amortigua con la prima cobrada
   - C. Porque la horquilla de la call es muy ancha en las crisis
   - D. Por un error en los datos de marzo de 2020

   *Respuesta B: Porque una covered call es, por paridad, una put vendida: conserva toda la caída del índice y solo la amortigua con la prima cobrada.* Vender una call limita la subida, no la bajada. La prima de una call de 25D es pequeña (27 puntos en el ejemplo, un 0,4 % del índice), así que en una caída del 28 % apenas se nota. Para limitar la bajada hace falta una put comprada: la protective put y el collar se quedan en −11,5 % y −10,0 %.

4. El bull put spread 25D/10D abierto el 24 de febrero de 2020 pierde un 3,1 % del índice y el del 20 de abril de 2020, un 8,5 %. ¿Qué explica la diferencia?

   - A. Que el índice cayó más en abril
   - B. Que con strikes elegidos por delta el ancho entre ellos crece con la volatilidad: 3,4 % del índice con una IV ATM de 0,147 y 11,2 % con 0,489
   - C. Que en abril la horquilla era más ancha
   - D. Que en febrero la put comprada no se pudo ejercer

   *Respuesta B: Que con strikes elegidos por delta el ancho entre ellos crece con la volatilidad: 3,4 % del índice con una IV ATM de 0,147 y 11,2 % con 0,489.* La delta depende de la distancia al strike medida en desviaciones típicas del plazo (la volatilidad por la raíz de T). Con la volatilidad tres veces mayor, las puts de 25D y 10D quedan tres veces más separadas, y la pérdida máxima (ancho − crédito) crece con ellas. «Riesgo definido» no quiere decir «riesgo pequeño».

5. La call 6.100 tiene una theta de −1,32 con las unidades de la lección. ¿Qué significa?

   - A. Que pierde 1,32 USD al año
   - B. Que pierde un 1,32 % al día
   - C. Que, con todo lo demás igual, pierde 1,32 puntos por día natural: 132 USD por contrato
   - D. Que pierde 1,32 puntos por sesión de negociación

   *Respuesta C: Que, con todo lo demás igual, pierde 1,32 puntos por día natural: 132 USD por contrato.* La theta se expresa aquí por día natural (la anual entre 365, como `thetaPerDay` de QuantLib con Actual/365) y por unidad de índice. Por contrato se multiplica por 100. Un fin de semana cuenta dos días naturales aunque no haya sesión.

## Ideas clave

- Una estructura es una lista de patas; su coste, payoff, P&L y griegas son la suma de los de cada pata con su signo y su cantidad.
- El coste real es el de cruzar la horquilla: compras al ask y ventas al bid. En la cadena del ejemplo va del 0,4 % de la prima en una call en el dinero al 1,8 % en un vertical de crédito fuera del dinero.
- Por paridad put-call, una covered call equivale a una put vendida y una protective put a una call comprada: vender una call no protege de la caída, como mostró su peor mes de la historia, −27,4 % frente a −28,1 % del índice.
- Débito o crédito es contabilidad: con los mismos strikes, el bull call y el bull put tienen el mismo payoff salvo el ancho descontado y las mismas griegas.
- Los verticales de crédito ganan a menudo y pierden de golpe: el 25D/10D es positivo en el 88 % de las entradas y su peor entrada pierde 37 veces su ganancia media; con strikes por delta, la pérdida máxima crece con la volatilidad.

## Recursos

### Research

- [Usos de la Volatilidad y Volatilidad Actual - VIX1D](https://pythonparatrading.com/usos-de-la-volatilidad/) · Research-0003 · 6 min

### Documentación

- [Cboe: S&P 500 Index Options (SPX), especificaciones del contrato](https://www.cboe.com/tradable_products/sp_500/spx_options/specifications/) · cboe.com
- [Cboe: índices de referencia de estrategias con opciones (BXM, PPUT, CLL…)](https://www.cboe.com/us/indices/benchmark_indices/) · cboe.com
- [QuantLib: documentación](https://www.quantlib.org/docs.shtml) · quantlib.org

### Libros

- [Hull, J. C.: Options, Futures, and Other Derivatives (Pearson)](https://www.pearson.com/en-us/subject-catalog/p/options-futures-and-other-derivatives/P200000005938) · pearson.com

### Datos

- [Datos del nivel 3: cadena diaria de opciones del índice ORX, 2014-2025 (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/opciones3_cadena.parquet) · Descarga · opciones3_cadena.parquet
- [Datos del nivel 3: índice ORX, dividendos y curva de tipos (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/opciones3_indice.csv) · Descarga · opciones3_indice.csv

Lección anterior: [3.4.7 · Modelos avanzados: Heston, SABR y volatilidad local](https://pythonparatrading.com/curso-python-trading/nivel-3/heston-sabr-y-volatilidad-local/)

Lección siguiente: [3.5.2 · Estructuras de volatilidad y rango: straddles, strangles, cóndores y mariposas](https://pythonparatrading.com/curso-python-trading/nivel-3/straddles-strangles-condors-y-butterflies/)
