← Lab
S013

Put-selling on capitulation — combined filter + risk-weighted sizing + max-loss stop

put-selling-capitulation-combined-v1
failed Stage 1 (Quick-screen) — 6 of 8 gates passed; 2 specific failures 2026-05-31
Share: Twitter / X LinkedIn
-1.2%+0.0%+1.2%+2.3%+3.5% 110 Monthly portfolio return distribution — S011 risk-weighted Monthly return
Break-even Monthly mean +0.47%
Monthly portfolio return distribution — S011 risk-weighted · n=95

ID: S013 Slug: put-selling-capitulation-combined-v1 Failed at: Stage 1 (Quick-screen) — 6 of 8 gates passed; 2 specific failures Fail reason: magnitude Date: 2026-05-31 Lineage: Combined version of S011 (risk-weighted sizing) + S012 (tightened volregime filter, 0.85× median) + new -200%-of-credit max-loss stop. Tested whether the orthogonal mechanisms compound positively AND whether the previously-omitted stop materially improves risk-adjusted return.

What we tested

Same S008 Variant B signal everyone in this lineage uses (multi-day capitulation in an uptrend, RV-rank ≥ 0.30). Same naked short put at the 93% strike, 45 DTE, same friction. What's different from prior H-NNNs:

Starting capital: $100,000 (same as S011 for direct comparability). Pre-registered 8 gates frozen before run; same portfolio-level gates as S011 plus one new structural-validation gate (max single-trade loss ≤ 0.10% of starting capital).

What we found

6 of 8 gates passed.

Criterion We needed We got
Portfolio CAGR ≥ +5% +4.57%
Max drawdown ≤ 25% 3.4%
Sharpe (monthly, annualised) ≥ 0.5 1.85
Per-trade win rate ≥ 75% 82.2%
Welch p<0.05 AND mean>0 yes p=0.0000, +0.88%
Both halves positive yes h1 $129K, h2 $156K
Final capital > starting yes $155,728 vs $100K
Max single-trade loss ≤ 0.10% capital yes 0.35% ($353.55)

Head-to-head against the lineage:

S008 (no controls) S011 (sizing only) S012 (filter only) S013 (filter+sizing+stop)
Trades 23,915 23,910 7,581 7,581
Mean EV (%) +0.88% +0.88% +1.19% +0.88%
Win rate 87.1% 87.1% 87.1% 82.2%
Total $ P/L −$1.35M +$185K (sized) +$619K (uniform) +$55K (sized)
Portfolio CAGR n/a +10.72% n/a +4.57%
Sharpe n/a 1.67 n/a 1.85
Max drawdown n/a 19.1% n/a 3.4%
Worst single trade n/a up to 1% capital n/a up to 0.35% capital
Stage 1 outcome CUT PASS PASS CUT

Exit-reason distribution for S013 (informational; not gated):

Reason Share
quick_take 58.4%
profit_take 17.5%
stop_loss 14.6%
force_close_loss 4.8%
force_close_win 4.7%

The stop fired 14.6% of the time — meaningful, not vestigial. Plus, 4.8% of trades reached day-21 force-close as full assignment losses (these are the trades that bled slowly without ever hitting the 2× MTM trigger).

Year-by-year realized P/L for S013:

2016: +$4,333    2020: +$5,274    2024: +$6,794
2017: +$7,676    2021: +$11,726   2025: +$6,649
2018: −$726      2022: +$97       2026: +$1,336 (YTD)
2019: +$5,038    2023: +$7,531

10 of 11 years positive. 2018 marginally negative. 2022 essentially breakeven. Notably smaller in absolute terms across the board than either S011 or S012's per-year numbers, reflecting the combined risk-control effect.

Why this matters / what surprised us

The drawdown collapse is genuine. From S011's 19.1% peak-to- trough to S013's 3.4% is a 5.6× reduction. The combination of sizing + filter + stop produces a portfolio path that almost never goes underwater meaningfully. This is a real finding even though the strategy is formally cut on CAGR.

The Sharpe improvement is also genuine, but small. 1.67 → 1.85 is +0.18 — meaningful but not dramatic. The improvement is mostly from the volatility-of-returns reduction (smaller drawdowns, smoother path) rather than from a fatter per-trade edge. Sharpe captures both numerator (return) and denominator (volatility); S013 has worse numerator but much better denominator.

The CAGR collapse from 10.7% to 4.6% is the cost. When you size for 1% per-trade risk AND filter to only the calmest 30% of days AND close losers at -200% (preventing the full assignment loss), there isn't enough dollar P/L per trade to compound at S011's pace. The strategy still makes money ($156K from $100K), but slower.

The stop is doing real work but only on a subset. 14.6% of trades stop out — that's not vestigial. But for the remaining ~85% the stop never triggers (most trades either get quick-take/profit-take or drift to force-close at modest losses). The stop's effect on drawdown is real but bounded — the bigger contributor to the 3.4% drawdown is the combination with the volregime filter, which prevents the strategy from firing during the worst regimes in the first place.

