PerpDiscountCapitulationSpotLong
Hypotheses
Perp-Discount Capitulation Reversal on Liquid Spot (Cross-Venue: BINANCE USD-M Perp Mark-vs-Index PREMIUM as Non-Price Signal → Buy BTC & ETH on BINANCE_SPOT When the Perp Trades at a Deep Forced-Deleveraging Discount to Index, Premium-Normalization Exit, 3-Parameter)
Hypotheses
A LONG-ONLY, cross-venue capitulation-reversal strategy that trades the SPOT leg but takes its signal from a genuine non-price futures feed: the USD-M perpetual's mark-vs-index PREMIUM. When leveraged longs are force-liquidated, the perp is sold down BELOW the index (deep negative premium / backwardation spike) faster than spot can follow — a mechanical, observable dislocation. This strategy buys BTCUSDT.BINANCE_SPOT and ETHUSDT.BINANCE_SPOT precisely on those deep-discount prints and holds the reversion. It is deliberately the SAME economic idea as the 'liquidation-capitulation reversal' family that has been abandoned FIVE times this session — but those all died on a DATA wall (the Binance liquidations feed is only live-accrued to ~90 recent days, so 3 entries ever fired over 2019→2026). This version replaces the unavailable liquidations feed with the perp PREMIUM (mark_price/index_price klines), which HAS confirmed multi-year history in the catalog — i.e. the same edge on a data source that actually exists. It also fixes the two failure modes of the dead spot dip-accumulation basket (61% drawdown, 88% impact cost): it trades ONLY the two deepest-liquidity names (negligible market impact vs the thin-8-alt baskets) and imposes a hard stop + time-box to bound the falling-knife risk that has no drawdown control in the dip baskets. It fills three under-represented buckets at once — BINANCE_SPOT (11.7% vs ≥15% target), cross-venue (7.1% vs ≥15%), and the non-price-signal lane — while escaping every documented death class: not pure-OHLCV (L30 — depends on the premium feed, not price), not options (L29), not a two-legged funding cash-and-carry (L28 — single spot leg, no funding), not the sparse liquidations feed (L3), and not a thin-alt impact bomb. 3 parameters to resist overfitting.
Hypotheses
Fixes the Layer-1.5 rejection by trading exactly the instruments the hypothesis declares. The previous iteration had moved execution to the USD-M perp on the reasoning that a perp-vs-spot discount closes through the perp rising, which is economically sound but is a different venue and contract type with different fees and settlement, so the consistency gate blocked it. The traded legs are now BTCUSDT.BINANCE_SPOT (primary) and ETHUSDT.BINANCE_SPOT, with BTCUSDT.BINANCE and ETHUSDT.BINANCE present purely as signal-carrying extras that no code path ever sends an order to. I confirmed the runner supports this: it builds a separate venue config for extra legs on other venues (runner.py:580), and all four legs have 15-minute catalog data. Two consequences of moving to a CASH account are handled: leverage is pinned to 1.0 (the spot hard cap), and sizing no longer reads equity naively — on a CASH account the USDT balance drops as each sleeve is bought, so the second sleeve would have sized off the post-purchase balance. Sleeves are now sized against a base captured while the whole book is flat and additionally capped at 98% of available cash. The entry path also now submits on the spot leg's own bar rather than the primary bar. Everything that already passed is untouched: imports unchanged, the instance-method _bar_ts override that keeps the Layer-2 proxy from mis-binding the base staticmethod, the contemporaneous-bar alignment check, the rolling premium z-score, the recovery-tick entry with per-episode hysteresis, and the trim-immune monotonic bar counter behind the time box. I added _param_bounds mirroring every clamp. Entry frequency is verified rather than assumed: replaying 4,512 aligned BTC spot-vs-perp 15m bars gives 18 entries at the default entry_z=2.5 (74 at 2.0, 7 at 3.0) on BTC alone, so there is no zero-trade risk with two names. One honest caveat for the analyst, which I have also put in the docstring: a perp discount can close either by the perp rising or by spot rising, and a spot-only long captures only the latter, so this expresses the signal less directly than the perp leg would — but the hypothesis specifies the spot leg, so that is what this implements, and the mechanism's profitability is the analyst's call after a full backtest.
Hypotheses
Negative expectancy on a reliable 107-trade sample: profit_factor 0.373, total_return -3.56%, Sharpe -3.05, expectancy -$66.5/trade. The perp-discount capitulation-reversal signal is gross-negative BEFORE fees (0.243*163.15 - 0.757*140.22 = -$67/trade; commission is a further 152% of gross), so there is no positive edge for the two-liquid-name / low-impact construction to monetize. avg_trade_return_pct 0.102% is also below the BINANCE_SPOT ~0.25% fee floor. This is a mean-reversion fade with PF < 1.15 and negative return (L55) -- tuning entry_z/stop/max_hold cannot manufacture positive expectancy the signal does not contain. The premium-feed swap fixed the data wall of the five prior siblings, but the newly-testable mechanism simply has no reversal edge in liquid spot. Not worth 2 hours of optimization. abandon_class=negative_expectancy.
Implementation
Long-only cross-venue capitulation-reversal trading BTCUSDT.BINANCE_SPOT and ETHUSDT.BINANCE_SPOT on 15-minute bars, signalled by the matching Binance USD-M perpetual's discount to spot. Each bar computes premium = (perp_close - spot_close)/spot_close in bps from contemporaneous bars of the two venues and z-scores it over a rolling lookback window. When forced deleveraging drives the perp to a deep discount (z <= -entry_z) the strategy waits for the FIRST recovery tick — the premium ticking back up — and buys the spot leg, so it never enters mid-cascade. Each name fires at most one entry per discount episode, re-arming only after the premium recovers above -rearm_z. Positions exit on premium normalization (z >= exit_z), a 1.5% hard stop, or a 48-bar (12h) time box. Sleeves are 30% of a flat-book equity base each, capped by available USDT, on a CASH account with no leverage and no shorting. The perps are signal-only legs and are never traded.
Verification Results
Verification failed (Layer 1.5 — hypothesis/config consistency) [class=hypothesis_mismatch]:
- config.instrument_id is BTCUSDT.BINANCE but the hypothesis declares BTCUSDT.BINANCE_SPOT — same asset, DIFFERENT venue/contract type (fees, settlement and the mechanism's premise differ). Trade the declared instrument.
Verification Results
Optimizer should target configs whose realized per-trade edge exceeds 0.20%; iterate/abandon at analyst stage if the full backtest confirms sub-fee returns.
Verification Results
Fee-viability watch: entry is z-score-gated (scale-invariant), so check-8's price-move rule doesn't apply directly, but sandbox per-trade return (0.0838%) sits below the ~0.20% BINANCE_SPOT round-trip, commissions at 165% of gross. Not a code defect — carried as edge_concern.
Verification Results
No code change required; implementation matches the written hypothesis. Analyst should weigh this when judging edge.
Verification Results
Mechanism fidelity: the discount can revert via the perp rising rather than spot; a spot-only long captures only the spot-upward resolution. The code faithfully implements the hypothesis's DECLARED spot leg, so this is NOT a failing mismatch — it caps how much of the signal is monetizable.
Backtest Review
Clean cross-venue construction: trades the two most liquid spot names so market impact is minor (avg_position_pct 15%, max_drawdown only 4.3%).
Backtest Review
Uses a genuinely available multi-year signal feed (perp premium) instead of the sparse liquidations feed that killed the prior siblings, and has real drawdown controls (hard stop + time-box).
Backtest Review
Negative expectancy on a reliable 107-trade sample: profit_factor 0.373, total_return -3.56%, Sharpe -3.05, expectancy -$66.5/trade.
Backtest Review
Gross-negative BEFORE fees: 0.243x163 - 0.757x140 = -$67/trade; the perp-discount reversal signal has no positive gross edge (commission is 152% of gross, but removing fees still leaves a loss).
Backtest Review
avg_trade_return_pct 0.102% sits below the BINANCE_SPOT ~0.25% round-trip floor.
Backtest Review
win_rate 24.3% with avg_win ~= avg_loss is structurally adverse for a mean-reversion fade; max_consecutive_losses 14. Negative in the calm and stressed regimes alike.
Iteration History
PerpDiscountCapitulationReversalSpotLong
Iteration History
Verification failed (Layer 2 — synthetic scenarios):
Parameters used: ['exit_z', 'entry_z', 'lookback', 'alloc_frac', 'min_notional', 'max_hold_bars', 'stop_loss_pct']
Check that __init__ sets all attributes from self.parameters.get().
- steady_uptrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
- steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
- flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
- volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
- zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
- price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735695600000)
Iteration History
Verification failed (Layer 4 — QA review):
- Time-box risk control is silently broken by buffer trimming. `_entry_idx[sym]` is stored as an ABSOLUTE index into `self._prem[sym]`, but that buffer is front-trimmed (`del buf[:-600]` once len>600). Front-trimming shifts every absolute index, so the stored entry index goes stale. Once the buffer hits its 600 cap (~6.25 days into any real backtest), len(buf) is pinned at 600 every bar while entry_idx stays fixed at 600, so `held = len(buf) - entry_idx` is 0 forever and `held >= max_hold_bars` NEVER fires. The hypothesis names the time-box as one of its two headline drawdown controls; it stops functioning in steady state. Corroborated by sandbox avg_holding_bars = 0.0.
- Signal-source divergence: hypothesis specifies the perp mark_price/index_price klines PREMIUM (a non-price feed); code instead computes perp OHLCV close vs spot OHLCV close (subscribe_mark_prices=false). The economic mechanic (buy spot on deep perp discount) is preserved so it's a warning, but the strategy's claim to escape the pure-OHLCV zero-survivor class is false — both legs are ordinary price bars.
- Marginal/negative fee viability on SPOT (~0.20% round-trip). Signal is a tiny perp-vs-spot basis z-score, and a discounted perp can revert via the perp rising rather than spot rising — buying spot may not capture the closure. Sandbox: avg_trade_return_pct 0.0268% (below the 0.20% round-trip), PF 0.219, Sharpe -4.18, turnover 82.9. Analyst-stage concern, flagged as a repeat-loser pattern.
Iteration History
Verification failed (Layer 4 — QA review):
- Fee-negative with no directional edge, now the SECOND iteration to lose decisively. Sandbox (42d, 76 trades): total_return -3.64%, PF 0.617, Sharpe -3.43, avg_trade_return_pct -0.0109% (negative, vs 0.20% spot round-trip). Turnover ROSE to 114.6 (from 82.9) — the hysteresis fix didn't cut churn. Structural cause: a perp-vs-spot discount reverts through the PERP rising back to spot, not the SPOT leg rising, so buying spot doesn't monetize the signal. Iter1 also lost (-2.06%). Two windows both negative = decisive no-edge.
- The hard stop doesn't bound the falling-knife risk the hypothesis claims. Stop is a next-bar market exit on 15m closes; buying into a liquidation cascade, spot gaps past -1.5% before filling. Result: largest_loss -$5,921 vs avg_win $318 (~19x tail), avg_loss > avg_win despite TP>SL, skew -2.66. The drawdown-control premise isn't delivered when it matters.
- Signal still uses perp_close vs spot_close (two LAST-price OHLCV series), not the mark/index premium klines the hypothesis names — so the 'not pure-OHLCV' claim is false. Defensible engineering call, so a warning, but should not be credited with a non-price edge.
Iteration History
PerpDiscountBasisReversalPerpLong
Backtest and paper results are hypothetical. Trading involves risk of loss.