---
title: "3.6.1 Systematic premium selling and tail risk"
description: "Put-write and short strangles on an option chain with the tail in view: worst months, leverage, Cboe margin and stress-based sizing."
url: "https://pythonparatrading.com/en/python-trading-course/level-3/systematic-premium-selling-tail-risk/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-3/systematic-premium-selling-tail-risk.png"
---

# 3.6.1 · Systematic premium selling: put-write, strangles and their tail risk

> Selling options every month collects the volatility risk premium: implied volatility tends to sit above realized. This lesson replicates on the level's synthetic data a put-selling strategy like the Cboe PUT index and a 0.16 delta strangle, measures them by their worst episode and not only by their Sharpe, and computes how much notional the margin allows and how much the capital can withstand.

- Course: [Level 3: Derivatives: futures, spreads, forex and options](https://pythonparatrading.com/en/python-trading-course/level-3/)
- Module: 3.6 · Systematic volatility and options strategies
- Duration: 70 min
- Prerequisites: [3.4.6 · Realized vs implied volatility; volatility risk premium; VIX and VSTOXX](https://pythonparatrading.com/en/python-trading-course/level-3/realized-vs-implied-volatility-vix/), [3.5.2 · Volatility and range structures: straddles, strangles, condors and butterflies](https://pythonparatrading.com/en/python-trading-course/level-3/straddles-strangles-condors-butterflies/), [3.5.4 · A custom tool: payoff, aggregate Greeks and scenarios](https://pythonparatrading.com/en/python-trading-course/level-3/option-payoff-greeks-scenario-tool/), [3.5.5 · Management: adjustments, rolls, early closes, early assignment and pin risk](https://pythonparatrading.com/en/python-trading-course/level-3/managing-option-positions/)

## By the end of this lesson

- Replicate a monthly cash-secured put sale following the methodology of the Cboe PUT index and a delta-based strangle sale, collecting at the bid and marking at the mid.
- Measure a premium-selling strategy with Sharpe, CAGR, maximum drawdown, monthly skewness and worst months, and explain why the Sharpe alone is misleading.
- Break the strangle down into its legs and explain why it loses in a sample with a bull market.
- Compute the margin of a naked short index put with the Cboe rule and the leverage it allows.
- Size a premium sale with stress scenarios and with the worst episode in the data, and see what happens with more leverage.

## What is collected by selling premium

Lesson 3.4.6 measured the volatility risk premium: the implied volatility of index options tends to sit above the
volatility that is later realized. Whoever sells options collects that difference systematically. What lesson 3.4.6
did not do is turn it into a strategy and see what happens to the capital. In the level's synthetic data, with the
VIX-style index (VORX) of the ORX chain:

```python
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"]

# volatility risk premium: VORX versus the realized volatility of
# the next 21 sessions (lesson 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 - realized: mean {vrp.mean():.1f}, median "
      f"{vrp.median():.1f} points; realized exceeds VORX on "
      f"{(vrp < 0).mean():.0%} of days; worst {vrp.min():.0f}")
```
```output
VORX - realized: mean 5.4, median 6.5 points; realized exceeds VORX on 12% of days; worst -78
```

VORX exceeds the realized volatility of the next 21 sessions by 5.4 points on average (median 6.5). But the
difference is not stable: on 12% of days realized volatility exceeds VORX, and in March 2020 it exceeds it by up to 78
points. That is the whole business of premium selling: collecting a few points almost always and paying dozens
sometimes. A premium-selling strategy is insurance sold, and like any insurer it has to be measured by the claim, not
by the premium.

The strategies in the lesson follow the same monthly cycle:

```mermaid
flowchart LR
  V[Sell at the bid] --> M[Mark at mid]
  M --> L[Settle at expiry]
  L --> R[Reinvest cash]
  R --> V
```

## Put-write: replicating the Cboe PUT index

The Cboe S&P 500 PutWrite index (PUT) is the public benchmark for systematic put selling. According to its
methodology, every month, normally on the third Friday, it sells an at-the-money monthly S&P 500 put: the listed
strike closest to the index without exceeding it. It sells it at the volume-weighted average price between 11:30 and
12:00 ET, holds it until expiration (it is settled with the special opening quotation, SOQ) and leaves the cash in
one- and three-month Treasury bills. The number of puts is set so that the cash covers the maximum settlement loss:
it is a cash-secured sale, without leverage.

The replication with the ORX data follows those rules with three differences imposed by daily data: it sells at the
bid of the close on expiration day (instead of the mid-morning average price), settles at the close (ORX options
expire at the close) and sets the number of puts with the cash before collecting the premium (somewhat more
conservative than the Cboe formula, which counts the premium and the interest). The same function also sells
strangles and each of their legs by delta, with the notional equal to the index:

```python
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):
    """Equity curve (starts at 1) of selling premium every month.

    “put”: at-the-money put (highest strike <= index) with a
    notional of apal × capital in strikes, like the Cboe PUT index
    when apal = 1. “strangle”, “put_d”, “call_d”: legs of
    delta ±delta with notional apal × capital in index. Sale at the bid
    (or at the mid) on the day of each expiration, of the next
    expiration with 20 days or more; daily marking at the mid;
    settlement at the expiration close; cash at the 1-month rate."""
    caja, patas, venc, eq, ultimo = 1.0, [], None, {}, 1.0
    for f in S.index:
        g = por_dia.get(f)  # None: day without a chain
        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:  # ruin: the cash does not cover the settlement
            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  # no quote: the previous mark
        else:
            eq[f] = ultimo = caja - marca
        caja *= np.exp(rf[f] / 252)
    return pd.Series(eq)
```

The `apal` parameter multiplies the notional per unit of capital: with 1, each unit of capital backs one unit of
strike (or of index); with 3, three. If the cash is not enough to pay a settlement, the account is ruined and the
curve stays at zero.

## Results with the tail in view

The standard metric, the Sharpe, is computed with the standard deviation of daily returns. In a strategy with its
tail on the left, the normal months set the standard deviation, and the tail barely weighs on it. That is why each
result comes with its maximum drawdown, its monthly skewness and its worst month:

```python
def metricas(eq):
    """Sharpe of the daily excess over the 1-month rate, CAGR,
    maximum drawdown, skewness and worst month (with its date)."""
    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 = {"TR index": ind["cierre_rt"] / ind["cierre_rt"].iloc[0],
          "put-write": venta_prima("put"),
          "put-write at mid": 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)
```
```output
                  sharpe   cagr  max_caida  asim_mensual  peor_mes fecha_peor
TR index           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 at mid   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-08
```

The header figure compares the put-write with the total return index. The put-write has a Sharpe of 0.52 versus 0.66
for the index and half of its CAGR (6.8% versus 12.5%), but not half of its risk: its maximum drawdown, −39.5%, is
practically that of the index (−39.9%), and its monthly skewness is −3.7 versus −0.8. Collecting at the mid instead
of at the bid barely changes anything (0.53): in an at-the-money put on a liquid index the bid-ask spread is small
relative to the premium. With real data, costs and execution weigh more in out-of-the-money options (lesson 3.6.4).

The figures in the data say nothing about what the strategy returns in real markets: they are synthetic, with the
volatility risk premium planted by the generator (data README). What they do show is its shape:

```python
mensual = pd.DataFrame({k: curvas[k].resample("ME").last().pct_change()
                        for k in ("TR index", "put-write")}).dropna()
mensual.index = mensual.index.strftime("%Y-%m")
peores = mensual.nsmallest(6, "put-write")
print(f"Months: {len(mensual)} · put-write positive in "
      f"{(mensual['put-write'] > 0).mean():.0%}")
(100 * peores).round(1)
```
```output
Months: 143 · put-write positive in 78%
         TR index  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.5
```

*Fig. — Distribution of the 143 monthly put-write returns on ORX, 2014-2025, in one-point bins: many small positive months and a long left tail.* Histogram of 143 months. 55 months lie between +1 and +2% and 28 between 0 and +1%; 78% are positive. On the left, a long and almost empty tail: one month between −9 and −8%, another between −8 and −7% and, isolated, May 2020 (−21.2%) and March 2020 (−23.2%, highlighted). On the right, a single month above +5%: +14%.

The put-write wins in 78% of months; 55 of the 143 fall between +1 and +2%. The two worst, March and May 2020 (−23.2
and −21.2%), add up to −44.4%: about thirty good months of +1.5%. In March 2020 the put-write loses more than the
index (−23.2 versus −19.5%): the put sold on 21 February is settled on 20 March, near the low, and the index recovers
somewhat in the last week of the month. In May, the second leg of the synthetic drop in the data, it loses less than
the index (−21.2 versus −28.8%): the May put was sold on 17 April with an implied volatility of 49% and collected
5.46% of the strike, versus 1.14% for the put sold on 21 February.

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

A premium sale with a Sharpe of 0.5 and a tail of −23% in a month is a profile many people cannot stomach: after
years of small, regular returns, the crisis arrives in weeks. A premium-selling strategy is always presented with its
worst episode, and never as income.

</aside>

## The 0.16 delta strangle: why it loses in this sample

The short strangle adds an out-of-the-money call to the put. It collects two premiums and, on paper, “wins if the
market does not move much”. In the table it has a Sharpe of −0.16, a CAGR of 0.2% and a maximum drawdown of −42.1%:
worse than the put alone (0.47 and −27.4%). The reason lies in the legs:

```python
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Δ"]),
                      "index": log_anual(curvas["TR index"])})
c = patas["call 16Δ"]
print(f"Call 16Δ: 2020-2021 {c.loc[[2020, 2021]].sum():.2f} in log; "
      f"other years {c.drop([2020, 2021]).mean():.3f} on average")
(100 * patas).round(1).T
```
```output
Call 16Δ: 2020-2021 -0.43 in log; other years 0.012 on average
          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
index      8.7  -0.0  22.6  12.4 -12.0  24.3  10.0  29.1 -21.1  20.4  33.2  13.7
```

*Fig. — Short ±0.16 delta strangle on ORX by leg: annual (log) return of selling only the put and only the call, 2014-2025.* Bars by year. The −0.16 delta put gains every year except 2018 (−4.0) and 2020 (−18.0), between +4.0 and +11.7 in the others. The 0.16 delta call loses in 2014-2016 (−2.6 to −4.3), in 2020 (−25.7, highlighted) and in 2021 (−16.9): the rebound after the fall and the 2021 rally take in two years everything it gains in the others, between +0.6 and +4.9.

The −0.16 delta put wins every year except 2018 (−4.0%) and 2020 (−18.0%). The 0.16 delta call loses in 2014-2016
and, above all, in 2020 and 2021: −25.7% and −16.9% in log, −0.43 in total, when the index rebounds after the drop
and rises 29.1% (in log) in 2021. In the other years it earns 1.2% on average: little, because the skew makes
out-of-the-money calls cheap and the premium collected is small. The result is a call leg that loses 2.6% a year in
the sample.

It is not a law: with another sample, without such a bullish market, the call leg could win. What it shows is that a
strangle is two bets: one on the left tail, well paid by the skew, and another on the right tail, poorly paid. Each
leg is measured separately before combining them.

## Sizing by margin: what the broker allows

A naked short put does not need the whole strike in cash: the broker requires a margin. The Cboe SPX specifications
set it for naked short index options at 100% of the premium plus 15% of the index value times the multiplier, minus
the amount the option is out of the money, with a minimum for puts of the premium plus 10% of the strike times the
multiplier. Applied to ORX two months before the drop:

```python
def margen_put(prima, S, K, mult=100):
    """Margin per contract of a naked short index put
    (Cboe SPX specifications): 100% of the premium + 15% of the
    index notional - the out-of-the-money amount, with a
    minimum of premium + 10% of the strike notional."""
    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 on {f0.date()}: {S[f0]}")
pd.DataFrame(filas).round(2)
```
```output
ORX on 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.13
```

An ATM put requires 45,976 USD of collateral for 285,000 of notional: the margin allows 6.2 times the capital in
notional. The −0.16 delta one, further from the money, needs even less margin: 8.1 times. The margin is designed to cover
the move of a few days with a cushion, not a crisis.

## Leverage and ruin

The same put-write, with more notional per unit of capital:

```python
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)
```
```output
     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.0
```

*Fig. — The same put-write on ORX with more notional per unit of capital, 2014-2025: compound annual return and maximum drawdown. At 4 times capital, the account runs out of collateral in March 2020.* Bars by leverage. 1×: CAGR +6.8% and maximum drawdown −39.5%. 1.5×: +8.6% and −55.7%. 2×: +9.7% and −69.6%. 3×: +7.8% and −91.4%. 4× (highlighted): ruin, the account goes negative. Return grows little and stops growing beyond 2×; the drawdown grows almost proportionally.

With 1.5 times the notional, the CAGR rises from 6.8 to 8.6% and the maximum drawdown goes from −39.5 to −55.7%. With
2 times, 9.7% and −69.6%. With 3 times the CAGR already falls (7.8%) and the drawdown is −91.4%: the account loses
nine tenths in March 2020. With 4 times, the account goes negative on 16 March 2020 and does not survive the
expiration: ruin, with a measured drawdown of −121.7% (the account owes money to the broker). The return grows little
and stops growing; the drawdown grows almost proportionally: beyond a certain leverage, large losses eat up the
compounded return.

All those leverages fit within the margin of the previous cell (6.2 times). The margin is not a risk limit: it is a
minimum the broker sets to protect itself.

## Stress-based sizing

A risk limit is set the other way around: you choose how much of the capital you accept losing in an extreme
scenario and compute the notional that meets it. The tool from lesson 3.5.4 does the repricing; here the ATM put of
2019-12-20 is enough, repriced with Black-Scholes if the scenario happens the next day:

```python
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))


# the ATM put of 2019-12-20 (previous cell), repriced if the
# scenario happens the next day
atm = filas[0]
K0, T0 = atm["strike"], (v0 - f0).days / AÑO - 1 / AÑO
escenarios = {"10% drop, vol 35%": (0.90, 0.35),
              "20% drop, vol 60%": (0.80, 0.60),
              "30% drop, 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  # % of notional
    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": "worst month in the data",
                "pérdida_%": peor_hist,
                "apal_20%": 20 / peor_hist,
                "con_apal_max_%": peor_hist * atm["apal_max"]})
print(f"Put {K0:.0f} sold at {atm['prima']}: "
      f"{100 * atm['prima'] / K0:.2f}% of notional")
pd.DataFrame(filas_e).set_index("escenario").round(2)
```
```output
Put 2850 sold at 32.5: 1.14% of notional
                         pérdida_%  apal_20%  con_apal_max_%
escenario
10% drop, vol 35%             9.46      2.11           58.63
20% drop, vol 60%            19.41      1.03          120.32
30% drop, vol 80%            29.21      0.68          181.06
worst month in the data      23.24      0.86          144.09
```

The put was sold at 32.5 points, 1.14% of its notional. With a 20% drop and volatility at 60% (a month like March
2020), it loses 19.41% of its notional: so as not to lose more than 20% of the capital, the notional cannot exceed
1.03 times the capital. With a 30% drop and volatility at 80%, 0.68 times. The worst month in the data at 1×
(−23.24%) gives 0.86 times. With the leverage the margin allows, those scenarios cost between 59 and 181% of the
capital.

```mermaid
flowchart TB
  A[Capital] --> B[Required margin]
  A --> C[Stress loss]
  B --> D[Max leverage 6.2x]
  C --> E[Prudent leverage 1x]
  D --> F[Notional = minimum]
  E --> F
```

The notional traded is the smaller of the two. In premium selling, the stress one almost always rules. Three
precautions about the scenarios: they must include the one-day gap, not only the cumulative drop (on 16 March 2020
the index falls 12.8% in one session); they must raise volatility more at the low strikes (lesson 3.5.4); and the
worst episode in the sample is not the worst possible, only the worst seen.

## What this lesson does not prove

The data are synthetic and the volatility risk premium is planted. The lesson teaches how to measure a premium sale,
not that it works. Before trading one with real money you need real option data with their bid-ask spreads and their
glitches (lesson 3.6.4), realistic execution costs at the opening and closing of each cycle, the opportunity cost of
the margin and a plan for the worst month that does not depend on the next one being better. The methodology of the
Cboe PUT index is a good starting point for comparing your own replication with a public series.

## Exercises

1. **Further from the money, with more notional.** Sell only the −0.16 delta put with 2 and 3 times the capital in
   notional and compare its CAGR, its maximum drawdown and its worst month with those of the ATM put-write at 1×.
   Which is riskier: a leveraged far put or an unleveraged near one?

**Solution.**

The far put collects less premium, so more notional is needed to approach the put-write's return; with more
notional, its worst month grows proportionally. With 2 times the capital it returns 6.6% a year (less than the
put-write at 1×, 6.8%) with a maximum drawdown of −54.8% and a worst month of −45.6%; with 3 times, 6.2%, −82.2% and
−69.9%. The leveraged far put is riskier and, in this sample, returns less: “far from the money” does not mean “low
risk” when it is offset with notional.

```python
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)
```
```output
              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
```

2. **A put with a wing.** Compute the loss in the three stress scenarios of a short put spread (2850 put sold and 2550
   put bought, 10% below, same expiration) and the notional the 20% limit allows.

**Solution.**

The bought wing costs 1.6 points: the net credit falls from 32.5 to 30.9 (1.08% of notional) and the maximum loss is
300 − 30.9 = 269.1 points, 9.44% of notional. In the scenarios, the spread loses 6.37, 7.99 and 8.70% of notional,
versus 9.46, 19.41 and 29.21% for the put alone: the 20% limit allows between 2.3 and 3.1 times the capital. The wing
costs 5% of the premium (1.6 of 32.5 points) and completely changes the tail.

```python
st = g0[(g0["vencimiento"] == v0) & (g0["tipo"] == "P")]
ala = st.set_index("strike").loc[2550.0]
credito = atm["prima"] - ala["ask"]
print(f"Net credit: {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)
```
```output
Net credit: 30.9 (1.08%)
                   pérdida_%  apal_20%
10% drop, vol 35%       6.37      3.14
20% drop, vol 60%       7.99      2.50
30% drop, vol 80%       8.70      2.30
```

3. **Margin or stress.** A colleague proposes trading the put-write with the leverage the margin allows “because the
   Sharpe is the same”. What do you answer with the numbers from the lesson?

**Solution.**

That the Sharpe barely measures the tail. With 6.2 times the capital, the worst month in the data (−23.2% at 1×) is a
loss of 144% of the capital, and already at 4 times the account in the data goes negative on 16 March 2020. Besides,
the Sharpe does change with leverage when there is ruin or near-total drawdowns: in the table it falls from 0.52 (1×)
to 0.34 (3×). Leverage is decided with stress scenarios and with the worst known episode, and the result (around 1x
the capital so as not to lose more than 20% in a 20% drop) is far below what the margin allows.

## Self-assessment

1. The put-write in the data has a Sharpe of 0.52 and a monthly skewness of −3.7. What best describes its profile?

   - A. Many small positive months (78%) and a few very bad months (−23.2% in March 2020), with a maximum drawdown of −39.5%, like that of the index
   - B. A stable income with low risk
   - C. A strategy uncorrelated with the index
   - D. A strategy with a higher return than the index

   *Answer A: Many small positive months (78%) and a few very bad months (−23.2% in March 2020), with a maximum drawdown of −39.5%, like that of the index.* Negative skewness says the distribution has its tail on the left. The put-write collects a small premium every month and gives back several years of premiums in a crisis. Its maximum drawdown is that of the index, with half the CAGR.

2. The ±0.16 delta short strangle loses in the sample (Sharpe −0.16) although the −0.16 delta put alone wins (0.47). Why?

   - A. Because the put and the call cancel out
   - B. Because strangles always lose
   - C. Because the implied volatility of calls is higher
   - D. Because the call leg loses 2.6% a year: the 2020 rebound and the 2021 rally (−0.43 in log over two years) wipe out what it earns in the other years

   *Answer D: Because the call leg loses 2.6% a year: the 2020 rebound and the 2021 rally (−0.43 in log over two years) wipe out what it earns in the other years.* A short call loses on strong rallies. In a sample with a very bullish market and a violent rebound, the premium of the calls (small: the skew makes them cheap) does not compensate. It is a result of the sample, not a law, but it is a reminder that each leg is a different bet.

3. With the Cboe margin rule, a short ATM put on ORX requires about 46,000 USD per contract of 285,000 notional. What leverage does it allow and what would have happened with it in the sample?

   - A. 1×; nothing
   - B. 15 times; a 15% drop
   - C. About 6 times the capital; with 4 times the account already goes negative on 2020-03-16
   - D. The margin prevents losing more than the capital

   *Answer C: About 6 times the capital; with 4 times the account already goes negative on 2020-03-16.* The margin covers the risk of a few days with 15% of the index, not a crisis. With 285,000 / 45,976 ≈ 6.2 times the capital, the worst month in the data (−23.2% at 1×) becomes a loss of more than 140% of the capital. In the leverage cell, already at 4× the account does not survive March 2020.

4. What notional keeps the loss below 20% of the capital in a scenario of a 20% drop with volatility at 60%?

   - A. 6.2 times the capital
   - B. About 1x the capital: in that scenario the ATM put loses 19.4% of its notional
   - C. 0.2 times the capital
   - D. It cannot be computed without the Sharpe

   *Answer B: About 1x the capital: in that scenario the ATM put loses 19.4% of its notional.* 20 / 19.41 = 1.03. Stress-based sizing comes from repricing the position in the scenario (lesson 3.5.4) and dividing the tolerable loss by the loss per unit of notional. It is six times less than the margin allows.

5. Why does the lesson present each strategy with its worst month and its maximum drawdown and not only with the Sharpe?

   - A. Because the Sharpe cannot be computed with options
   - B. Because the Sharpe assumes the standard deviation summarizes the risk; with a skewness of −3.7, the normal months set the standard deviation and the tail barely weighs on it
   - C. Out of habit
   - D. Because the worst month is always equal to the maximum drawdown

   *Answer B: Because the Sharpe assumes the standard deviation summarizes the risk; with a skewness of −3.7, the normal months set the standard deviation and the tail barely weighs on it.* With very skewed distributions, two strategies with the same Sharpe can have very different tails. A premium sale without its worst episode in view looks like safe income, and it is not.

## Key points

- Selling options collects the volatility risk premium (in the data, VORX exceeds realized volatility by 5.4 points on average), in exchange for large losses in crises: it is insurance sold, not income.
- The put-write in the data has a Sharpe of 0.52 with a maximum drawdown of −39.5%, that of the index, and a monthly skewness of −3.7. A premium-selling strategy is always presented with its worst episode.
- The 0.16 delta strangle loses in this sample because the call leg loses in the bull market: each leg is a different bet and is measured separately.
- The Cboe margin for a naked index put allows about 6 times the capital; at 4 times, the account in the data goes negative in March 2020. The margin measures the risk of a few days, not that of a crisis.
- Size is set with stress scenarios and with the worst known episode: in the data, a notional of about 1x the capital so as not to lose more than 20% in a 20% drop.

## Resources

### Research

- [Volatility Targeting in Python](https://pythonparatrading.com/en/volatility-targeting-2/) · Research-0004 · 7 min

### Documentation

- [Cboe: S&P 500 PutWrite index methodology (PUT, PUTCAD and PWT)](https://cdn.cboe.com/api/global/us_indices/governance/Cboe_SP_500_PutWrite_Indices_Methodology.pdf) · cdn.cboe.com
- [Cboe: SPX option specifications (includes the margin for naked short options)](https://www.cboe.com/tradable_products/sp_500/spx_options/specifications/) · cboe.com

### Books

- [Sheldon Natenberg, Option Volatility and Pricing, 2nd ed. (McGraw-Hill, 2015)](https://www.mheducation.com/highered/mhp/product/option-volatility-pricing-advanced-trading-strategies-techniques-2nd-edition.html) · mheducation.com

### Data

- [Level 3 data: ORX daily option chain (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/opciones3_cadena.parquet) · Download · opciones3_cadena.parquet
- [Level 3 data: ORX index with rates and dividends (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/opciones3_indice.csv) · Download · opciones3_indice.csv

Previous lesson: [3.5.5 · Management: adjustments, rolls, early closes, early assignment and pin risk](https://pythonparatrading.com/en/python-trading-course/level-3/managing-option-positions/)

Next lesson: [3.6.2 · Delta hedging, gamma scalping and dispersion](https://pythonparatrading.com/en/python-trading-course/level-3/delta-hedging-gamma-scalping-dispersion/)