My pre-registered "max single-trade loss ≤ 0.10%" gate was incompatible with the sizing rule. With 1% sizing, each trade can lose up to 1% of capital via assignment. The stop caps loss at 2× premium (~0.03-0.05% of capital), but only for trades that hit the 2× threshold. Trades that DON'T hit the threshold (many do not — they drift slowly into modest losses) can still realize up to ~1% loss via the sizing bound. My pre-registered gate of 0.10% was therefore mathematically impossible to clear without making the stop strictly tighter or the sizing strictly smaller. This is a pre-registration design error: the gate as written would only pass if the stop bounded EVERY losing trade, which it does not by construction. The right gate would have been "max single-trade loss ≤ 1.10% × sizing-budget" or "stop fires on ≥80% of losing trades" or similar. The gate stands as-written and counts as a fail per pre-registration discipline. But the strategy itself did not fail on actual risk — the worst single trade was $353, well below S011's worst trade (~$1,000).

The big-picture takeaway: S013 is the conservative variant of the S008 lineage. CAGR is too low to clear the +5% bar written into the spec, but the path is the smoothest yet seen. For a real product positioned to risk-averse subscribers, this profile (4.6% CAGR with 3.4% max drawdown and 1.85 Sharpe) might be more attractive than S011's (10.7% CAGR with 19% drawdown). The gate framework doesn't capture that preference axis — and arguably shouldn't, because pre-registration's whole purpose is to commit to criteria before seeing results.

What this doesn't tell us yet

  1. A re-spec with looser CAGR gate could pass. "Sharpe ≥ 0.5 AND max drawdown ≤ 10%" with the CAGR gate dropped (or moved to +3%) would have cleared S013. But that would be a new pre-registration (S014 candidate), not a modification of S013. The current gates were pre-registered to be apples- to-apples with S011; that choice cost S013 its formal pass.

  2. A different stop threshold could pass the CAGR gate. -300% stop (close at 3× premium instead of 2×) means fewer trades stop out and lose smaller amounts overall, which could improve CAGR while still capping the worst trades. Sensitivity sweep is a Stage-2 question for whichever survivor proceeds.

  3. A different filter threshold could pass. The 0.85× median came from S012; a 0.90× median might give more signals and higher dollar P/L while keeping most of the filter benefit.

  4. Combining stop + sizing without filter might thread the needle — preserves S011's higher trade count + adds tail protection. Would be a separate setup (S014 candidate).

What happens next

S013 is formally cut. Two Stage-1 survivors remain on the table: S011 (sizing alone) and S012 (filter alone, uniform sizing).

The S013 result changes the practical priority somewhat. The combination of mechanisms produces a real risk-control improvement (drawdown 3.4%, Sharpe 1.85) at the cost of CAGR. Three reasonable next moves:

(a) Stage 2 S011 — the strongest CAGR result; standard Stage-2 walk-forward + IV-rank reconstruction + parameter sensitivity (which would include stop-loss sensitivity automatically). S013's finding informs Stage 2 design: stop-loss at multiple thresholds will be one of the parameters.

(b) Pre-register S014 with looser/CAGR-relaxed gates for the conservative-variant profile. Tests whether there's a real product position around "lower-return, much-lower-risk" worth pursuing. ~1.5 hour pre-register + run.

(c) Pre-register S014 = sizing + stop (no filter) — tests whether the stop adds incremental value when not combined with the filter. Helps isolate which orthogonal mechanism contributed what.

My read: (a) is the right move. S013's lesson — that stop + filter + sizing collectively over-control risk — is a Stage 2 sensitivity finding, not a separate Stage 1 setup. Stage 2 for S011 should explicitly include the stop-loss sweep as a parameter, which is where this exploration belongs.

For the specialist — methodology details (click to expand)

Setup (verbatim from spec)

Selling 45-DTE OTM puts on S008 Variant B signals, restricted to the S012 calm-regime subset (SPY rv_20d < 0.85 × trailing-252d median), sized per-trade so worst-case assignment loss = 1% of running portfolio capital, AND closed early when MTM exceeds 2.0 × opening premium produces portfolio CAGR ≥ +5% net of friction, max drawdown ≤ 25%, Sharpe ≥ 0.5 of monthly portfolio returns, with all per-trade-quality and concentration gates also clearing.

Test setup

All elements inherited from prior H-NNN spec files: - Signal: S008 Variant B (multi-day capitulation in uptrend) - Filter: S012 (SPY rv_20d < 0.85 × trailing-252d median) - Sizing: S011 (1% capital max-loss per trade, fractional shares) - Trade structure: S008 (naked short put, 93% strike, 45 DTE) - Friction: S008 ($1.30 round-trip + 5% slippage on MTM at close) - NEW: stop-loss at 2.0 × opening premium (priority-0 exit)

Stop-loss implementation

Added stop_loss_pct: float | None = None parameter to src/lab/options_sim.py:simulate_short_put. New priority-0 exit in the MTM loop, evaluated before quick-take and profit-take:

