Perpetual Option Roll on Weekly Put Credit Spreads

Algorithm logic by Alex Joseph

Perpetual Weekly Put Credit Spread (PCS) – Rolling Algorithm

A production‑ready spec for an algorithm that continuously sells and manages weekly put credit spreads, with rule‑based entries, exits, rolls, and risk controls.


1) Strategy Intent & Universe

  • Intent: harvest short‑dated put premium while keeping tail risk bounded via defined‑risk spreads and an always‑on roll engine.

  • Underlying universe (examples): SPY, QQQ, IWM, mega‑cap index ETFs, and the top‑N most liquid equity underlyings (weekly options, tight spreads, robust borrow/SSFs if hedging with futures is preferred). Allow a whitelist per account.


2) Core Parameters (tunable)

  • Entry DTE: 5–9 DTE (default 7).

  • Entry window: open Mon–Thu for next Fri expiration; avoid opening during last 90 minutes of RTH.

  • Short‑put target delta: regime‑adaptive 0.10–0.30.

  • Width: fixed ($1–$10) or ATR‑scaled (e.g., width = max($3, 0.6 * ATR20)), capped by risk.

  • Min credit: min_credit = max(0.30 * width, $0.20); stricter in low IV.

  • Max risk per spread: width – credit.

  • Portfolio heat (max net risk at once): <= 20% of account (configurable).

  • Max correlated underlyings: e.g., at most 2 concurrent index ETFs.

  • Event risk filters: block entries 24h before CPI, FOMC, jobs report; block single‑name entries inside earnings window [t−2, t+1] trading days.

  • Volatility filters:

    • IV Rank (IVR): prefer IVR >= 25; if IVR < 15 require min credit >= 40% * width or skip.

    • VIX filter (for index): if VIX > 28, reduce size 50% and shift to 0.10–0.15 delta.

  • Trend/Regime:

    • Bullish/Neutral = MA20 > MA50 and/or RSI14 > 45 → target short delta 0.20–0.25.

    • Bearish/High vol = otherwise → target short delta 0.10–0.15 and smaller size.


3) Entry Logic (PCS opening)

Pre‑checks (all must pass):

  1. Liquidity: bid/ask width <= 5% of mid, open interest on both legs >= 500 (or 10× your size), spread slippage model ok.

  2. Risk budget available (portfolio heat OK, correlation budget OK).

  3. No blocked events in window; no hard news flagged.

Strike selection:

  • Choose expiration E with 5–9 DTE.

  • Compute target short delta from regime (Section 2).

  • Pick short strike Kshort closest to target delta; long strike Klong = Kshort − width.

  • Enforce distance: Kshort <= Spot − 0.8 * ATR20 (farther OTM in high vol).

  • Enforce credit: natural credit >= min_credit after slippage.

Position sizing:

  • Contracts n = floor( min( risk_budget_remaining, heat_cap_remaining ) / (width − credit) ), bounded by per‑underlying max.

  • If n == 0, skip.

Send limit order at mid − slippage (0.5–1.0 ticks). Use smart retry (time‑slice, join the bid when necessary, hard cancel before news).


4) Lifecycle Management

Profit taking

  • TP1: Close at 50–60% of max profit (e.g., when spread price decays to 40–50% of entry credit) OR when DTE <= 3 and unrealized_pnl >= 40%.

  • TP2 (time‑based): If DTE == 1 and spread is profitable, close at MOC; do not hold through expiry unless (a) wide cushion Spot >= Kshort + 0.8*ATR5, (b) borrow/assignment handling confirmed, and (c) risk engine green.

Risk exits (untested → tested)

Trigger any of the following and escalate to roll/exit decision:

  • Spot breaches short strike (Spot < Kshort) OR short leg delta >= 0.35.

  • Spread mark >= 2.0 * entry_credit OR stop‑loss at 1.5× credit in low vol.

  • IV spike: underlying IV (or VIX) jumps >= +30% versus entry.

  • News shock detected (underlying drops >1.5× ATR in a session).

Emergency stop

  • If gap risk or structural break (halt, downgrade, macro shock) → flatten all PCS in underlying; suspend entries for N sessions.


