Lección 3.6.1 · 70 min
Venta sistemática de prima: put-write, strangles y su riesgo de cola
Vender opciones cada mes cobra la prima de riesgo de volatilidad: la implícita suele estar por encima de la realizada. Esta lección replica en los datos sintéticos del nivel una venta de puts como la del índice PUT de Cboe y un strangle de delta 0,16, los mide con su peor episodio y no solo con su Sharpe, y calcula cuánto nominal permite el margen y cuánto aguanta el capital.
- Módulo
- 3.6 · Estrategias sistemáticas de volatilidad y opciones
- Duración
- 70 min
- Requisitos
- 3.4.6 · Volatilidad realizada frente a implícita; prima de riesgo de volatilidad; VIX y VSTOXX, 3.5.2 · Estructuras de volatilidad y rango: straddles, strangles, cóndores y mariposas, 3.5.4 · Herramienta propia: payoff, griegas agregadas y escenarios, 3.5.5 · Gestión: ajustes, roll, cierre anticipado, asignación temprana y pin risk
Lecciones del nivel 3
3.1 · Futuros en profundidad
3.2 · Spreads de futuros
- 3.2.1 Spreads de calendario, butterflies y condors
- 3.2.2 Spreads intercommodity: crack, spark y crush
- 3.2.3 Spreads de tipos y de índices: 2s10s, NOB, NQ/ES y Europa frente a EE. UU.
- 3.2.4 Ratios de cobertura: por nominal, por DV01 y por volatilidad
- 3.2.5 Datos y backtesting de spreads: cotizados, sintéticos y por patas
- 3.2.6 Estacionalidad de spreads: análisis multi-año, patrones y trampas
3.3 · Forex avanzado
3.4 · Teoría y valoración de opciones
- 3.4.1 Payoffs, paridad put-call y límites de arbitraje
- 3.4.2 Árboles binomiales, Black-Scholes-Merton, Black-76 y Monte Carlo
- 3.4.3 Griegas: delta, gamma, vega, theta, rho, vanna, volga y charm
- 3.4.4 Volatilidad implícita: Newton-Raphson, Brent, py_vollib y QuantLib
- 3.4.5 Sonrisa, skew y estructura temporal; superficie de volatilidad con SVI
- 3.4.6 Volatilidad realizada frente a implícita; prima de riesgo de volatilidad; VIX y VSTOXX
- 3.4.7 Modelos avanzados: Heston, SABR y volatilidad local
3.5 · Estructuras de opciones en Python
- 3.5.1 Estructuras direccionales y verticales: call, put, covered call, collar y spreads
- 3.5.2 Estructuras de volatilidad y rango: straddles, strangles, cóndores y mariposas
- 3.5.3 Calendarios, diagonales, ratios, backspreads, risk reversals y jade lizard
- 3.5.4 Herramienta propia: payoff, griegas agregadas y escenarios
- 3.5.5 Gestión: ajustes, roll, cierre anticipado, asignación temprana y pin risk
3.6 · Estrategias sistemáticas de volatilidad y opciones
3.7 · Cripto derivados y estrategias específicas
Qué se cobra al vender prima
La lección 3.4.6 midió la prima de riesgo de volatilidad: la volatilidad implícita de las opciones sobre índices suele estar por encima de la que luego se realiza. Quien vende opciones cobra esa diferencia de forma sistemática. Lo que la lección 3.4.6 no hizo es convertirla en una estrategia y ver qué pasa con el capital. En los datos sintéticos del nivel, con el índice tipo VIX (VORX) de la cadena de ORX:
import numpy as np
import pandas as pd
from scipy.special import ndtr
AÑO = 365.0
ind = pd.read_csv("opciones3_indice.csv", parse_dates=["fecha"])
ind = ind.set_index("fecha")
S = ind["cierre"]
rf = ind["tipo_1m"] / 100
q = ind["rentabilidad_dividendo"] / 100
cad = pd.read_parquet("opciones3_cadena.parquet")
cad["medio"] = (cad["bid"] + cad["ask"]) / 2
por_dia = dict(tuple(cad.groupby("fecha")))
vencs = sorted(cad["vencimiento"].unique())
vol = pd.read_csv("vol3_indices.csv", parse_dates=["fecha"])
vorx = vol.set_index("fecha")["vorx"]
# prima de riesgo de volatilidad: VORX frente a la realizada de
# las 21 sesiones siguientes (lección 3.4.6)
r_log = np.log(S).diff()
realizada = r_log.rolling(21).std().shift(-21) * np.sqrt(252) * 100
vrp = (vorx - realizada).dropna()
print(f"VORX - realizada: media {vrp.mean():.1f}, mediana "
f"{vrp.median():.1f} puntos; la realizada supera al VORX el "
f"{(vrp < 0).mean():.0%} de los días; peor {vrp.min():.0f}")VORX - realizada: media 5.4, mediana 6.5 puntos; la realizada supera al VORX el 12% de los días; peor -78El VORX supera a la volatilidad realizada de las 21 sesiones siguientes en 5,4 puntos de media (mediana 6,5). Pero la diferencia no es estable: el 12 % de los días la realizada supera al VORX, y en marzo de 2020 llega a superarlo en 78 puntos. Ese es todo el negocio de la venta de prima: cobrar unos puntos casi siempre y pagar decenas a veces. Una estrategia de venta de prima es un seguro vendido, y como cualquier asegurador hay que medirla por el siniestro, no por la prima.
Las estrategias de la lección siguen el mismo ciclo mensual:
Fuente Mermaid
flowchart LR V[Vender al bid] --> M[Valorar a medios] M --> L[Liquidar al vencer] L --> R[Reinvertir caja] R --> V
Put-write: la réplica del índice PUT de Cboe
El índice Cboe S&P 500 PutWrite (PUT) es la referencia pública de la venta sistemática de puts. Según su metodología, vende cada mes, normalmente el tercer viernes, una put mensual del S&P 500 en el dinero: el strike listado más cercano al índice sin superarlo. La vende al precio medio ponderado por volumen entre las 11:30 y las 12:00 ET, la mantiene hasta el vencimiento (se liquida con el valor especial de apertura, SOQ) y deja el efectivo en letras del Tesoro a uno y tres meses. El número de puts se fija para que el efectivo cubra la pérdida máxima de la liquidación: es una venta con garantía en efectivo, sin apalancamiento.
La réplica con los datos de ORX sigue esas reglas con tres diferencias que impone el dato diario: vende al bid del cierre del día del vencimiento (en vez del precio medio de media mañana), liquida al cierre (las opciones de ORX vencen al cierre) y fija el número de puts con el efectivo antes de cobrar la prima (algo más conservador que la fórmula de Cboe, que cuenta la prima y los intereses). La misma función vende también strangles y cada una de sus patas por delta, con el nominal igual al índice:
def delta_bsm(tipo, S, K, T, iv, r, q):
d1 = (np.log(S / K) + (r - q + iv**2 / 2) * T) / (iv * np.sqrt(T))
w = 1.0 if tipo == "C" else -1.0
return w * np.exp(-q * T) * ndtr(w * d1)
PATAS = {"put": ("P",), "strangle": ("P", "C"), "put_d": ("P",),
"call_d": ("C",)}
def venta_prima(estructura, apal=1.0, cobro="bid", delta=0.16):
"""Curva de capital (empieza en 1) de vender prima cada mes.
«put»: put en el dinero (strike más alto <= índice) con un
nominal de apal × capital en strikes, como el índice PUT de
Cboe cuando apal = 1. «strangle», «put_d», «call_d»: patas de
delta ±delta con nominal apal × capital en índice. Venta al bid
(o al medio) el día de cada vencimiento, del vencimiento
siguiente con 20 días o más; valoración diaria al medio;
liquidación al cierre del vencimiento; caja al tipo a 1 mes."""
caja, patas, venc, eq, ultimo = 1.0, [], None, {}, 1.0
for f in S.index:
g = por_dia.get(f) # None: día sin cadena
if venc is not None and f == venc:
caja -= sum(n * max(k - S[f] if t == "P" else S[f] - k, 0)
for t, k, n in patas)
patas, venc = [], None
if caja <= 0: # ruina: la caja no cubre la liquidación
eq[f] = ultimo = 0.0
continue
if venc is None and g is not None:
v = next(x for x in vencs if (x - f).days >= 20)
sub = g[g["vencimiento"] == v]
T = (v - f).days / AÑO
if estructura == "put":
pp = sub[(sub["tipo"] == "P") & (sub["strike"] <= S[f])]
sel = [pp.loc[pp["strike"].idxmax()]]
n = apal * caja / sel[0]["strike"]
else:
sel = []
for t in PATAS[estructura]:
st = sub[sub["tipo"] == t]
d = delta_bsm(t, S[f], st["strike"].to_numpy(),
T, st["iv_modelo"].to_numpy(),
rf[f], q[f])
sel.append(st.iloc[int(np.argmin(
np.abs(np.abs(d) - delta)))])
n = apal * caja / S[f]
caja += sum(n * fila[cobro] for fila in sel)
patas = [(fila["tipo"], fila["strike"], n) for fila in sel]
venc = v
marca = 0.0
if patas and g is not None:
m = g[g["vencimiento"] == venc].set_index(
["tipo", "strike"])["medio"]
marca = sum(n * m.get((t, k), np.nan) for t, k, n in patas)
if patas and (g is None or not np.isfinite(marca)):
eq[f] = ultimo # sin cotización: la valoración anterior
else:
eq[f] = ultimo = caja - marca
caja *= np.exp(rf[f] / 252)
return pd.Series(eq)El parámetro apal multiplica el nominal por unidad de capital: con 1, cada unidad de capital respalda una unidad de
strike (o de índice); con 3, tres. Si la caja no alcanza para pagar una liquidación, la cuenta queda en ruina y la
curva se queda en cero.
Resultados con la cola a la vista
La métrica estándar, el Sharpe, se calcula con la desviación típica de las rentabilidades diarias. En una estrategia con la cola a la izquierda la desviación típica la fijan los meses normales, y la cola apenas pesa en ella. Por eso cada resultado va con su máxima caída, su asimetría mensual y su peor mes:
def metricas(eq):
"""Sharpe del exceso diario sobre el tipo a 1 mes, CAGR, máxima
caída, asimetría y peor mes (con su fecha)."""
r = eq.pct_change().dropna()
ex = r - rf.reindex(r.index) / 252
mes = eq.resample("ME").last().pct_change().dropna()
anos = (eq.index[-1] - eq.index[0]).days / 365.25
return {"sharpe": ex.mean() / ex.std() * np.sqrt(252),
"cagr": (eq.iloc[-1] / eq.iloc[0]) ** (1 / anos) - 1,
"max_caida": (eq / eq.cummax() - 1).min(),
"asim_mensual": mes.skew(), "peor_mes": mes.min(),
"fecha_peor": mes.idxmin().strftime("%Y-%m")}
curvas = {"índice RT": ind["cierre_rt"] / ind["cierre_rt"].iloc[0],
"put-write": venta_prima("put"),
"put-write al medio": venta_prima("put", cobro="medio"),
"strangle 16Δ": venta_prima("strangle"),
"put 16Δ": venta_prima("put_d"),
"call 16Δ": venta_prima("call_d")}
res = pd.DataFrame([metricas(v) for v in curvas.values()],
index=list(curvas))
res.round(3) sharpe cagr max_caida asim_mensual peor_mes fecha_peor
índice RT 0.656 0.125 -0.399 -0.793 -0.288 2020-05
put-write 0.520 0.068 -0.395 -3.731 -0.232 2020-03
put-write al medio 0.533 0.069 -0.394 -3.720 -0.232 2020-03
strangle 16Δ -0.165 0.002 -0.421 -5.480 -0.237 2020-03
put 16Δ 0.469 0.047 -0.274 -8.596 -0.223 2020-03
call 16Δ -0.850 -0.026 -0.384 -3.701 -0.119 2020-08La figura de la cabecera compara el put-write con el índice de rentabilidad total. El put-write tiene un Sharpe de 0,52 frente a 0,66 del índice y la mitad de su CAGR (6,8 % frente a 12,5 %), pero no la mitad de su riesgo: su máxima caída, −39,5 %, es prácticamente la del índice (−39,9 %), y su asimetría mensual es de −3,7 frente a −0,8. Cobrar al medio en vez de al bid apenas cambia nada (0,53): en una put en el dinero de un índice líquido la horquilla es pequeña frente a la prima. Con datos reales los costes y la ejecución pesan más en las opciones fuera del dinero (lección 3.6.4).
Las cifras de los datos no dicen nada sobre lo que rinde la estrategia en mercados reales: son sintéticas, con la prima de riesgo de volatilidad plantada por el generador (README de los datos). Lo que sí enseñan es su forma:
mensual = pd.DataFrame({k: curvas[k].resample("ME").last().pct_change()
for k in ("índice RT", "put-write")}).dropna()
mensual.index = mensual.index.strftime("%Y-%m")
peores = mensual.nsmallest(6, "put-write")
print(f"Meses: {len(mensual)} · put-write positivo el "
f"{(mensual['put-write'] > 0).mean():.0%}")
(100 * peores).round(1)Meses: 143 · put-write positivo el 78%
índice RT put-write
2020-03 -19.5 -23.2
2020-05 -28.8 -21.2
2018-02 -7.8 -8.9
2018-10 -8.7 -7.1
2015-09 -6.9 -5.6
2022-05 -10.9 -4.5El put-write gana en el 78 % de los meses; 55 de los 143 quedan entre +1 y +2 %. Los dos peores, marzo y mayo de 2020 (−23,2 y −21,2 %), suman −44,4 %: unos treinta meses buenos de +1,5 %. En marzo de 2020 el put-write pierde más que el índice (−23,2 frente a −19,5 %): la put vendida el 21 de febrero se liquida el 20 de marzo, cerca del mínimo, y el índice recupera algo en la última semana del mes. En mayo, el segundo tramo de la caída sintética de los datos, pierde menos que el índice (−21,2 frente a −28,8 %): la put de mayo se vendió el 17 de abril con una volatilidad implícita del 49 % y cobró un 5,46 % del strike, frente al 1,14 % de la put vendida el 21 de febrero.
El strangle de delta 0,16: por qué pierde en esta muestra
El strangle vendido añade a la put una call fuera del dinero. Cobra dos primas y, en el papel, «gana si el mercado no se mueve mucho». En la tabla tiene un Sharpe de −0,16, un CAGR del 0,2 % y una máxima caída de −42,1 %: peor que la put sola (0,47 y −27,4 %). La razón está en las patas:
def log_anual(eq):
return np.log(eq).diff().groupby(eq.index.year).sum()
patas = pd.DataFrame({"put 16Δ": log_anual(curvas["put 16Δ"]),
"call 16Δ": log_anual(curvas["call 16Δ"]),
"índice": log_anual(curvas["índice RT"])})
c = patas["call 16Δ"]
print(f"Call 16Δ: 2020-2021 {c.loc[[2020, 2021]].sum():.2f} en log; "
f"resto de años {c.drop([2020, 2021]).mean():.3f} de media")
(100 * patas).round(1).TCall 16Δ: 2020-2021 -0.43 en log; resto de años 0.012 de media
2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025
put 16Δ 5.2 4.0 5.3 6.5 -4.0 8.3 -18.0 7.8 8.7 11.7 10.8 8.6
call 16Δ -2.6 -4.3 -4.2 1.0 4.9 0.6 -25.7 -16.9 3.7 4.2 4.4 4.0
índice 8.7 -0.0 22.6 12.4 -12.0 24.3 10.0 29.1 -21.1 20.4 33.2 13.7La put de delta −0,16 gana todos los años salvo 2018 (−4,0 %) y 2020 (−18,0 %). La call de delta 0,16 pierde en 2014-2016 y, sobre todo, en 2020 y 2021: −25,7 % y −16,9 % en log, −0,43 en total, cuando el índice rebota tras la caída y sube un 29,1 % (en log) en 2021. El resto de los años gana un 1,2 % de media: poco, porque el skew abarata las calls fuera del dinero y la prima que se cobra es pequeña. El resultado es una pata de calls que pierde un 2,6 % al año en la muestra.
No es una ley: con otra muestra, sin un mercado tan alcista, la pata de calls podría ganar. Lo que enseña es que un strangle es dos apuestas: una sobre la cola izquierda, bien pagada por el skew, y otra sobre la cola derecha, mal pagada. Cada pata se mide por separado antes de juntarlas.
Tamaño por margen: lo que permite el bróker
Una put vendida sin cubrir no necesita tener todo el strike en efectivo: el bróker exige un margen. La ficha de Cboe de las SPX lo fija para las opciones de índice vendidas sin cubrir en el 100 % de la prima más el 15 % del valor del índice por el multiplicador, menos lo que la opción esté fuera del dinero, con un mínimo para las puts de la prima más el 10 % del strike por el multiplicador. Aplicado a ORX dos meses antes de la caída:
def margen_put(prima, S, K, mult=100):
"""Margen por contrato de una put de índice vendida sin cubrir
(ficha de Cboe de las SPX): 100 % de la prima + 15 % del
nominal del índice - lo que esté fuera del dinero, con un
mínimo de prima + 10 % del nominal del strike."""
fuera = max(S - K, 0)
return mult * max(prima + 0.15 * S - fuera, prima + 0.10 * K)
f0 = pd.Timestamp("2019-12-20")
g0 = por_dia[f0]
v0 = next(x for x in vencs if (x - f0).days >= 20)
filas = []
for nombre, d in (("ATM", 0.5), ("16Δ", 0.16)):
st = g0[(g0["vencimiento"] == v0) & (g0["tipo"] == "P")]
dl = delta_bsm("P", S[f0], st["strike"].to_numpy(), (v0 - f0).days
/ AÑO, st["iv_modelo"].to_numpy(), rf[f0], q[f0])
fila = st.iloc[int(np.argmin(np.abs(np.abs(dl) - d)))]
m = margen_put(fila["bid"], S[f0], fila["strike"])
filas.append({"put": nombre, "strike": fila["strike"],
"prima": fila["bid"], "margen_usd": m,
"nominal_usd": 100 * fila["strike"],
"apal_max": 100 * fila["strike"] / m})
print(f"ORX el {f0.date()}: {S[f0]}")
pd.DataFrame(filas).round(2)ORX el 2019-12-20: 2850.28
put strike prima margen_usd nominal_usd apal_max
0 ATM 2850.0 32.5 45976.2 285000.0 6.20
1 16Δ 2750.0 11.0 33826.2 275000.0 8.13Una put ATM exige 45.976 USD de garantía por 285.000 de nominal: el margen permite 6,2 veces el capital en nominal. La de delta −0,16, más lejos del dinero, aún menos margen: 8,1 veces. El margen está pensado para cubrir el movimiento de unos días con un colchón; no para una crisis.
Apalancamiento y ruina
El mismo put-write, con más nominal por unidad de capital:
apal = {}
for L in (1.0, 1.5, 2.0, 3.0, 4.0):
eq = venta_prima("put", apal=L)
m = metricas(eq)
m["ruina"] = bool((eq <= 0).any())
apal[L] = m
pd.DataFrame(apal).T.drop(columns="fecha_peor").astype(float).round(3) sharpe cagr max_caida asim_mensual peor_mes ruina
1.0 0.520 0.068 -0.395 -3.731 -0.232 0.0
1.5 0.482 0.086 -0.557 -3.609 -0.358 0.0
2.0 0.439 0.097 -0.696 -3.485 -0.491 0.0
3.0 0.336 0.078 -0.914 -3.211 -0.777 0.0
4.0 -0.609 -1.000 -1.217 -4.810 -1.000 1.0Con 1,5 veces el nominal el CAGR sube del 6,8 al 8,6 % y la máxima caída pasa del −39,5 al −55,7 %. Con 2 veces, 9,7 % y −69,6 %. Con 3 veces el CAGR ya baja (7,8 %) y la caída es de −91,4 %: la cuenta pierde nueve décimas partes en marzo de 2020. Con 4 veces, la cuenta queda en negativo el 16 de marzo de 2020 y no sobrevive al vencimiento: ruina, con una caída medida de −121,7 % (la cuenta debe dinero al bróker). La rentabilidad crece poco y deja de crecer; la caída crece casi en proporción: más allá de cierto apalancamiento, las pérdidas grandes se comen la rentabilidad compuesta.
Todos esos apalancamientos caben en el margen de la celda anterior (6,2 veces). El margen no es un límite de riesgo: es un mínimo que pone el bróker para protegerse a sí mismo.
Tamaño por estrés
Un límite de riesgo se fija al revés: se elige cuánto del capital se acepta perder en un escenario extremo y se calcula el nominal que lo cumple. La herramienta de la lección 3.5.4 hace la revaloración; aquí basta con la put ATM del 2019-12-20, revalorada con Black-Scholes si el escenario ocurre al día siguiente:
def bsm_put(S, K, T, iv, r, q):
d1 = (np.log(S / K) + (r - q + iv**2 / 2) * T) / (iv * np.sqrt(T))
d2 = d1 - iv * np.sqrt(T)
return (K * np.exp(-r * T) * ndtr(-d2)
- S * np.exp(-q * T) * ndtr(-d1))
# la put ATM del 2019-12-20 (celda anterior), revalorada si el
# escenario ocurre al día siguiente
atm = filas[0]
K0, T0 = atm["strike"], (v0 - f0).days / AÑO - 1 / AÑO
escenarios = {"caída del 10 %, vol 35 %": (0.90, 0.35),
"caída del 20 %, vol 60 %": (0.80, 0.60),
"caída del 30 %, vol 80 %": (0.70, 0.80)}
filas_e = []
for nombre, (mov, iv) in escenarios.items():
valor = bsm_put(S[f0] * mov, K0, T0, iv, rf[f0], q[f0])
perdida = 100 * (valor - atm["prima"]) / K0 # % del nominal
filas_e.append({"escenario": nombre,
"pérdida_%": perdida,
"apal_20%": 20 / perdida,
"con_apal_max_%": perdida * atm["apal_max"]})
peor_hist = -res.at["put-write", "peor_mes"] * 100
filas_e.append({"escenario": "peor mes de los datos",
"pérdida_%": peor_hist,
"apal_20%": 20 / peor_hist,
"con_apal_max_%": peor_hist * atm["apal_max"]})
print(f"Put {K0:.0f} vendida a {atm['prima']}: "
f"{100 * atm['prima'] / K0:.2f} % del nominal")
pd.DataFrame(filas_e).set_index("escenario").round(2)Put 2850 vendida a 32.5: 1.14 % del nominal
pérdida_% apal_20% con_apal_max_%
escenario
caída del 10 %, vol 35 % 9.46 2.11 58.63
caída del 20 %, vol 60 % 19.41 1.03 120.32
caída del 30 %, vol 80 % 29.21 0.68 181.06
peor mes de los datos 23.24 0.86 144.09La put se vendió a 32,5 puntos, el 1,14 % de su nominal. Con una caída del 20 % y la volatilidad al 60 % (un mes como marzo de 2020), pierde el 19,41 % de su nominal: para no perder más del 20 % del capital, el nominal no puede pasar de 1,03 veces el capital. Con una caída del 30 % y la volatilidad al 80 %, de 0,68 veces. El peor mes de los datos a 1 × (−23,24 %) da 0,86 veces. Con el apalancamiento que permite el margen, esos escenarios cuestan entre el 59 y el 181 % del capital.
Fuente Mermaid
flowchart TB A[Capital] --> B[Margen exigido] A --> C[Pérdida en estrés] B --> D[Apal. máximo 6,2x] C --> E[Apal. prudente 1x] D --> F[Nominal = mínimo] E --> F
El nominal que se opera es el menor de los dos. En venta de prima, el de estrés casi siempre manda. Tres precauciones sobre los escenarios: deben incluir el salto de un día, no solo la caída acumulada (el 16 de marzo de 2020 el índice cae un 12,8 % en una sesión); deben subir la volatilidad más en los strikes bajos (lección 3.5.4); y el peor episodio de la muestra no es el peor posible, solo el peor que se ha visto.
Lo que esta lección no prueba
Los datos son sintéticos y la prima de riesgo de volatilidad está plantada. La lección enseña a medir una venta de prima, no que funcione. Antes de operar una con dinero hacen falta datos reales de opciones con sus horquillas y sus incidencias (lección 3.6.4), costes de ejecución realistas en la apertura y el cierre de cada ciclo, el coste de oportunidad del margen y un plan para el peor mes que no dependa de que el siguiente sea mejor. La metodología del índice PUT de Cboe es un buen punto de partida para comparar una réplica propia con una serie pública.
Ejercicios
- Más lejos del dinero, con más nominal. Vende solo la put de delta −0,16 con 2 y 3 veces el capital en nominal y compara su CAGR, su máxima caída y su peor mes con los del put-write ATM a 1 ×. ¿Qué es más arriesgado: una put lejana apalancada o una cercana sin apalancar?
Solución
La put lejana cobra menos prima, así que hace falta más nominal para acercarse a la rentabilidad del put-write; con más nominal, su peor mes crece en proporción. Con 2 veces el capital rinde un 6,6 % anual (menos que el put-write a 1 ×, 6,8 %) con una caída máxima de −54,8 % y un peor mes de −45,6 %; con 3 veces, 6,2 %, −82,2 % y −69,9 %. La put lejana apalancada es más arriesgada y, en esta muestra, rinde menos: «lejos del dinero» no significa «poco riesgo» cuando se compensa con nominal.
filas = {"put-write 1x": metricas(curvas["put-write"])}
for L in (2.0, 3.0):
filas[f"put 16Δ {L:.0f}x"] = metricas(venta_prima("put_d", apal=L))
pd.DataFrame(filas).T[["sharpe", "cagr", "max_caida", "peor_mes"]
].astype(float).round(3) sharpe cagr max_caida peor_mes
put-write 1x 0.520 0.068 -0.395 -0.232
put 16Δ 2x 0.373 0.066 -0.548 -0.456
put 16Δ 3x 0.288 0.062 -0.822 -0.699- Una put con ala. Calcula la pérdida en los tres escenarios de estrés de un put spread vendido (put 2850 vendida y put 2550 comprada, 10 % por debajo, del mismo vencimiento) y el nominal que permite el límite del 20 %.
Solución
El ala comprada cuesta 1,6 puntos: el crédito neto baja de 32,5 a 30,9 (1,08 % del nominal) y la pérdida máxima queda en 300 − 30,9 = 269,1 puntos, el 9,44 % del nominal. En los escenarios, el spread pierde un 6,37, un 7,99 y un 8,70 % del nominal, frente al 9,46, 19,41 y 29,21 % de la put sola: el límite del 20 % permite entre 2,3 y 3,1 veces el capital. El ala cuesta un 5 % de la prima (1,6 de 32,5 puntos) y cambia por completo la cola.
st = g0[(g0["vencimiento"] == v0) & (g0["tipo"] == "P")]
ala = st.set_index("strike").loc[2550.0]
credito = atm["prima"] - ala["ask"]
print(f"Crédito neto: {credito:.1f} ({100 * credito / K0:.2f} %)")
filas_s = {}
for nombre, (mov, iv) in escenarios.items():
s1 = S[f0] * mov
valor = (bsm_put(s1, K0, T0, iv, rf[f0], q[f0])
- bsm_put(s1, 2550.0, T0, iv, rf[f0], q[f0]))
perdida = 100 * (valor - credito) / K0
filas_s[nombre] = {"pérdida_%": perdida, "apal_20%": 20 / perdida}
pd.DataFrame(filas_s).T.round(2)Crédito neto: 30.9 (1.08 %)
pérdida_% apal_20%
caída del 10 %, vol 35 % 6.37 3.14
caída del 20 %, vol 60 % 7.99 2.50
caída del 30 %, vol 80 % 8.70 2.30- Margen o estrés. Un compañero propone operar el put-write con el apalancamiento que permite el margen «porque el Sharpe es el mismo». ¿Qué le contestas con los números de la lección?
Solución
Que el Sharpe apenas mide la cola. Con 6,2 veces el capital, el peor mes de los datos (−23,2 % a 1 ×) es una pérdida del 144 % del capital, y ya con 4 veces la cuenta de los datos queda en negativo el 16 de marzo de 2020. Además, el Sharpe sí cambia con el apalancamiento cuando hay ruina o caídas casi totales: en la tabla baja de 0,52 (1 ×) a 0,34 (3 ×). El apalancamiento se decide con escenarios de estrés y con el peor episodio conocido, y el resultado (en torno a 1 vez el capital para no perder más del 20 % en una caída del 20 %) es muy inferior al que permite el margen.
Respuesta plegada en cada pregunta
Autoevaluación
El put-write de los datos tiene un Sharpe de 0,52 y una asimetría mensual de −3,7. ¿Qué describe mejor su perfil?
- AUna renta estable con riesgo bajo
- BMuchos meses pequeños y positivos (el 78 %) y pocos meses muy malos (−23,2 % en marzo de 2020), con una máxima caída del −39,5 %, como la del índice
- CUna estrategia sin correlación con el índice
- DUna estrategia con más rentabilidad que el índice
Ver respuesta
Respuesta B. Muchos meses pequeños y positivos (el 78 %) y pocos meses muy malos (−23,2 % en marzo de 2020), con una máxima caída del −39,5 %, como la del índice
La asimetría negativa dice que la distribución tiene la cola a la izquierda. El put-write cobra cada mes una prima pequeña y devuelve varios años de primas en una crisis. Su máxima caída es la del índice, con la mitad de CAGR.
El strangle vendido de delta ±0,16 pierde en la muestra (Sharpe −0,16) aunque la put de delta −0,16 sola gana (0,47). ¿Por qué?
- APorque la put y la call se cancelan
- BPorque la pata de calls pierde un 2,6 % al año: el rebote de 2020 y la subida de 2021 (−0,43 en log en dos años) se llevan lo que gana en los demás
- CPorque los strangles siempre pierden
- DPorque la volatilidad implícita de las calls es más alta
Ver respuesta
Respuesta B. Porque la pata de calls pierde un 2,6 % al año: el rebote de 2020 y la subida de 2021 (−0,43 en log en dos años) se llevan lo que gana en los demás
Una call vendida pierde con las subidas fuertes. En una muestra con un mercado muy alcista y un rebote violento, la prima de las calls (pequeña: el skew las abarata) no compensa. Es un resultado de la muestra, no una ley, pero recuerda que cada pata es una apuesta distinta.
Con la regla de margen de Cboe, una put ATM vendida sobre ORX exige unos 46.000 USD por contrato de 285.000 de nominal. ¿Qué apalancamiento permite y qué habría pasado con él en la muestra?
- A1 ×; nada
- BUnas 6 veces el capital; con 4 veces la cuenta ya queda en negativo el 16-03-2020
- C15 veces; una caída del 15 %
- DEl margen impide perder más que el capital
Ver respuesta
Respuesta B. Unas 6 veces el capital; con 4 veces la cuenta ya queda en negativo el 16-03-2020
El margen cubre el riesgo de unos días con un 15 % del índice, no una crisis. Con 285.000 / 45.976 ≈ 6,2 veces el capital, el peor mes de los datos (−23,2 % a 1 ×) se convierte en una pérdida de más del 140 % del capital. En la celda de apalancamiento, ya con 4 × la cuenta no sobrevive a marzo de 2020.
¿Qué nominal deja la pérdida por debajo del 20 % del capital en un escenario de caída del 20 % con la volatilidad al 60 %?
- A6,2 veces el capital
- BAlrededor de 1 vez el capital: en ese escenario la put ATM pierde un 19,4 % de su nominal
- C0,2 veces el capital
- DNo se puede calcular sin el Sharpe
Ver respuesta
Respuesta B. Alrededor de 1 vez el capital: en ese escenario la put ATM pierde un 19,4 % de su nominal
20 / 19,41 = 1,03. El tamaño por estrés sale de revalorar la posición en el escenario (lección 3.5.4) y dividir la pérdida tolerable entre la pérdida por unidad de nominal. Es seis veces menos de lo que permite el margen.
¿Por qué la lección presenta cada estrategia con su peor mes y su máxima caída y no solo con el Sharpe?
- APorque el Sharpe no se puede calcular con opciones
- BPorque el Sharpe supone que la desviación típica resume el riesgo; con una asimetría de −3,7, la desviación típica la fijan los meses normales y la cola apenas pesa en ella
- CPor costumbre
- DPorque el peor mes siempre es igual a la máxima caída
Ver respuesta
Respuesta B. Porque el Sharpe supone que la desviación típica resume el riesgo; con una asimetría de −3,7, la desviación típica la fijan los meses normales y la cola apenas pesa en ella
Con distribuciones muy asimétricas, dos estrategias con el mismo Sharpe pueden tener colas muy distintas. Una venta de prima sin su peor episodio a la vista parece una renta segura y no lo es.
Ideas clave
- Vender opciones cobra la prima de riesgo de volatilidad (en los datos, el VORX supera a la realizada en 5,4 puntos de media), a cambio de pérdidas grandes en las crisis: es un seguro vendido, no una renta.
- El put-write de los datos tiene un Sharpe de 0,52 con una máxima caída del −39,5 %, la del índice, y una asimetría mensual de −3,7. Una estrategia de venta de prima se presenta siempre con su peor episodio.
- El strangle de delta 0,16 pierde en esta muestra porque la pata de calls pierde con el mercado alcista: cada pata es una apuesta distinta y se mide por separado.
- El margen de Cboe para una put de índice sin cubrir permite unas 6 veces el capital; con 4 veces, la cuenta de los datos queda en negativo en marzo de 2020. El margen mide el riesgo de unos días, no el de una crisis.
- El tamaño se fija con escenarios de estrés y con el peor episodio conocido: en los datos, un nominal de alrededor de 1 vez el capital para no perder más del 20 % en una caída del 20 %.