Lección 3.5.5 · 65 min
Gestión: ajustes, roll, cierre anticipado, asignación temprana y pin risk
Abrir una posición de opciones es la mitad de la operación; la otra mitad son las decisiones mientras vive: cerrarla antes, rodarla, ajustarla o dejarla vencer. Esta lección mide en los datos sintéticos del nivel cinco reglas de gestión de una venta de puts, enseña qué es y qué no es un roll, cuándo conviene ejercer una opción americana antes del vencimiento y por qué un cierre pegado al strike es un riesgo.
- Módulo
- 3.5 · Estructuras de opciones en Python
- Duración
- 65 min
- Requisitos
- 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.5.1 · Estructuras direccionales y verticales: call, put, covered call, collar y spreads, 3.5.4 · Herramienta propia: payoff, griegas agregadas y escenarios
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
Una posición viva: qué se puede decidir
Entre la apertura y el vencimiento de una posición de opciones hay cuatro decisiones posibles, y cada día que pasa se toma una de ellas, aunque sea no hacer nada:
Fuente Mermaid
stateDiagram-v2 [*] --> Abierta Abierta --> Ajustada: ajuste Ajustada --> Abierta Abierta --> Cerrada: cierre Abierta --> Rodada: roll Rodada --> Abierta: nueva posición Abierta --> Vencida: vencimiento Abierta --> Asignada: ejercicio Cerrada --> [*] Vencida --> [*] Asignada --> [*]
| Decisión | Qué es | Qué cambia en las griegas | Coste |
|---|---|---|---|
| Dejar vencer | No hacer nada hasta el vencimiento | Nada; la gamma crece al acercarse | Ninguno, salvo liquidación o entrega |
| Cerrar antes | Recomprar lo vendido (o vender lo comprado) | Todo a cero | Horquilla de salida |
| Rodar | Cerrar y abrir otra posición más lejos en el tiempo o en el strike | Las de la nueva posición | Dos horquillas |
| Ajustar | Añadir o quitar patas (alas, coberturas con subyacente, cambiar un strike) | Las que se buscan corregir | Una o varias horquillas |
| Asignación o ejercicio | La contraparte ejerce (opciones americanas) o se llega al vencimiento dentro del dinero | Opción sustituida por subyacente o efectivo | Dividendo perdido, entrega, financiación |
La lección usa dos conjuntos de datos sintéticos del nivel. Las opciones de ORX (lecciones 3.5.4 y 3.6.1) son europeas y se liquidan en efectivo: sirven para medir reglas de cierre y de roll. Las de KRN, una acción ficticia con dividendo trimestral, son americanas y se valoran con un árbol binomial con dividendos discretos (lección 3.4.2 y README de los datos): sirven para el ejercicio anticipado y el pin risk. Los resultados de los datos no dicen qué regla funciona en un mercado real; enseñan cómo medirla y dónde están las trampas.
Cerrar antes: cinco reglas medidas en ORX
La estrategia base es sencilla: el día de cada vencimiento mensual se vende al bid una put de delta −0,16 del vencimiento siguiente (con 20 días o más) y se gestiona con una regla. Es la pata de puts del strangle de la lección 3.6.1, sin apalancamiento: el resultado se mide en % del strike de cada operación.
import numpy as np
import pandas as pd
from scipy.special import ndtr
ind = pd.read_csv("opciones3_indice.csv", parse_dates=["fecha"])
ind = ind.set_index("fecha")
S, r = ind["cierre"], ind["tipo_1m"] / 100
q = ind["rentabilidad_dividendo"] / 100
cad = pd.read_parquet(
"opciones3_cadena.parquet",
columns=["fecha", "vencimiento", "tipo", "strike", "bid", "ask",
"iv_modelo"])
puts = cad[cad["tipo"] == "P"]
por_dia = dict(tuple(puts.groupby("fecha")))
series = {k: g.set_index("fecha")[["bid", "ask"]]
for k, g in puts.groupby(["vencimiento", "strike"])}
vencs = sorted(puts["vencimiento"].unique())
print(len(por_dia), "días con cadena ·", len(vencs), "vencimientos")3017 días con cadena · 147 vencimientosdef 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)
def put_por_delta(f, v, objetivo):
"""Put del vencimiento v con |delta| más cercana al objetivo."""
g = por_dia[f]
g = g[g["vencimiento"] == v]
T = (v - f).days / 365
d = delta_bsm("P", S[f], g["strike"].to_numpy(), T,
g["iv_modelo"].to_numpy(), r[f], q[f])
return g.iloc[int(np.argmin(np.abs(np.abs(d) - objetivo)))]
def ciclo(objetivo=0.16):
"""Vende una put al bid el día de cada vencimiento mensual
(o el primer día con cadena), del vencimiento siguiente con
20 días o más. Devuelve una operación por ciclo."""
ops, f = [], S.index[0]
while True:
while f not in por_dia:
f = S.index[S.index.get_loc(f) + 1]
v = next((x for x in vencs if (x - f).days >= 20), None)
if v is None or v > S.index[-1]:
return ops
fila = put_por_delta(f, v, objetivo)
k = fila["strike"]
ops.append({"entrada": f, "venc": v, "strike": k,
"credito": fila["bid"], "ST": S[v],
"cot": series[(v, k)].loc[f:v].iloc[1:]})
f = v
ops = ciclo(0.16)
cred = pd.Series([100 * o["credito"] / o["strike"] for o in ops])
print(len(ops), "operaciones · crédito medio",
f"{cred.mean():.2f} % del strike")
pd.DataFrame(ops[:3]).drop(columns="cot")143 operaciones · crédito medio 0.65 % del strike
entrada venc strike credito ST
0 2014-01-02 2014-02-21 1700.0 7.5 1882.25
1 2014-02-21 2014-03-21 1800.0 6.7 1839.01
2 2014-03-21 2014-04-17 1750.0 6.7 1793.62Son 143 operaciones entre 2014 y 2025, con un crédito medio del 0,65 % del strike: unos 0,65 puntos por cada 100 de nominal, cobrados a cambio de cubrir las caídas por debajo de un strike que queda, en mediana, un 5,8 % por debajo del índice (entre el 4,1 y el 9,5 % en el 80 % central de las operaciones). Las reglas:
- Mantener: liquidación al vencimiento, sin hacer nada.
- 50 %: recomprar en cuanto la put cueste la mitad del crédito (el beneficio objetivo más citado en la venta de prima).
- 21 días: recomprar cuando queden 21 días naturales, antes de que la gamma crezca.
- Stop 2×: recomprar si la put llega a valer tres veces el crédito (pérdida de dos créditos).
- 50 % o 21 días: la que llegue antes.
Todas recompran al ask del cierre del día en que se cumple la condición: es lo que se puede hacer con datos diarios, y es menos favorable que una orden durante la sesión.
def gestiona(op, objetivo=None, dias=None, stop=None):
"""P&L por unidad (puntos) y fecha de salida. Recompra al ask
al cierre del primer día en que se cumple una regla; si no,
liquidación al vencimiento."""
for f, (bid, ask) in op["cot"].iterrows():
if f >= op["venc"]:
break
if objetivo is not None and ask <= objetivo * op["credito"]:
return op["credito"] - ask, f
if stop is not None and ask >= stop * op["credito"]:
return op["credito"] - ask, f
if dias is not None and (op["venc"] - f).days <= dias:
return op["credito"] - ask, f
pago = max(op["strike"] - op["ST"], 0.0)
return op["credito"] - pago, op["venc"]
REGLAS = {"mantener": {}, "50 %": {"objetivo": 0.5},
"21 días": {"dias": 21}, "stop 2x": {"stop": 3.0},
"50 % o 21 días": {"objetivo": 0.5, "dias": 21}}
def resultados(ops):
pnl, dias = {}, {}
for nombre, kw in REGLAS.items():
filas = [gestiona(o, **kw) for o in ops]
pnl[nombre] = pd.Series(
[100 * x / o["strike"] for (x, _), o in zip(filas, ops)],
index=[o["entrada"] for o in ops])
dias[nombre] = np.mean([(f - o["entrada"]).days
for (_, f), o in zip(filas, ops)])
pnl = pd.DataFrame(pnl) # % del strike por operación
tabla = pd.DataFrame({
"media": pnl.mean(), "mediana": pnl.median(),
"ganadoras": (pnl > 0).mean(), "peor": pnl.min(),
"dias": pd.Series(dias), "total": pnl.sum()})
return pnl, tabla
pnl, tabla = resultados(ops)
tabla.round(2) media mediana ganadoras peor dias total
mantener 0.29 0.55 0.95 -24.97 30.55 41.18
50 % 0.17 0.33 0.98 -24.97 11.41 23.80
21 días 0.23 0.25 0.85 -2.10 9.66 33.06
stop 2x 0.46 0.55 0.93 -3.53 29.78 65.75
50 % o 21 días 0.22 0.24 0.87 -2.10 7.91 31.46La tabla es el resumen que suele enseñarse para defender una regla, y cada columna cuenta una historia distinta. Cerrar al 50 % sube las operaciones ganadoras del 95 al 98 % y reduce la permanencia de 30,6 a 11,4 días, pero baja la media de 0,29 a 0,17 % por operación y conserva la peor, −24,97 %. Las reglas de 21 días y de stop recortan la peor operación a −2,10 y −3,53 %, y el stop suma 65,75 frente a 41,18 de mantener. Leída así, el stop parecería la mejor regla. Pero la tabla mezcla 140 meses normales con tres episodios:
peores = pnl["mantener"].nsmallest(3).index
print("Peores con «mantener»:",
[f.date().isoformat() for f in peores])
pd.DataFrame({"total": pnl.sum(),
"sin las 3 peores": pnl.drop(peores).sum(),
"en esas 3": pnl.loc[peores].sum()}).round(2)Peores con «mantener»: ['2020-02-21', '2018-01-19', '2018-09-21']
total sin las 3 peores en esas 3
mantener 41.18 78.29 -37.12
50 % 23.80 48.29 -24.49
21 días 33.06 33.20 -0.15
stop 2x 65.75 72.99 -7.24
50 % o 21 días 31.46 31.60 -0.15La figura de la cabecera separa las dos partes. Las tres peores operaciones de «mantener» son las abiertas en febrero de 2020, enero de 2018 y septiembre de 2018: en ellas, mantener pierde en total 37,1 puntos porcentuales del strike, y cualquier regla que salga antes pierde menos. En las otras 140, mantener es la que más suma (78,3), el stop queda cerca (73,0) y las reglas de tiempo se quedan en 33: cerrar a 21 días renuncia a la mitad de la theta de cada mes. La comparación entre reglas, con 143 ciclos, la deciden tres. Si la próxima crisis llega en un salto y no en varias sesiones, o en la segunda mitad del ciclo en vez de en la primera, el orden puede cambiar.
El stop tiene además un problema propio: se comprueba al cierre y se ejecuta donde está el mercado, no donde se puso.
salidas = []
for o in ops:
x, f = gestiona(o, stop=3.0)
if f < o["venc"]:
salidas.append({"entrada": o["entrada"].date(),
"salida": f.date(),
"perdida_en_creditos": -x / o["credito"]})
pd.DataFrame(salidas).round(2) entrada salida perdida_en_creditos
0 2014-02-21 2014-02-27 2.12
1 2016-06-17 2016-06-24 2.59
2 2018-01-19 2018-02-02 2.03
3 2018-09-21 2018-10-18 6.82
4 2020-02-21 2020-03-09 6.88
5 2022-06-17 2022-07-07 2.39
6 2025-02-21 2025-02-28 2.24
7 2025-03-21 2025-04-04 4.21De ocho stops, cinco se ejecutan entre 2,03 y 2,59 créditos de pérdida, cerca de los 2 previstos. Los de las operaciones abiertas en septiembre de 2018, febrero de 2020 y marzo de 2025 se ejecutan a 6,82, 6,88 y 4,21 créditos: la put pasó en una sola sesión de valer menos de tres créditos a valer más de cinco, o casi ocho. El de 2020 salta el 9 de marzo, el día del −7,9 % del README: un stop comprobado al cierre llega después del salto. Y un stop dentro de la sesión, sobre un precio de opción con horquillas que se abren en el estrés, salta con más facilidad por ruido.
Rodar y ajustar
Rodar (roll) es cerrar una posición y abrir otra parecida más lejos en el tiempo, en otro strike o ambas cosas. Se suele presentar como una forma de «dar tiempo» a una operación perdedora. Los números de los datos enseñan lo que es: dos operaciones. La put 2525 vendida el 19-01-2018 queda dentro del dinero el 5 de febrero, el día del salto del −4,2 % del README; se recompra al ask y se vende al bid una put de delta −0,16 del vencimiento siguiente:
o = next(o for o in ops if o["entrada"] == pd.Timestamp("2018-01-19"))
tocada = next(f for f in o["cot"].index if S[f] < o["strike"])
cierre = o["cot"].at[tocada, "ask"]
nueva = put_por_delta(tocada, next(
x for x in vencs if (x - tocada).days >= 20 and x > o["venc"]),
0.16)
v2, k2 = nueva["vencimiento"], nueva["strike"]
pago2 = max(k2 - S[v2], 0.0)
print(f"Vendida {o['entrada'].date()}: put {o['strike']:.0f} a "
f"{o['credito']}; tocada el {tocada.date()} con ORX {S[tocada]}")
print(f"Recompra al ask {cierre}; nueva put {k2:.0f} "
f"({v2.date()}) al bid {nueva['bid']}")
pd.Series({
"mantener": o["credito"] - max(o["strike"] - o["ST"], 0),
"cerrar al tocar": o["credito"] - cierre,
"rodar (cerrar + nueva)": (o["credito"] - cierre
+ nueva["bid"] - pago2),
" de ello, la nueva": nueva["bid"] - pago2,
}).round(2)Vendida 2018-01-19: put 2525 a 9.9; tocada el 2018-02-05 con ORX 2440.24
Recompra al ask 106.5; nueva put 2150 (2018-03-16) al bid 30.2
mantener -194.87
cerrar al tocar -96.60
rodar (cerrar + nueva) -66.40
de ello, la nueva 30.20
dtype: float64Mantenida, la put vendida a 9,9 puntos pierde 194,87. Cerrada al tocar, 96,60. El roll suma −66,40, pero esa cifra junta dos operaciones: la primera perdió 96,60 y quedó realizada en la recompra; la segunda, una put 2150 de marzo vendida a 30,2 con la volatilidad disparada, venció sin valor y ganó 30,20. Que la segunda saliera bien no tiene nada que ver con la primera: podría haberse abierto sin la primera, y habría ganado lo mismo. Juntarlas en un solo P&L hace parecer que el roll recuperó parte de la pérdida.
Los ajustes son variantes de lo mismo: añadir o quitar patas para cambiar las griegas. Con la herramienta de la lección 3.5.4 se pueden calcular antes de hacerlos:
| Ajuste | Ejemplo | Efecto principal |
|---|---|---|
| Comprar un ala | Convertir una put vendida en un put spread | Pérdida máxima acotada; menos theta y menos vega corta |
| Cubrir la delta | Vender o comprar subyacente o futuros | Delta a cero; gamma y vega sin cambios |
| Rodar la pata no tocada | En un strangle tras una caída, subir la call vendida | Recentra la delta cobrando algo más de prima; aumenta el riesgo si el mercado rebota |
| Reducir tamaño | Recomprar parte de los contratos | Todas las griegas en proporción; realiza parte de la pérdida |
Asignación temprana: opciones americanas con dividendos
Las opciones sobre acciones de EE. UU. son americanas: el titular puede ejercerlas cualquier día. Quien las tiene vendidas puede ser asignado antes del vencimiento. El reparto lo hace la cámara (OCC) entre sus miembros y cada bróker entre sus clientes con un método fijo, FIFO o aleatorio, que debe comunicar por escrito (regla 2360 de FINRA). Para saber cuándo ocurre, hay que saber cuándo le conviene al titular.
Una opción americana vale al menos su valor intrínseco. Si vale exactamente eso, ejercerla ya es óptimo: esperar no
añade nada. La cadena de KRN tiene, para cada opción, el precio americano (precio_modelo, árbol binomial de 150
pasos con dividendos discretos) y el de la misma opción europea (europea_modelo). La diferencia es la prima de
ejercicio anticipado:
krn = pd.read_csv("accion3_diario.csv", parse_dates=["fecha"])
krn = krn.set_index("fecha")["cierre"]
ev = pd.read_csv("accion3_eventos.csv", parse_dates=["fecha"])
divs = ev[ev["evento"] == "dividendo"].set_index("fecha")["dividendo"]
op_a = pd.read_parquet("accion3_opciones.parquet")
op_a["S"] = krn.reindex(op_a["fecha"]).to_numpy()
w = np.where(op_a["tipo"] == "C", 1.0, -1.0)
op_a["intr"] = np.maximum(w * (op_a["S"] - op_a["strike"]), 0)
op_a["valor_temporal"] = op_a["precio_modelo"] - op_a["intr"]
op_a["prima_ejercicio"] = (op_a["precio_modelo"]
- op_a["europea_modelo"])
# precio = intrínseco (± el redondeo del cierre y del árbol):
# ejercer ya o en la próxima ocasión da lo mismo
op_a["ejercer"] = op_a["valor_temporal"] < 0.02
dentro = op_a[op_a["intr"] > 0]
dentro.groupby("tipo")[["prima_ejercicio", "ejercer"]].agg(
["mean", "max"]).round(3) prima_ejercicio ejercer
mean max mean max
tipo
C 0.188 1.019 0.022 True
P 0.335 2.348 0.229 TrueEntre las opciones dentro del dinero, la prima de ejercicio anticipado media es de 0,19 USD en las calls y de 0,34 en las puts, con máximos de 1,02 y 2,35 USD. La celda considera óptimo ejercer cuando el precio americano supera al intrínseco en menos de 2 céntimos: el cierre está redondeado al céntimo y el árbol, con pasos de unas horas, deja algún céntimo de valor a ejercer en el paso siguiente. Con ese criterio, ejercer ya es óptimo en el 2,2 % de las filas de calls dentro del dinero y en el 22,9 % de las de puts. Son dos mecanismos distintos.
Calls: el dividendo
Una call no paga dividendo; la acción sí. La víspera de la fecha ex, el titular de una call dentro del dinero compara dos cosas: si ejerce, recibe la acción y cobra el dividendo ; si no, la acción cae al día siguiente y él conserva el valor temporal de la opción. Por la paridad put-call, ese valor temporal es aproximadamente el de la put del mismo strike más el interés del strike hasta el vencimiento. Ejercer solo puede convenir si
con el tiempo desde la fecha ex hasta el vencimiento. La celda lo contrasta con el árbol en todas las vísperas de fecha ex de los datos:
sesiones = krn.index
vispera = {sesiones[sesiones.get_loc(d) - 1]: d for d in divs.index}
c = dentro[(dentro["tipo"] == "C")
& dentro["fecha"].isin(list(vispera))].copy()
c["ex"] = c["fecha"].map(vispera)
c = c[c["vencimiento"] >= c["ex"]]
c["D"] = c["ex"].map(divs)
eu_put = op_a[op_a["tipo"] == "P"].set_index(
["fecha", "vencimiento", "strike"])["europea_modelo"]
c["put"] = eu_put.reindex(
pd.MultiIndex.from_frame(c[["fecha", "vencimiento", "strike"]])
).to_numpy()
tau = (c["vencimiento"] - c["ex"]).dt.days / 365
r_c = ind["tipo_1m"].reindex(c["fecha"]).to_numpy() / 100
# lo que se pierde al ejercer: el seguro de la put y el interés
# del strike hasta el vencimiento
c["umbral"] = c["put"] + c["strike"] * (1 - np.exp(-r_c * tau))
c["regla"] = c["D"] > c["umbral"]
print(len(c), "calls dentro del dinero en las vísperas")
print(pd.crosstab(c["ejercer"], c["regla"],
rownames=["árbol: ejercer"], colnames=["regla"]))
c[c["ejercer"]].groupby(c["fecha"].dt.year).size()494 calls dentro del dinero en las vísperas
regla False True
árbol: ejercer
False 324 66
True 0 104
fecha
2022 46
2023 22
2024 14
2025 22
dtype: int64De 494 calls dentro del dinero en las vísperas, el árbol ejerce 104 y la regla marca esas 104 y 66 más. Es una condición necesaria, no suficiente: en las 66 restantes el árbol todavía encuentra valor temporal (la aproximación ignora la volatilidad que queda hasta el vencimiento, más allá del seguro de la put). Los ejercicios óptimos aparecen todos los años (46 en 2022, 22 en 2023, 14 en 2024 y 22 en 2025) y siempre en la serie que vence una o dos semanas después de la fecha ex: cuanto menos tiempo queda, menos valor temporal se sacrifica. Un ejemplo, la call 95 que vence el 18-02-2022 con la acción en 106-110 USD:
ej = op_a[(op_a["tipo"] == "C") & (op_a["strike"] == 95)
& (op_a["vencimiento"] == pd.Timestamp("2022-02-18"))]
ej = ej.set_index("fecha").loc["2022-01-27":"2022-02-17"]
ej = ej.assign(europea_menos_intr=ej["europea_modelo"] - ej["intr"])
ej[["S", "precio_modelo", "intr", "valor_temporal",
"europea_menos_intr"]].iloc[[0, 5, 8, 9, 10, 12]].round(3) S precio_modelo intr valor_temporal europea_menos_intr
fecha
2022-01-27 109.79 14.806 14.79 0.016 -0.821
2022-02-03 110.43 15.436 15.43 0.006 -0.850
2022-02-08 106.78 11.779 11.78 -0.001 -0.847
2022-02-09 106.84 11.835 11.84 -0.005 -0.857
2022-02-10 106.62 11.639 11.62 0.019 0.019
2022-02-14 105.60 10.606 10.60 0.006 0.006La americana vale su intrínseco más 0,016 USD el 27 de enero y prácticamente nada en la semana anterior a la fecha ex (0,006 el 3 de febrero; −0,001 y −0,005 en las dos vísperas, por el redondeo del cierre). La europea vale entre 0,82 y 0,86 USD menos que su intrínseco: no puede ejercerse y perderá el dividendo de 0,88. Desde el 10 de febrero, sin dividendos pendientes, las dos coinciden. Quien tenga esa call vendida debe contar con ser asignado la víspera: entregará 100 acciones por contrato y, si no las tenía, quedará corto en la fecha ex y deberá el dividendo. El diagrama resume la comprobación que hace un vendedor de calls antes de cada fecha ex (VT es el valor temporal de la call, D el dividendo):
Fuente Mermaid
flowchart TB
A{Call corta ITM} --> B{Fecha ex antes}
B -- no --> C[Riesgo bajo]
B -- sí --> D{VT menor que D}
D -- no --> C
D -- sí --> E[Espera asignación]
E --> F[Cerrar o rodar]Puts: el interés del strike
Una put muy dentro del dinero es casi una venta a plazo de la acción a precio K. Ejercerla adelanta el cobro de K, que rinde intereses; esperar conserva un seguro contra que la acción vuelva a subir por encima de K, que vale poco si la put está muy dentro del dinero. Con tipos positivos, a partir de cierta distancia ejercer es óptimo:
p = dentro[dentro["tipo"] == "P"].copy()
p["dentro_pct"] = 100 * (p["strike"] / p["S"] - 1)
tramo = pd.cut(p["dentro_pct"], [0, 2, 5, 10, 20, 60])
p.groupby(tramo, observed=True).agg(
filas=("ejercer", "size"), ejercer=("ejercer", "mean"),
prima_media=("prima_ejercicio", "mean")).round(3) filas ejercer prima_media
dentro_pct
(0, 2] 3594 0.001 0.065
(2, 5] 5412 0.034 0.099
(5, 10] 8991 0.122 0.184
(10, 20] 9438 0.337 0.377
(20, 60] 7396 0.476 0.767Cerca del dinero el ejercicio casi nunca es óptimo (0,1 % de las filas). A más de un 10 % dentro del dinero lo es en un tercio de las filas (33,7 %), y a más de un 20 % en casi la mitad (47,6 %). La prima de ejercicio anticipado crece con la distancia, de 0,07 a 0,77 USD de media. Para quien vende puts sobre acciones, una caída fuerte trae una asignación anticipada probable: la compra de 100 acciones por contrato antes de lo previsto, que hay que financiar.
Pin risk en el vencimiento
En las opciones con entrega física, el día del vencimiento las que acaban dentro del dinero se ejercen automáticamente salvo instrucción contraria (el procedimiento de ejercicio por excepción de la regla 805 de la OCC) y el titular tiene hasta las 17:30 ET para decidir (regla 2360 de FINRA). Si la acción cierra justo en el strike, quien vendió no sabe hasta el día siguiente si será asignado: depende de lo que haga el precio después del cierre y de lo que decidan los titulares. Es el pin risk.
filas = []
for v in sorted(op_a["vencimiento"].unique()):
if v > sesiones[-1]:
continue
ultimo = op_a.loc[op_a["vencimiento"] == v, "fecha"].max()
ks = op_a[(op_a["fecha"] == ultimo) & (op_a["vencimiento"] == v)
& (op_a["tipo"] == "C")].set_index("strike")
k = ks.index[np.abs(ks.index - krn[v]).argmin()]
filas.append({"vencimiento": v.date(), "cierre": krn[v],
"strike": k, "distancia": krn[v] - k,
"interes_abierto": ks.at[k, "interes_abierto"]})
pin = pd.DataFrame(filas)
cerca = pin["distancia"].abs() <= 0.25
print(f"{cerca.sum()} de {len(pin)} vencimientos a 0,25 USD o menos "
f"de un strike (al azar: {len(pin) * 0.5 / 2.5:.1f})")
pin[cerca].tail(4)11 de 48 vencimientos a 0,25 USD o menos de un strike (al azar: 9.6)
vencimiento cierre strike distancia interes_abierto
28 2024-05-17 137.35 137.5 -0.15 5368
30 2024-07-19 159.84 160.0 -0.16 4967
37 2025-02-21 192.32 192.5 -0.18 6418
46 2025-11-21 172.67 172.5 0.17 4853En los datos, 11 de los 48 vencimientos de KRN cierran a 0,25 USD o menos de un strike, frente a 9,6 que daría el azar con strikes de 2,5 en 2,5: en los datos no hay atracción hacia los strikes, solo aritmética. En mercados reales la literatura documenta que los cierres de las acciones con opciones listadas se agrupan cerca de los strikes los días de vencimiento (Ni, Pearson y Poteshman, 2005, en los recursos). Uno de los casos de los datos, el 19-07-2024:
rv = np.log(krn).diff().std() # desviación típica diaria
S_v, K_v, n = 159.84, 160.0, 10
print(f"Volatilidad diaria de KRN: {rv:.2%}")
print(f"Si no hay asignación: 0 acciones. Si la hay: "
f"{-100 * n} acciones a {K_v}")
print(f"Riesgo de un día de 1000 acciones: "
f"{1000 * S_v * rv:,.0f} USD (1 desviación típica)")Volatilidad diaria de KRN: 1.69%
Si no hay asignación: 0 acciones. Si la hay: -1000 acciones a 160.0
Riesgo de un día de 1000 acciones: 2,708 USD (1 desviación típica)KRN cierra a 159,84 con 4.967 contratos abiertos en el strike 160. Con 10 calls 160 vendidas, el lunes la posición puede ser cero acciones o −1.000. Si hay noticias después del cierre y la acción sube, los titulares ejercerán. Un día de 1.000 acciones de KRN es un riesgo de unos 2.700 USD por desviación típica; un resultado o una noticia de fin de semana, varias veces eso. El mismo problema, al revés, tienen las puts vendidas.
La delta explica por qué no se puede cubrir con antelación:
Sg = np.array([155.0, 158.0, 159.0, 159.5, 160.0, 160.5, 161.0,
162.0, 165.0])
perfil = {f"{d} días": delta_bsm("C", Sg, 160.0, d / 365, 0.25,
0.04, 0.0)
for d in (10, 2, 0.25)}
pd.DataFrame(perfil, index=Sg).round(3) 10 días 2 días 0.25 días
155.0 0.236 0.045 0.000
158.0 0.399 0.255 0.028
159.0 0.458 0.375 0.171
159.5 0.489 0.441 0.319
160.0 0.519 0.508 0.503
160.5 0.549 0.575 0.686
161.0 0.578 0.640 0.831
162.0 0.636 0.756 0.972
165.0 0.785 0.954 1.000A 10 días, la delta de la call 160 pasa de 0,24 a 0,79 entre 155 y 165. A 6 horas del vencimiento es casi un escalón: 0,03 en 158, 0,50 en 160 y 0,97 en 162. Cubrir la delta de una opción pegada al strike en la última sesión obliga a comprar y vender casi todo el nominal con cada movimiento de un dólar (lección 3.6.2). La solución práctica es cerrar las posiciones vendidas cercanas al strike antes del cierre del día del vencimiento, aceptando la horquilla.
Índices con liquidación en efectivo
Las opciones sobre índices como las SPX son europeas y se liquidan en efectivo: no hay asignación anticipada ni entrega de acciones, y desaparecen los dos riesgos anteriores. Queda otro: el precio de liquidación. En las SPX estándar, según la ficha de Cboe, la negociación termina la víspera (normalmente un jueves) y el valor de liquidación (SET) se calcula con los precios de apertura de los componentes el día del vencimiento: una posición mantenida hasta el final queda expuesta a la apertura del viernes sin poder cerrarse. En los datos de ORX se liquida al cierre del día del vencimiento, por simplicidad. Antes de mantener una posición hasta el vencimiento hay que leer en la ficha del contrato cómo y cuándo se fija el precio de liquidación.
Ejercicios
- Otra delta. Repite la tabla de reglas y la separación de las tres peores operaciones con puts de delta −0,30. ¿Cambia la conclusión?
Solución
Con puts más cercanas al dinero el crédito es mayor y la conclusión se mantiene. En total, el stop suma 90,05 y mantener 68,41; sin las tres peores operaciones, mantener suma 113,62 y el stop 105,94. Las reglas de tiempo se quedan en 48-49 con o sin esos episodios: cortan la cola y renuncian a buena parte de la theta. La peor operación de mantener empeora a −26,01 % y la del stop a −10,02 %: con más delta, el salto que se come el stop es mayor.
ops30 = ciclo(0.30)
pnl30, tabla30 = resultados(ops30)
peores30 = pnl30["mantener"].nsmallest(3).index
print(tabla30.round(2))
pd.DataFrame({"total": pnl30.sum(),
"sin las 3 peores": pnl30.drop(peores30).sum()}).round(2) media mediana ganadoras peor dias total
mantener 0.48 0.98 0.89 -26.01 30.55 68.41
50 % 0.27 0.59 0.93 -26.01 13.58 39.12
21 días 0.35 0.39 0.83 -4.73 9.66 49.47
stop 2x 0.63 0.96 0.86 -10.02 29.65 90.05
50 % o 21 días 0.32 0.39 0.83 -4.73 8.32 45.27
total sin las 3 peores
mantener 68.41 113.62
50 % 39.12 62.82
21 días 49.47 48.26
stop 2x 90.05 105.94
50 % o 21 días 45.27 44.07- Rodar sin bajar el strike. En el ejemplo de 2018, en vez de vender la put de delta −0,16 de marzo, vende la put 2525 de marzo (mismo strike, más tiempo). Calcula el crédito del roll y el resultado de la nueva operación.
Solución
Vender el mismo strike un mes más lejos cobra 32,6 puntos más de lo que cuesta la recompra (un roll a crédito), pero la nueva put está dentro del dinero: es una apuesta mucho mayor que la de delta −0,16. ORX vence en marzo a 2315,19 y la nueva operación pierde 70,71 puntos. Sumadas, las dos operaciones pierden 167,3 (−96,6 de la primera y −70,7 de la segunda), casi tanto como mantener la original (−194,87). El crédito del roll no era una ganancia: era la prima de un riesgo nuevo.
fila = por_dia[tocada]
fila = fila[(fila["vencimiento"] == v2)
& (fila["strike"] == o["strike"])].iloc[0]
pago = max(o["strike"] - S[v2], 0.0)
print(f"Recompra {cierre} · venta de la 2525 de marzo a "
f"{fila['bid']} · crédito del roll {fila['bid'] - cierre:.1f}")
print(f"ORX el {v2.date()}: {S[v2]} · resultado de la nueva: "
f"{fila['bid'] - pago:.2f}")Recompra 106.5 · venta de la 2525 de marzo a 139.1 · crédito del roll 32.6
ORX el 2018-03-16: 2315.19 · resultado de la nueva: -70.71- Pin risk. Tienes 10 calls 160 de KRN vendidas y la acción cotiza a 159,90 a falta de una hora para el cierre del día del vencimiento. Enumera tus opciones y qué riesgo deja cada una.
Solución
Recomprar las calls: paga la horquilla y elimina el riesgo. No hacer nada: si la acción cierra por debajo de 160 y no hay noticias, vencen sin valor; si sube después del cierre, pueden asignarte y el lunes estarás corto de 1.000 acciones (unos 2.700 USD de riesgo por desviación típica de un día, más si hay noticias). Comprar 500 acciones como cobertura parcial: deja una posición de +500 o −500 acciones según haya o no asignación, la misma incertidumbre con otro signo. Rodar al vencimiento siguiente: cierra el riesgo de hoy y abre una posición nueva, que se evalúa como tal. La opción más común en una mesa es recomprar las posiciones vendidas a menos de un strike del precio antes del cierre.
Respuesta plegada en cada pregunta
Autoevaluación
En la venta mensual de puts de delta −0,16, la regla «cerrar al 50 % del crédito» gana más a menudo (98 % de operaciones ganadoras) pero suma menos que mantener (23,8 frente a 41,2 % del strike). ¿Por qué?
- APorque paga más comisiones
- BPorque renuncia a la theta de los días que quedan en las operaciones normales y no protege de las caídas que llegan antes de alcanzar el objetivo: su peor operación es la misma, −25,0 %
- CPorque el 50 % es un objetivo demasiado ambicioso
- DPorque el cierre al ask es gratuito
Ver respuesta
Respuesta B. Porque renuncia a la theta de los días que quedan en las operaciones normales y no protege de las caídas que llegan antes de alcanzar el objetivo: su peor operación es la misma, −25,0 %
Un objetivo de beneficio solo actúa cuando la operación va bien. La caída de febrero de 2020 llegó antes de que la put perdiera la mitad de su valor, así que la regla la sufre entera. En las 140 operaciones normales suma 48,3 frente a 78,3 de mantener.
El stop al doble del crédito suma 65,8 frente a 41,2 de mantener. ¿Qué conclusión es correcta?
- AQue el stop es una ventaja demostrada en ventas de prima
- BQue la diferencia la deciden tres operaciones: sin ellas, mantener suma 78,3 y el stop 73,0; con 143 ciclos, la comparación depende de cómo se desarrollaron tres episodios
- CQue mantener tiene un error de cálculo
- DQue el stop elimina el riesgo de cola
Ver respuesta
Respuesta B. Que la diferencia la deciden tres operaciones: sin ellas, mantener suma 78,3 y el stop 73,0; con 143 ciclos, la comparación depende de cómo se desarrollaron tres episodios
En las 140 operaciones normales el stop salta alguna vez y pierde lo que mantener habría recuperado. Su ventaja total sale de 2018 y 2020, cuando la caída se desarrolló en varias sesiones. En un salto de apertura, un stop se ejecuta mucho más lejos: en los datos, hasta 6,9 veces el crédito en vez de 2.
Una put vendida se recompra a 106,5 y en el mismo momento se vende otra de un vencimiento posterior a 30,2. ¿Cuál es el resultado de la operación original?
- A−66,4 puntos, porque el roll se cobra a crédito
- BEl crédito inicial menos 106,5 (−96,6 puntos): el roll es un cierre y una apertura; los 30,2 son la prima de una operación nueva, con su propio riesgo
- CCero, porque se ha rodado
- DNo se sabe hasta el nuevo vencimiento
Ver respuesta
Respuesta B. El crédito inicial menos 106,5 (−96,6 puntos): el roll es un cierre y una apertura; los 30,2 son la prima de una operación nueva, con su propio riesgo
Rodar no repara una pérdida: la realiza y abre otra posición. En el ejemplo de 2018, la nueva put venció sin valor y sumó 30,2 puntos, pero podría no haber sido así; juntar las dos operaciones esconde la pérdida de la primera.
La víspera de la fecha ex, una call americana de KRN muy dentro del dinero vale exactamente su intrínseco y la europea equivalente 0,86 USD menos. ¿Qué hace un titular racional y qué le pasa a quien la tiene vendida?
- ANada: las opciones no tienen dividendos
- BEjerce para cobrar el dividendo de 0,88 USD; el vendedor es asignado, entrega las acciones y pierde ese dividendo
- CVende la acción
- DEspera al vencimiento, porque ejercer antes nunca es óptimo
Ver respuesta
Respuesta B. Ejerce para cobrar el dividendo de 0,88 USD; el vendedor es asignado, entrega las acciones y pierde ese dividendo
Ejercer antes de la fecha ex da derecho al dividendo; esperar conserva un valor temporal que aquí es casi nulo. Para el vendedor, la asignación llega antes de la fecha ex y tiene que entregar las acciones (o queda corto de ellas y debe el dividendo).
KRN cierra a 159,84 USD el día del vencimiento y tienes 10 calls 160 vendidas. ¿Cuál es el riesgo?
- ANinguno: las calls vencen fuera del dinero
- BNo saber hasta después del cierre si te asignarán: el titular puede decidir ejercer hasta las 17:30 ET; el lunes puedes amanecer corto de 1.000 acciones, con un riesgo de un día de unos 2.700 USD por desviación típica
- CQue el bróker cobre una comisión
- DQue las calls valgan más de 160
Ver respuesta
Respuesta B. No saber hasta después del cierre si te asignarán: el titular puede decidir ejercer hasta las 17:30 ET; el lunes puedes amanecer corto de 1.000 acciones, con un riesgo de un día de unos 2.700 USD por desviación típica
Las opciones fuera del dinero por céntimos no se ejercen automáticamente, pero el titular puede presentar una instrucción contraria hasta el corte de las 17:30 ET (regla 2360 de FINRA). Con noticias después del cierre, lo hará. El vendedor no lo sabrá hasta el día siguiente.
Ideas clave
- Las reglas de gestión cambian la forma del resultado, no crean ventaja: cerrar al 50 % sube el porcentaje de aciertos y baja la suma; cerrar por tiempo o por pérdida corta la cola a costa de las operaciones normales.
- En una venta de prima la comparación entre reglas la deciden muy pocas operaciones (aquí, 3 de 143): antes de elegir una regla, mira de dónde sale la diferencia.
- Un stop en opciones se comprueba al cierre y se ejecuta al ask: en los saltos se ejecuta mucho más lejos de donde se puso.
- Rodar es cerrar y abrir. La pérdida de la primera operación queda realizada; la segunda es una apuesta nueva.
- Las opciones americanas sobre acciones pueden ejercerse antes del vencimiento: calls muy dentro del dinero antes de la fecha ex y puts muy dentro del dinero con tipos positivos. El vendedor debe vigilarlo.
- Un cierre pegado al strike de una opción con entrega física deja la posición del lunes en el aire: ciérrala antes del vencimiento si no aceptas la incertidumbre.
Recursos
Documentación
- FINRA: regla 2360 (ejercicio por excepción, corte de las 17:30 ET y asignación aleatoria o FIFO)
- Cboe: especificaciones de las opciones sobre el S&P 500 (estilo europeo, liquidación SET)
- Ni, Pearson y Poteshman (2005), Stock price clustering on option expiration dates, Journal of Financial Economics 78