Short Strangle Strategy with Adjustments
Sell a 0.16 Δ put and call at IV Rank 30+. Take half, stop at 2× the credit, out at 21 days. When a side is tested, roll the other toward it; after max_rolls, go to a straddle.
Default settings, 2020 to Nov 4, 2026.
By stock and year
Select a row to chart it below. Shade is the gap to buying and holding that stock.Unhedged: nothing protects against a crash beyond what the strategy itself holds.
| Stock | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 YTD | CAGR | B&H CAGR | Max drawdown |
|---|---|---|---|---|---|---|---|---|---|---|
| −4.2%−19.4 | +3.7%−23.2 | +3.1%+22.6 | +6.6%−17.7 | +3.7%−19.6 | +1.1%−15.2 | +2.7%−9.7 | +2.4% | +13.4% | −6.5% | |
| +0.5%−44.6 | +6.5%−20.3 | +2.6%+35.7 | +9.0%−44.8 | +4.7%−20.2 | +3.3%−16.8 | +3.4%−9.2 | +4.4% | +18.5% | −7.1% | |
| −4.6%−23.0 | +18.3%+5.0 | +13.1%+34.7 | +11.3%−3.8 | +11.6%+1.5 | +2.2%−9.2 | +5.7%−9.7 | +8.2% | +8.2% | −19.4% | |
| +1.1%−116.6 | +4.1%−121.1 | +4.1%+54.5 | +10.8%−228.2 | +3.3%−167.9 | +8.5%−30.4 | +5.4%+5.4 | +5.4% | +65.2% | −3.0% | |
| +2.2%−74.5 | +4.7%−29.1 | +6.9%+33.7 | +10.9%−37.3 | +6.0%−24.1 | +2.8%−5.8 | +0.4%−28.1 | +4.9% | +25.2% | −5.2% | |
| +2.4%−12.8 | +3.0%−24.0 | +4.4%+23.9 | +5.8%−18.5 | +4.1%−19.2 | +2.5%−13.8 | +1.2%−11.2 | +3.4% | +13.4% | −3.5% | |
| +2.3%−42.8 | +5.5%−21.3 | +8.5%+41.6 | +8.6%−45.2 | +6.1%−18.7 | +6.0%−14.2 | +1.8%−10.8 | +5.6% | +18.5% | −4.6% | |
| +6.8%−11.6 | +13.3%+0.0 | +10.9%+32.5 | +9.3%−5.8 | +9.1%−1.0 | +1.9%−9.6 | +4.8%−10.6 | +8.1% | +8.2% | −7.1% | |
| +0.6%−117.1 | +2.1%−123.1 | +3.3%+53.7 | +8.3%−230.7 | +13.1%−158.1 | +8.3%−30.6 | +5.8%+5.7 | +6.0% | +65.2% | −2.5% | |
| +1.3%−75.4 | +3.2%−30.6 | +4.8%+31.7 | +9.0%−39.2 | +5.5%−24.6 | −1.3%−9.9 | −1.3%−29.8 | +3.0% | +25.2% | −4.5% |
Growth of $10,000
Weekly closes on a log scale; the red shade is the strategy's drawdown from its last high. Returns are on the capital the strategy needed at its peak, with interest on idle cash. Hypothetical: how the backtests are made.
Rules · the when / do flow, read-only until you make a copyShow flow
The strategy runs as 2 tracks side by side. Each day, the first rule whose conditions hold in each track acts.
1. Strangle
The put and the call, adjusted as one position
- INSell the strangle
When:
book.open == 0andiv_rank >= ivr_minDo: sell put (as put)delta put_delta (0.16)dte dte (45)dte_min dte_min (30)dte_max dte_max (60)avoid_earnings 1strict 1; sell call (as call)delta call_delta (0.16)expiry leg.put.expirystrike_min spotstrict 1 - TPHalf the credit kept: close both
When:
book.pnl_pct >= take_pctDo: close put; close call - SLLost stop_pct of the credit: close both
When:
book.pnl_pct <= -stop_pctDo: close put; close call - SRA straddle by now: roll both out for a credit
When:
leg.call.strike <= leg.put.strikeandmin(leg.put.dte, leg.call.dte) <= straddle_roll_dteDo: roll putstrike leg.put.strikedte dte (45)dte_min dte_min (30)dte_max dte_max (60)avoid_earnings 1require new.mark + mid_call(leg.call.strike, new.expiry) > leg.put.mark + leg.call.mark; roll callstrike leg.call.strikeexpiry leg.put.expiry - EXexit_dte left: close both
When:
min(leg.put.dte, leg.call.dte) <= exit_dteDo: close put; close call - APPut tested: roll the call down to roll_untested_to Δ (never below the put)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls > 0andleg.call.delta < roll_untested_to / 2Do: roll calldelta roll_untested_to (0.3)expiry leg.call.expirystrike_min leg.put.strike - ACCall tested: roll the put up to roll_untested_to Δ (never above the call)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls > 0andleg.put.delta < roll_untested_to / 2Do: roll putdelta roll_untested_to (0.3)expiry leg.put.expirystrike_max leg.call.strike - STRolls used up, put tested: move the call to the put strike (a straddle)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls <= 0andnot (leg.call.strike <= leg.put.strike)Do: roll callstrike leg.put.strikeexpiry leg.call.expirystrict 1 - STRolls used up, call tested: move the put to the call strike (a straddle)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls <= 0andnot (leg.call.strike <= leg.put.strike)Do: roll putstrike leg.call.strikeexpiry leg.put.expirystrict 1 - Closed or expired
When:
book.open == 0Do: nothing (hold) - TPHalf the credit kept: close both
When:
book.pnl_pct >= take_pctDo: close put; close call - SLLost stop_pct of the credit: close both
When:
book.pnl_pct <= -stop_pctDo: close put; close call - SRA straddle by now: roll both out for a credit
When:
leg.call.strike <= leg.put.strikeandmin(leg.put.dte, leg.call.dte) <= straddle_roll_dteDo: roll putstrike leg.put.strikedte dte (45)dte_min dte_min (30)dte_max dte_max (60)avoid_earnings 1require new.mark + mid_call(leg.call.strike, new.expiry) > leg.put.mark + leg.call.mark; roll callstrike leg.call.strikeexpiry leg.put.expiry - EXexit_dte left: close both
When:
min(leg.put.dte, leg.call.dte) <= exit_dteDo: close put; close call - APPut tested: roll the call down to roll_untested_to Δ (never below the put)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls > 1andleg.call.delta < roll_untested_to / 2Do: roll calldelta roll_untested_to (0.3)expiry leg.call.expirystrike_min leg.put.strike - ACCall tested: roll the put up to roll_untested_to Δ (never above the call)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls > 1andleg.put.delta < roll_untested_to / 2Do: roll putdelta roll_untested_to (0.3)expiry leg.put.expirystrike_max leg.call.strike - STRolls used up, put tested: move the call to the put strike (a straddle)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls <= 1andnot (leg.call.strike <= leg.put.strike)Do: roll callstrike leg.put.strikeexpiry leg.call.expirystrict 1 - STRolls used up, call tested: move the put to the call strike (a straddle)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls <= 1andnot (leg.call.strike <= leg.put.strike)Do: roll putstrike leg.call.strikeexpiry leg.put.expirystrict 1 - Closed or expired
When:
book.open == 0Do: nothing (hold) - TPHalf the credit kept: close both
When:
book.pnl_pct >= take_pctDo: close put; close call - SLLost stop_pct of the credit: close both
When:
book.pnl_pct <= -stop_pctDo: close put; close call - SRA straddle by now: roll both out for a credit
When:
leg.call.strike <= leg.put.strikeandmin(leg.put.dte, leg.call.dte) <= straddle_roll_dteDo: roll putstrike leg.put.strikedte dte (45)dte_min dte_min (30)dte_max dte_max (60)avoid_earnings 1require new.mark + mid_call(leg.call.strike, new.expiry) > leg.put.mark + leg.call.mark; roll callstrike leg.call.strikeexpiry leg.put.expiry - EXexit_dte left: close both
When:
min(leg.put.dte, leg.call.dte) <= exit_dteDo: close put; close call - APPut tested: roll the call down to roll_untested_to Δ (never below the put)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls > 2andleg.call.delta < roll_untested_to / 2Do: roll calldelta roll_untested_to (0.3)expiry leg.call.expirystrike_min leg.put.strike - ACCall tested: roll the put up to roll_untested_to Δ (never above the call)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls > 2andleg.put.delta < roll_untested_to / 2Do: roll putdelta roll_untested_to (0.3)expiry leg.put.expirystrike_max leg.call.strike - STRolls used up, put tested: move the call to the put strike (a straddle)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls <= 2andnot (leg.call.strike <= leg.put.strike)Do: roll callstrike leg.put.strikeexpiry leg.call.expirystrict 1 - STRolls used up, call tested: move the put to the call strike (a straddle)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls <= 2andnot (leg.call.strike <= leg.put.strike)Do: roll putstrike leg.call.strikeexpiry leg.put.expirystrict 1 - Closed or expired
When:
book.open == 0Do: nothing (hold) - TPHalf the credit kept: close both
When:
book.pnl_pct >= take_pctDo: close put; close call - SLLost stop_pct of the credit: close both
When:
book.pnl_pct <= -stop_pctDo: close put; close call - SRA straddle by now: roll both out for a credit
When:
leg.call.strike <= leg.put.strikeandmin(leg.put.dte, leg.call.dte) <= straddle_roll_dteDo: roll putstrike leg.put.strikedte dte (45)dte_min dte_min (30)dte_max dte_max (60)avoid_earnings 1require new.mark + mid_call(leg.call.strike, new.expiry) > leg.put.mark + leg.call.mark; roll callstrike leg.call.strikeexpiry leg.put.expiry - EXexit_dte left: close both
When:
min(leg.put.dte, leg.call.dte) <= exit_dteDo: close put; close call - STRolls used up, put tested: move the call to the put strike (a straddle)
When:
spot <= leg.put.strike * (1 + test_pct)andmax_rolls <= 3andnot (leg.call.strike <= leg.put.strike)Do: roll callstrike leg.put.strikeexpiry leg.call.expirystrict 1 - STRolls used up, call tested: move the put to the call strike (a straddle)
When:
spot >= leg.call.strike * (1 - test_pct)andmax_rolls <= 3andnot (leg.call.strike <= leg.put.strike)Do: roll putstrike leg.call.strikeexpiry leg.put.expirystrict 1 - Closed or expired
When:
book.open == 0Do: nothing (hold)
2. Crash put
A cheap far put under whatever is held; hedge_delta 0 turns it off
- CP1Something is held and no crash put: buy one
When:
hedge_delta > 0andleg.hedge.open == 0andshares >= 100 or book.open > 0Do: buy put (as hedge)qty max(1, round(shares / 100))delta hedge_delta (0)dte hedge_dte (90)dte_min hedge_replace_dte + 7strike_max spot - 0.001strict 1 - CP2Nothing left to protect: sell it
When:
leg.hedge.open == 1andshares < 100andbook.open <= 1Do: close hedge - CP3Down to its last month, or worth hedge_take_x its cost: sell it and buy a fresh one
When:
leg.hedge.open == 1andleg.hedge.dte <= hedge_replace_dte or (hedge_take_x > 0 and leg.hedge.mark >= leg.hedge.cost * hedge_take_x)Do: close hedge; buy put (as hedge)qty max(1, round(shares / 100))delta hedge_delta (0)dte hedge_dte (90)dte_min hedge_replace_dte + 7strike_max spot - 0.001strict 1
Parameters and defaults
Every named number in the rules can be changed in the Rule Builder. These are the defaults the backtest used.
| Parameter | Default |
|---|---|
put_delta | 0.16 |
call_delta | 0.16 |
dte | 45 |
dte_min | 30 |
dte_max | 60 |
ivr_min | 30 |
take_pct | 50 |
stop_pct | 200 |
exit_dte | 21 |
test_pct | 0.01 |
roll_untested_to | 0.3 |
max_rolls | 2 |
straddle_roll_dte | 21 |
hedge_delta | 0 |
hedge_dte | 90 |
hedge_replace_dte | 30 |
hedge_take_x | 3 |
Make a copy to change any of it and run your own backtest.
Trade log · every open, roll, assignment and close for SPYShow trades
Loading…
Sell a 0.16 Δ put and call at IV Rank 30+. Take half, stop at 2× the credit, out at 21 days. When a side is tested, roll the other toward it; after max_rolls, go to a straddle.
What it is
Sell a 0.16 delta put and a 0.16 delta call about 45 days out when IV Rank is 30 or more. Take half the credit, stop at twice the credit, and close at 21 days left. When one side is tested, roll the other side toward it; after the allowed number of rolls, move it to a straddle.
When to use it
Use it on liquid underlyings in a range-bound market with elevated implied volatility, when you expect the price to stay between the strikes.
Maximum risk
The call side has unlimited risk and the put side nearly full share downside. The stop at 200% of the credit limits losses in normal conditions but not across overnight gaps.
Questions
Why 0.16 delta?
Around one standard deviation out: roughly a 68% chance of both legs expiring worthless at the start, with a meaningful credit.
Why close at 21 days?
Gamma risk grows fast in the last weeks. Closing at 21 days gives up the last bit of premium to avoid the sharpest moves.
What does rolling the untested side mean?
If the put is tested, the call is moved down toward the price for more credit, which widens the break-even on the put side.