Covered Call

Income

Own the underlying and sell an OTM call to collect premium, capping upside.

Performance across all datasets

SymbolReturn %SharpeMax DD %Win %Avg/trade %Trades
SPY+36.2%0.46+13.4%+84.2%+1.9%19
QQQ+42.8%0.48+16.4%+79.0%+2.3%19
IWM+13.9%0.14+23.4%+63.2%+0.7%19
DIA+21.0%0.30+14.6%+73.7%+1.1%19
Avg+28.5%0.35+17.0%+75.0%19
Cumulative P&L % — all symbols

What this shows: Overlayed cumulative return series for this strategy across all available symbols.

How to read it: Look for symbols with smoother curves and faster recoveries to assess whether performance is broad-based or driven by a few outliers.

Detail:
Cumulative P&L % — SPY

What this shows: Single-symbol cumulative return path for SPY.

How to read it: Use this detailed view to inspect entry/exit behavior over time and whether drawdowns cluster in specific periods.

Risk Profile

Max Profit
Strike − Entry + Premium
Max Loss
Entry Price − Premium (underlying → 0)
Breakeven
Entry − Premium
Outlook
Neutral to mildly bullish

Parameters

ParameterDefaultDescription
strike_pct1.02Strike as fraction of spot (2% OTM)
dte45Days to expiration at entry
cycle_days21Trading days between new positions

Methodology

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.

Implementation

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