if stop_loss_pct is not None and mtm_put >= stop_loss_pct * opening_premium:
    exit_reason = "stop_loss"
    exit_premium = mtm_put
    exit_idx = t
    break

Default None preserves all existing H-NNN callers' behaviour (S008, S010, S011, S012 all called with no stop, verified identical output via spot-check).

Pre-registered gates (FROZEN 2026-05-31)

portfolio_cagr             ≥ +5%
max_drawdown               ≤ 25%
sharpe_monthly (ann.)      ≥ 0.5
per_trade_win_rate         ≥ 75%
welch_p<0.05 AND mean>0    (per-trade EV % notional)
both_halves_positive
final_capital > starting
max_single_trade_loss_pct_capital ≤ 0.10%

Detailed numbers

  • Signals after S012 filter (PIT-eligible + calm-regime): 7,661
  • Trades simulated: 7,581 (after dropping insufficient-forward-history)
  • Trades executed (after portfolio-sim sizing): 7,581 (none skipped)
  • Final capital: $155,728 (starting $100,000)
  • Total return: +55.73% over 9.9 years
  • CAGR: +4.57%
  • Max drawdown: 3.4%
  • Sharpe (monthly, annualised): 1.85
  • Per-trade win rate: 82.2%
  • Per-trade mean EV (% notional): +0.88% (identical to S008B — sizing/stop don't change per-trade EV %)
  • Welch p (1-sample): 0.0000, mean positive
  • H1-end capital: $129,494 ($100K → $129K)
  • H2-end capital: $155,728 ($129K → $156K)
  • Worst single trade: −$353.55 (0.354% of starting capital)
  • Yearly P/L: 10 of 11 years positive; range −$726 (2018) to +$11,726 (2021)

Exit-reason distribution

quick_take       58.4%  (≥25% premium captured by day 7)
profit_take      17.5%  (≥50% premium captured any day)
stop_loss        14.6%  (MTM ≥ 2× opening premium)  ← NEW
force_close_loss  4.8%  (day-21 assignment loss; trade ran without stop firing)
force_close_win   4.7%  (day-21 close above strike; close at residual MTM)

The stop is binding on 14.6% of trades. The 4.8% force_close_loss trades are the source of the 0.35% worst-single-trade — these slowly bled into the strike over weeks without ever hitting the 2× MTM threshold.

Why the max-single-trade-loss gate failed (pre-registration error)

I pre-registered the gate based on the math: 1% capital sizing × 200% stop = roughly 0.03% per trade max loss. But this math is wrong: the 200% stop only bounds the loss for trades whose MTM crosses the threshold. Trades that drift slowly into modest losses (e.g., MTM goes from 1.0× to 1.5× to 1.8× of premium over 21 days without ever hitting 2.0×) reach force-close at the full assignment loss, which the sizing rule already bounds at ~1% of capital.

The correct gate calibration would have been: - "max single-trade loss ≤ 1.10% × starting capital" (anchored to the sizing bound, not the stop bound), OR - "stop fires on ≥80% of losing trades" (validates the stop's effectiveness, not the absolute loss bound), OR - Simply omit this gate — the sizing rule already provides the loss bound.

I chose 0.10% based on incorrect arithmetic. Per pre-registration discipline, the gate stands as-specified and counts as a fail. The strategy's actual worst-loss of 0.35% would have passed a correctly- specified version of this gate.

Look-ahead-bias audit

Inherits S011 + S012 audits. Stop-loss-specific check: - MTM evaluated at day-t close uses day-t price (known after close) - Stop fires at day-t close; in a real-world setting this would execute at next-session open (Stage 2 should add this realism) - No future-MTM lookups; the stop trigger checks only contemporaneous MTM

Artifacts

  • Executed trades: lab/postmortem/put-selling-capitulation-combined-v1/trades_executed.parquet
  • Capital path: capital_path.parquet
  • Summary JSON: stage1_summary.json
  • Histogram bins (monthly returns): chart_data.json
  • Driver script: lab/quickkill/put-selling-capitulation-combined-v1/run.py
  • Pre-registered gates: lab/setups/gates.md §put-selling-capitulation-combined-v1
  • Setup spec: lab/setups/put-selling-capitulation-combined-v1.md
  • New code: src/lab/options_sim.py:simulate_short_put gained stop_loss_pct parameter (default None preserves all prior callers' behaviour)

Stage 1 ran 2026-05-31. Pre-registered gates frozen earlier the same day before the test executed. No gates were adjusted post-hoc despite one gate (max single-trade loss ≤ 0.10%) being identified post-run as having been mis-specified by the author. The honest record stands: gate failed as written.

← Olderput-selling-capitulation-combined-v1 Newer →put-selling-capitulation-combined-v2

Mechaniq provides information, not investment advice. We do not execute trades. Past results are no guarantee for future performance. You are solely responsible for your trading decisions.

Lab · Methodology · Greeks Lab · About · FAQ · Glossary · Privacy · Terms · mechaniq.trade © 2026

07 Jul 2026, 07:06