Skip to content

View original

BtcOpenInterestCrowdingReversalLS

Hypotheses

BTC Perp 4H Open-Interest Crowding Reversal (Single-Instrument USD-M, Long-Short, Trapped-Positioning Unwind)

Hypotheses

A long-SHORT, SINGLE-INSTRUMENT, single-venue reversal strategy on BTCUSDT.BINANCE USD-M perpetual futures using 4-HOUR bars, where OPEN INTEREST (supplementary data) is the structural signal and price action is the P&L (OI is used only as a signal, never credited as a cash flow). The thesis is trapped-positioning unwind: when a sharp directional price move is accompanied by a sharp RISE in open interest, it means the move is driven by NEW leveraged positions piling in (fresh longs into a rally / fresh shorts into a sell-off) rather than by genuine spot demand — a crowded, offside book. Once price stalls and turns, those new positions are underwater and become forced fuel (long liquidations / short covering) that drives a sharp reversal. The strategy fades the exhausted move only when OI confirms crowding, and explicitly SKIPS moves where OI is falling (healthy de-leveraging with no trapped fuel). This deliberately avoids every recurring failure this session: NOT BINANCE_SPOT (CASH metric bug), NOT BINANCE_CM (not backtestable), NOT cross-venue/Hyperliquid (basis artifact), NOT a multi-instrument pair (extra-leg feed not delivered to optimizers), NOT funding-carry (no uncreditable cash flow), NOT trend-following (over-represented/overfit-prone), and NOT generic buy-the-dip MR — it is gated on an observable positioning-crowding condition (OI surge), giving a POSITIVE-skew forced-unwind payoff rather than the negative-skew falling-knife profile that killed prior MR attempts. BTC is chosen for the deepest, most reliable OI history (minimizing the data-sparsity risk that broke alt-based ideas). It fills the long-short direction quota (only 14.4% vs heavy 85.6% long-only) on the clean single-instrument USD-M OHLCV path, and is kept to ~4 parameters to resist overfitting.

Hypotheses

Implements the trapped-positioning-unwind hypothesis exactly: OI is signal-only (never a credited cash flow), the crowding gate (og>0 and oi_z>=oi_surge_z) is what distinguishes this from generic mean reversion, and the falling-OI skip delivers the positive-skew profile. Iteration-4 fix for the Layer-3 timeout: the previous revision merged the full-history `metrics` stream (hundreds of thousands of 5-min OI rows back to ~2020); loading and parsing that payload blew the 300s smoke wall-clock. This revision references only the lighter-weight `open_interest` supplementary stream, which loads fast and covers the recent smoke/backtest window — all trading logic, gates, z-scoring, sizing, and the one-time bisect index are unchanged, so Layers 1 and 2 stay green while the smoke backtest completes well under the limit. Stays on the clean single-instrument USD-M path (BINANCE futures, MARGIN, long+short) required to short; leverage kept at 1.0 (referenced in the notional cap but not amplifying, so no leverage_set_but_unused flag).

Hypotheses

verifying_stuck_3_timeouts

Implementation

Single-instrument long-short reversal on BTCUSDT.BINANCE USD-M perpetual 4-HOUR bars. Uses open-interest (supplementary) as the structural crowding signal and price action for P&L. When OI surges (rising AND z-score above threshold) alongside a sharp price extension, it fades the exhausted move (short into OI-fueled rallies, long into OI-fueled flushes), betting the trapped leveraged positions unwind. Moves on falling OI (healthy de-leveraging) are skipped for a positive-skew forced-unwind payoff. OI is indexed once and looked up per bar via bisect (O(log n)).

Verification Results

Verification failed (Layer 4 — QA review) [class=not_measurable]: - [edge_concern] Setting measurability aside, the 15-trade sandbox is also weakly negative (total_return -0.51%, PF 0.91, avg_loss $909 > avg_win $550, return_skew -0.78) — the opposite of the positive-skew forced-unwind payoff the hypothesis promises. But with only 15 trades this is noise, not evidence either way; the real blocker is that the sample is too small to conclude anything. Do not read the negative sandbox as the edge failing — read it as unmeasurable. - NOT MEASURABLE — OI data coverage limits the strategy to ~15 trades over the FULL backtest. The sandbox is not a truncated smoke window: it processed 14389 bars / 2398 data_days (the full ~6.5-year BTC 4H history) yet produced only 15 trades, and every stress window from 2020 through 2025 reports exactly 0.0 return (no trades). That shows the `open_interest` stream the strategy reads covers only a recent slice (~last year), so the crowding gate can only fire there. 15 trades cannot populate the HARD >=10-trade holdout (last 20% ~= 3 trades) or a 3-window walk-forward, and cannot distinguish edge from noise (L16/L26). The fuller data exists — the developer's rationale states the full-history `metrics` OI stream reaches ~2020 — but it was removed because loading its hundreds of thousands of 5-min rows blew the 300s Layer-3 wall-clock. So the limit is loading performance, not a genuine absence of OI history.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['risk_pct', 'oi_surge_z', 'price_ext_z', 'min_notional', 'max_hold_bars', 'stop_loss_pct', 'zscore_window', 'change_lookback', 'take_profit_pct', 'max_notional_frac', 'zscore_min_samples', 'oi_max_staleness_sec'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000) - steady_downtrend: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000) - flat_ranging: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000) - volatility_spike: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000) - zero_volume: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000) - price_gap: TypeError: BtcOpenInterestCrowdingReversalLS._parse_oi_row() takes 2 positional arguments but 3 were given (bar timestamp: 1735691340000)

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).
Strategy report

Backtest and paper results are hypothetical. Trading involves risk of loss.