Sell an OTM put and collect premium. Obligated to buy the underlying at the strike if assigned.
| Parameter | Default | Description |
|---|---|---|
| strike_pct | 0.95 | Strike as fraction of spot (5% OTM) |
| dte | 45 | Days to expiration at entry |
| cycle_days | 21 | Trading days between new positions |
A cash-secured put sells an out-of-the-money put option and holds cash equal to the strike price as collateral. The maximum profit is the premium collected; the maximum loss is the strike minus premium (if the underlying goes to zero). The strategy profits when the underlying stays above the strike at expiration. It is equivalent to a covered call in terms of risk/reward and is commonly used to acquire stock at a discount or generate income in neutral-to-bullish markets. Backtested using 45 DTE cycles, rolling every 21 trading days, with strikes at 95% of spot.
def run_cash_secured_put(S, K, T, r, sigma):
"""
Cash-Secured Put: sell OTM put, collect premium.
S: spot price, K: strike (95% of S), T: time to expiry (years)
r: risk-free rate, sigma: implied volatility
"""
premium = black_scholes_put(S, K, T, r, sigma)
# At expiration:
# P&L = premium - max(0, K - S_exp)
# Max profit = premium (if S_exp >= K)
# Max loss = K - premium (if S_exp = 0)
return premium
# Backtest loop (45 DTE, monthly cycles)
for entry in monthly_entries:
S = spot_at_entry
K = round(S * 0.95 / 5) * 5 # 5% OTM put
T = 45 / 365.25
premium = black_scholes_put(S, K, T, RISK_FREE_RATE, avg_iv)
S_exp = spot_at_expiry
pnl = premium - max(0, K - S_exp)
pnl_pct = pnl / K * 100 # as % of collateral| Symbol | Return % | Sharpe | Max DD % | Win % | Avg/trade % | Trades |
|---|---|---|---|---|---|---|
| SPY | -6.7% | -0.20 | +7.9% | +94.7% | -0.3% | 19 |
| QQQ | -10.3% | -0.22 | +11.1% | +94.7% | -0.5% | 19 |
| IWM | -15.1% | -0.29 | +16.1% | +79.0% | -0.8% | 19 |
| DIA | -2.9% | -0.11 | +5.9% | +94.7% | -0.1% | 19 |
| Avg | -8.8% | -0.20 | +10.2% | +90.8% | — | 19 |