Own the underlying and sell an OTM call to collect premium, capping upside.
| Parameter | Default | Description |
|---|---|---|
| strike_pct | 1.02 | Strike as fraction of spot (2% OTM) |
| dte | 45 | Days to expiration at entry |
| cycle_days | 21 | Trading days between new positions |
A covered call owns the underlying asset and sells an out-of-the-money call against it. The premium collected reduces the cost basis and provides income. Upside is capped at the strike price. The strategy profits in flat-to-moderately-bullish markets and underperforms in strong rallies. Backtested with 45 DTE cycles at a strike of 102% of spot, rolling every 21 trading days. P&L combines stock movement (capped at strike) plus premium minus call payoff.
def run_covered_call(S, K, T, r, sigma):
"""
Covered Call: own stock, sell OTM call.
K: strike (102% of S)
"""
premium = black_scholes_call(S, K, T, r, sigma)
# At expiration:
# stock_pnl = min(S_exp, K) - S_entry
# call_payoff = max(0, S_exp - K)
# P&L = stock_pnl + premium - call_payoff
return premium
# Backtest loop
for entry in monthly_entries:
S = spot_at_entry
K = round(S * 1.02 / 5) * 5 # 2% OTM call
T = 45 / 365.25
premium = black_scholes_call(S, K, T, RISK_FREE_RATE, avg_iv)
S_exp = spot_at_expiry
stock_pnl = min(S_exp, K) - S
pnl = stock_pnl + premium - max(0, S_exp - K)
pnl_pct = pnl / S * 100| Symbol | Return % | Sharpe | Max DD % | Win % | Avg/trade % | Trades |
|---|---|---|---|---|---|---|
| SPY | -20.1% | -0.27 | +31.5% | +47.4% | -1.1% | 19 |
| QQQ | -40.4% | -0.42 | +48.5% | +36.8% | -2.1% | 19 |
| IWM | -78.1% | -0.97 | +79.0% | +15.8% | -4.1% | 19 |
| DIA | -7.9% | -0.15 | +16.9% | +68.4% | -0.4% | 19 |
| Avg | -36.6% | -0.45 | +44.0% | +42.1% | — | 19 |