5) Roll Engine (Perpetual Behavior)

Objective: keep risk defined and theta allocated while limiting variance drag.

Roll windows:

  • Early roll (premium harvest): when DTE <= 3 and position is untested (Spot > Kshort) and price <= 25% of entry credit, close and re‑open new PCS with 5–9 DTE.

  • Defensive roll (tested): when Spot <= Kshort and DTE >= 3:

    1. Out-in-time, same strikes (O→O+7): if credit >= 30% * width when rolling calendar‑style, take it.

    2. Down‑and‑out: move strikes lower and out a week to keep same width, require net additional credit >= 10–20% of width.

    3. If unable to collect credit on roll and short delta > 0.45, close the spread (cap losses) and re‑enter smaller/wider per regime after cool‑down.

  • Pin risk roll (DTE 0–1): if Spot is within ±0.25 * width of Kshort, close intraday (avoid assignment) or roll out a week for small credit only if liquidity conditions are excellent.

Do not roll if doing so increases max loss or provides < $0.05 credit and keeps you tested; prefer close and reset.


6) Optional Hedges

  • Tail put: buy a 1–2 week 5–10Δ long put for the aggregate book when VIX term structure inverts.

  • Futures micro‑hedge: if allowed, short /MES or /MNQ proportional to aggregate delta when portfolio PCS delta exceeds a threshold (e.g., −0.15 beta‑adj).

  • Gamma day hedge: on large down open (>1.25× ATR), temporarily pause new entries and consider buying 0DTE units as intraday hedge against early breach.


7) Decision Matrix (Entry/Exit/Roll)

7.1 Quick Matrix (tabular)

State
DTE
Spot vs Kshort
IV change
Spread P&L
Action

Fresh entry signal

5–9

Spot >= Kshort + 0.8*ATR20

IVR ≥ 25 (or min credit met)

n/a

Open PCS sized by risk

Untested, decayed

≤3

Above Kshort

Flat/down

≥50–75% max profit

Close & Re‑open next‑week PCS

Untested, slow decay

2–4

Above Kshort

Flat

<25% of credit

Early Roll Out if next week credit ≥ 30% width, else hold

Tested light

≥3

Spot ~ Kshort

Flat/Down

Loss ≤ 1× credit

Roll Out same strikes for credit; or Down‑and‑Out for ≥10–20% width credit

Tested heavy

≥3

Below Kshort

Up big

Loss > 1.5–2× credit or Δshort ≥ 0.45

Close; optional re‑entry smaller/wider after cooldown

Pin risk

0–1

`

Spot−Kshort

<= 0.25*width`

Any

Event window

Any

Any

Any

Any

No New Entries; manage/flatten risk

7.2 Flowchart (Mermaid)

flowchart TD
    A[Daily Scheduler] --> B{Open Positions?}
    B -- No --> C{Entry Filters Pass?\n(IVR, Trend, Events, Liquidity)}
    C -- Yes --> D[Select 5–9 DTE; choose Δ; set width/credit; size]
    D --> E[Send Limit Order]
    C -- No --> Z[Skip Entries]

    B -- Yes --> F{Position State}
    F -->|Untested & DTE<=3 & PnL>=50–60%| G[Close & Reopen Next Week]
    F -->|Untested & DTE<=4 & Decay<25%| H{Next‑week credit ≥30% width?}
    H -- Yes --> I[Early Roll Out]
    H -- No --> J[Hold]
    F -->|Tested & DTE>=3 & Δshort<0.45| K{Roll for Net Credit?}
    K -- Yes --> L[Roll Out Same/Lower Strikes]
    K -- No --> M[Close Spread]
    F -->|Tested & Δshort>=0.45 or Price>=1.5–2x credit| M
    F -->|Pin Risk DTE<=1| N[Close or Micro‑roll 1w]
    F -->|Event Risk/News Shock| O[Flatten & Suspend Entries]

    subgraph Risk Controls
    P[Portfolio Heat ≤ 20%]
    Q[Per‑underlying limits]
    R[Correlation budget]
    end
    E --> P
    P --> Q --> R --> S[OK]
    S --> T[Live]

