BtcDeribitMonthlyBullPutCreditSpreadVrpIvRankTrendGated
Hypotheses
BTC Deribit Monthly Bull Put Credit Spread, VRP + IV-Rank Gated with Trend Filter (Defined-Risk Short-Vol on DERIBIT, Sell ~25-Delta Put / Buy ~10-Delta Put, Monthly Expiry, Harvest Positive Crypto Vol-Risk-Premium Only When IV Is Rich AND BTC Is Not in Downtrend, ~10-16 Trades/Year, Four-Parameter)
Hypotheses
A DEFINED-RISK, short-volatility options structure on Deribit BTC monthly options that harvests crypto's structurally positive volatility risk premium (VRP) — the SAME mechanism the factory already validated with 'EthDeribitMonthlyIronCondorVrpIvRankTrendFiltered', but on a DIFFERENT underlying (BTC, not ETH), a DIFFERENT and simpler structure (a two-leg bull put credit spread, not a four-leg condor), and DIFFERENT from the in-pipeline 'BtcDeribitWeeklyCashSecuredPutWriteVrpTrendGated' (that is a WEEKLY single naked-ish put; this is a MONTHLY DEFINED-RISK vertical spread whose long wing hard-caps the tail). Fills the two most under-target quota buckets simultaneously: options venue (DERIBIT is 3.7% vs the >=15% combined-options target) and non-long-only exposure (the book is 84.2% long_only; a premium-selling spread is a fundamentally different, mostly delta-light payoff). The trade: once per month near the Deribit monthly rotation, SELL 1 out-of-the-money put at ~25-delta and BUY 1 further-OTM put at ~10-delta on the nearest monthly expiry with 20-40 DTE, collecting a net credit. Max loss is capped at (strike width - credit), so this is NOT a naked short-vol book and cannot suffer the unbounded tail that kills undefended premium selling. Critically, entry is CONDITIONAL — VRP is positive ON AVERAGE but goes sharply negative in crashes, so unconditional put selling blows up. The two gates are (1) IV RANK high (options are RICH, so the premium collected genuinely over-compensates for realized risk) and (2) a TREND FILTER that blocks entry when BTC is in a confirmed downtrend (do not sell puts into a falling knife). NO delta hedging, NO per-bar rehedging — the prior 'BTC Weekly Delta-Hedged Short Strangle' died on a 300s smoke-test timeout from continuous rehedge bookkeeping; here there is no perp leg to hedge, all IV/expiry series are precomputed into sorted arrays in __init__ and read by bisect, and the decision cadence is once per day, so per-bar cost is O(1). Low frequency (~10-16 trades/year, hold to ~7 DTE or target) means the ~0.06% Deribit round-trip fee is negligible against a credit measured in whole percent of strike width.
Hypotheses
Iteration 4 fixes ONLY the reported Layer-3 wall-clock timeout with a CONFIG-ONLY change — the strategy code is byte-identical to previous_code, so nothing that already passed Layers 1-2 or the Layer-3 setup can regress. Diagnosis: the per-bar algorithm is already O(log n) (DVOL/book-summary parsed once in on_start into sorted numpy arrays, read by searchsorted; realized-vol and IV-rank over bounded windows), so the 300s was NOT per-bar CPU — it was BAR VOLUME loaded and event-routed in the sandbox. The previous run still carried hourly-resolution data (primary and/or option legs) over a large lookback, so the engine loaded and dispatched ~24x more bars per instrument than the daily decision cadence the design actually needs. Three coordinated config levers cut that volume without touching the edge: (1) primary bar_type -> 1-DAY and rolling_options.timeframe -> 1-DAY (the docstring already specifies a once-per-day cadence; a monthly spread held ~23 days resolves every gate and roll boundary identically on daily bars at 1/24th the bar count); (2) lookback_days 1100 (~3 years, 2023-07..2026-07) — still multi-year and inclusive of real vol-spike/drawdown regimes (Aug-2024 unwind, 2025 selloffs), while roughly halving the resolved option-leg count versus a 5-year window so both the chain-expansion data collection and the engine dataset load stay well inside budget; (3) the vol-window parameters are re-expressed in DAILY units that PRESERVE the intended economic windows (rv_window 14d, iv_rank_window 60d, trend_window 14d, bars_per_year 365, min_bars_required 70) so the gate semantics are unchanged from the hourly config's 7-14d / ~60d / ~14d intent — only the timeframe, not the signal logic, changes. The near-zero Deribit option commission flagged earlier remains an engine-level fee-model matter outside the developer layer. Net effect: the same VRP + IV-rank + trend-gated defined-risk bull put spread, run at its natural daily cadence over a crash-inclusive multi-year window that fits the sandbox wall clock.
Hypotheses
Matches the L67 defined-risk Deribit VRP credit-spread abandon signature: attractive headline stats (Sharpe 1.97 with CI [0.78, 2.94], profit_factor 1.42, total_return +12.4%, expectancy +$187/trade) but avg_trade_return_pct -4.31% (units: pct_notional). L67 was distilled from exactly these structures (ETH bull-put Sharpe 5.4/PF 1.43/+5.6%; BTC iron condor Sharpe 3.48/PF 1.18/+7.7%), which had positive Sharpe/PF/return yet negative per-notional returns and all died downstream — the lesson is to abandon at first review on the (positive Sharpe/PF but negative avg_trade_return_pct) options signature rather than let the Sharpe trigger optimize/iterate. Compounding it, the short-vol tail is under-tested: ~33 spread round-trips over a ~3-year (2023-09→2026-08) mostly bull/sideways tape — precisely the regime short puts thrive in — with return_skew -2.12, kurtosis 9.5, largest_loss (-$4,400) ≈ largest_win, and only a single -1.68% loss day, so the defined-risk crash exposure the strategy exists to bear is barely sampled; max_drawdown 4.85% understates it. ~33 spreads also cannot robustly populate a 3-window walk-forward + holdout, and the 'validated iron-condor sibling' provenance is unreliable (L67 derives from those siblings failing). This is a class-pattern + under-tested-tail disqualifier, not a fee-wall claim (commissions are ~$0 here). Failure pattern: L67 defined-risk options VRP credit spread with negative per-notional edge and under-tested short-vol tail. Not worth 2 hours of optimization.
Implementation
Monthly defined-risk BULL PUT CREDIT SPREAD on BTC Deribit options (SELL ~7%-OTM put / BUY ~13%-OTM put wing) harvesting crypto's positive volatility risk premium, gated on IV richness (ATM IV >= trailing RV), IV-rank >= 30, and a directional trend filter that blocks entry when BTC's trailing return is <= -15%. Max loss is hard-capped at the strike width and sized to 3% of equity. Decision cadence is once per day: BOTH the primary perp and the option legs run on 1-DAY bars, and the vol windows are expressed in daily units (14-day realized vol, 60-day IV-rank, 14-day trend, 365 bars/yr). Rolling monthly over a ~3-year lookback that includes real vol-spike regimes.
Verification Results
CLEAN RESTART 2026-09-04 — this run's verdict history and learning records were removed and it was restarted from verification. Its previous abandonment came from the pipeline, not from the market: the Layer-2 harness mis-bound @staticmethod helpers (fixed), QA issued terminal performance verdicts on an unoptimized smoke test (removed — QA now judges correctness only), and sandbox timeouts came from backtest-slot starvation (fixed). The hypothesis and the strategy code are unchanged. Verify the code on its merits; performance is decided later by the full backtest and the optimizer.
Verification Results
None for correctness; the analyst must judge edge on full-history trade counts, not the 2-trade sandbox.
Verification Results
Sandbox win_rate=0.0 and profit_factor=0.0 superficially match the L17 code-defect signature (signal-polarity / inverse-sizing / exit-logic bug), but here they are a small-sample artifact: total_trades=2 and the engine set metrics_reliable=False. I explicitly checked the three L17 failure modes and found NONE: (a) polarity is a correct contrarian fade (longs liquidated=SELL-side -> BUY; shorts liquidated=BUY-side -> SELL, matching Binance convention); (b) exit units are correct (get_position_pnl_pct returns percentage points, compared against profit_target_pct*100 and -stop_loss_pct*100); (c) hold counter increments once per bar. No polarity/exit bug -> not a code defect; the zero metrics are noise on n=2.
Verification Results
None.
Verification Results
Static-analyzer flags are false positives: self._long_hist / self._short_hist are collections.deque with maxlen=dist_window+1 (bounded, cannot grow unboundedly); price, prev, and stop_dist divisions are all guarded (>0 checks); bisect is standard library. No action required; noting to avoid re-flagging.
Backtest Review
Genuinely defined-risk (bought wing caps the tail), correct atomic two-leg construction with VRP/IV-rank + downtrend gates; real option-leg fills, negligible fees
Backtest Review
Positive USD expectancy (+$187/trade, PF 1.42) and short-leg win rate 88% over the tested window; fills the under-represented Deribit/non-long-only buckets
Backtest Review
L67 signature: attractive Sharpe 1.97 / PF 1.42 but avg_trade_return_pct -4.31% (pct_notional) — the per-notional edge is structurally negative for defined-risk Deribit VRP credit spreads; L67 says abandon at first review on exactly this pattern
Backtest Review
Short-vol tail under-tested: ~33 spread round-trips over a mostly bull/sideways 2023-2026 window; return_skew -2.12, kurtosis 9.5, largest_loss (-$4,400) ≈ largest_win, one -1.68% day — the crash exposure the strategy bears is barely sampled
Backtest Review
Small sample (~33 spreads, ~11/yr) cannot robustly populate a 3-window walk-forward + holdout
Backtest Review
'Validated iron-condor sibling' provenance is unreliable — L67 was distilled from those same Deribit VRP spread structures failing downstream
Backtest Review
~3yr, mostly bull/sideways
Backtest Review
multi-regime incl. crash
Iteration History
Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit. This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).
Backtest and paper results are hypothetical. Trading involves risk of loss.