8) Order Handling & Microstructure

  • Use limit orders at mid; cross one tick after N seconds; cancel/replace at thresholds.

  • Partial fills allowed up to 25% variation; otherwise cancel and resize.

  • Slippage model: slip = max(1 tick, 0.15 * quoted spread); embed in all checks.


9) Risk & Compliance Guardrails

  • Hard daily loss stop for the strategy: e.g., −2% of account or −0.75× monthly vol estimate.

  • Max days held: forced exit on DTE 0 unless wide cushion and assignment permitted by broker rules you’ve coded for.

  • Circuit breaker: pause new entries for the session after any emergency stop.


10) Pseudocode (Framework‑Agnostic)

for each trading_day:
    update_data()
    for u in universe:
        regime = get_regime(u)  # trend, IVR, VIX term, events
        risk_ok = check_portfolio_heat() and correlation_ok(u)
        if not has_open_pcs(u) and entry_window() and regime.entry_ok and risk_ok:
            dte = pick_dte(5, 9)
            delta = target_delta(regime)  # 0.10–0.30
            k_short = strike_by_delta(u, dte, delta)
            width  = choose_width(u, regime)  # fixed or ATR‑scaled
            k_long = k_short - width
            credit = quote_credit(u, dte, k_short, k_long)
            if credit >= min_credit(width, regime) and distance_ok(u, k_short):
                size = position_size(credit, width, risk_state)
                if size > 0:
                    send_limit_order(u, dte, k_short, k_long, size)

    # Manage open spreads
    for pos in open_spreads():
        u, dte, k_short, k_long = pos.underlying, pos.dte, pos.k_short, pos.k_long
        mark = pos.mark_price()
        pnl  = pos.unrealized_pnl()
        delta_short = leg_delta(u, dte, k_short)
        tested = spot(u) <= k_short

        if pnl >= 0.5 * pos.max_profit or (dte <= 3 and pnl >= 0.4 * pos.max_profit):
            close(pos); continue

        if dte <= 1 and near_pin(spot(u), k_short, width):
            close(pos); continue

        if tested and dte >= 3:
            # attempt to roll for net credit
            roll = find_roll_candidate(pos, out_weeks=1, allow_down=True)
            if roll.net_credit >= 0.1 * width:
                execute_roll(pos, roll); continue
            if delta_short >= 0.45 or mark >= 1.5 * pos.entry_credit:
                close(pos); continue

        if news_shock(u) or emergency_flag():
            close(pos); suspend_entries(u)

11) Backtest/Live Monitoring KPIs

  • Win rate; avg win/avg loss; P/L per trade; P/L per calendar week.

  • Return on risk (ROR): per spread and aggregate.

  • Tail drawdowns (5% worst days), max DD, recovery time.

  • Exposure (contracts & risk dollars) vs VIX/IVR.

  • Percent of rolls vs closes, net credit from rolls, and post‑roll outcomes.

  • Assignment rate and cost.


12) Suggested Default Settings (SPY example)

  • Entry: Tue/Thu, 7–8 DTE.

  • Target Δ: 0.20 in normal regime; 0.12 if VIX>25.

  • Width: $5; Min credit: $1.50 (30% of width).

  • TP: 55% of max profit or DTE ≤ 3 with ≥ 40%.

  • Risk exits: price ≥ 1.8× credit, or Δshort ≥ 0.40.

  • Rolls: Out 1 week, keep width, seek ≥ $0.50 net credit when tested; otherwise close.


13) Implementation Notes

  • Schedule two loops: pre‑open (risk/events) and intraday (entries/management).

  • Log all decisions with state snapshots for auditability.

  • Parameterize everything; run walk‑forward optimizations on yearly slices.


Appendix A – Test Cases (What‑ifs)

  1. Low IV drift week: few openings due to credit filter; early rolls harvest decay → small, steady gains.

  2. Vol spike mid‑week: tested spreads trigger defensive roll; heat reduced; daily loss stop prevents cascade.

  3. Pin close Friday: algorithm closes at 3pm ET; avoids assignment.

  4. Event lockout (CPI): skips Tuesday entries; resumes after print.

Last updated

Was this helpful?