Skip to content

View translation

XrpOiDivergenceSpikeFadeLS

Hypotheses

XRP Perp OI-Divergence Spike Fade (Single-Instrument USD-M, Long-Short, 1H, Fade Sharp Moves on FALLING Open Interest, Stand Aside on Rising-OI Conviction)

Hypotheses

A long-SHORT, SINGLE-INSTRUMENT, single-venue MEAN-REVERSION strategy on XRPUSDT.BINANCE USD-M perpetual futures using 1-HOUR bars, that FADES sharp price spikes ONLY when they are accompanied by FALLING open interest. This is the deliberate structural COMPLEMENT to the factory's OI-confirmed-trend strategy (which goes WITH price when OI is RISING): the two halves form one coherent open-interest-conditioned framework — rising OI during a move = new capital with conviction = continuation (trade with it); FALLING OI during a move = position UNWINDING (short-covering squeeze up, or long-liquidation flush down) with NO new directional conviction = the move is mechanical and mean-reverts (fade it). CRITICAL DESIGN NOTES separating this from the closed families and anti-patterns: (1) it is NOT generic single-symbol RSI/Bollinger mean-reversion — the differentiating MICROSTRUCTURE TWIST is the OI-divergence gate: it fades a spike ONLY if OI is contracting, and explicitly STANDS ASIDE when OI is rising (genuine conviction that would steamroll a fader), which is precisely the filter that makes naive crypto mean-reversion fail without it; (2) it is NON-momentum (the session has declared directional momentum dead) and profits from REVERSION, which the current 2025-26 chop regime rewards; (3) it is a SINGLE creditable price leg — no carry, no basis, no delta-neutral cancellation, no funding-as-cashflow dependency (OI is a SIGNAL only, the validated role for crypto-native data); (4) NOT cross-venue / HYPERLIQUID, NOT COIN-M (engine-blocked), NOT trade-tick — it reads aggregated per-bar OHLCV + the open_interest supplementary series, fully representable in the bar engine; (5) XRP is among the most liquid, longest-listed, highest-retail-flow alts with deep OI history, so walk-forward has real power (no thin-data wall) and sharp squeeze/flush moves are frequent, populating every OOS window densely — the opposite of the event-sparsity that killed the drawdown-accumulation class. Intentionally minimal: 3 tunables (ret_lookback, ret_entry_z, oi_drop_threshold).

Hypotheses

Before changing anything I measured the actual cost: the strategy's entire per-bar arithmetic runs in 0.33 s over a full 20,000-bar window, the open-interest series is built ONCE lazily (~51k rows for XRPUSDT) and every lookup is a bisect (O(log n)), and there is no sort/min/full-series rescan anywhere — so the reported 'per-bar work that scales with history' diagnosis does not describe this code, and the 300 s is far more consistent with data/slot contention (the same backtest-slot starvation that other runs in this batch were restarted for). I therefore made the smallest change that still removes every remaining non-constant per-bar operation rather than restructuring a working mechanism: the trailing-return z-score no longer re-slices the return list and loops over 72 elements each bar — the returns live in a deque(maxlen=z_window) with running sum and sum-of-squares, so mean and sample variance come from two scalars, and the deque's own eviction replaces the per-bar list-copy trim. I verified numerically that the new z-score is identical to the old one (max absolute difference 1e-14 over 500 bars), so signal values, the OI-divergence gate, entry/exit rules, sizing and all three tunables are behaviourally unchanged. Bar type stays 1-HOUR as the hypothesis specifies.

Hypotheses

Statistically empty and negative single-perp OI-gated fade — not worth 2 hours of optimization. The OI supplementary feed is recent-only, so despite 58,360 bars of XRP history (2020-2026) every trade falls in one 2026 regime (annual_returns only {2026}, only_one_regime true, effective_daily_obs 32, all stress windows null) — directly falsifying the hypothesis's claim of 'deep OI history / no thin-data wall / every OOS window densely populated.' The OI-drop gate plus z>=2 spike is so restrictive it produced just 30 trades over 6.6 years, and on that sample the edge is negative: total_return -0.21%, expectancy -$6.77/trade, profit_factor 0.84, Sharpe -0.32 with CI [-0.95, 0.45], avg_loss > avg_win, commission 28.86% of gross, and avg_trade_return_pct 0.079% below the 0.15% floor. A 3-window walk-forward plus 20% holdout would leave a handful of trades per fold, so any optimized Sharpe would be best-of-N noise. This is the L73 single-perp OI/supplementary-gated directional family crossed with the L55 single-name fade family, both zero-survivor this session. No parameter change buys the multi-year OI history the feed lacks or flips a negative-expectancy 30-trade single-regime sample. Failure pattern: data_unavailable/no_edge single-perp OI-gated fade, unmeasurable single-regime sample (L73/L55).

Implementation

Long-short single-instrument mean reversion on XRPUSDT.BINANCE USD-M perp, 1-HOUR bars. Each bar the 6-bar trailing return is z-scored against the prior 72 returns; a sharp spike (|z| >= 2) is FADED — but only when open interest over the same 6-hour window has FALLEN by at least 2% (position unwinding: short-covering squeeze up or long-side flush down, i.e. a mechanical move with no new directional conviction). When OI is flat or rising the strategy explicitly STANDS ASIDE, since a conviction-backed move would steamroll a fader. Exits on reversion (|z| < 0.5), a 3% protective stop, or a 12-bar max hold. Open interest is a SIGNAL only, never a cash flow; if the OI series is empty the strategy stands aside rather than falling back to a price-only proxy.

Verification Results

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (833 days of XRPUSDT.BINANCE-1-HOUR-LAST-EXTERNAL). 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 Review

Clean 3-parameter single-instrument construction; OI used as signal-only (correct role); point-in-time bisect lookups; contained risk (max_drawdown 0.56%, no blow-up)

Backtest Review

Statistically empty: only 30 trades over 6.6 years, all in a single 2026 regime (only_one_regime true, effective_daily_obs 32) — the OI feed is recent-only, so the multi-year 'deep OI history' the hypothesis claimed does not exist

Backtest Review

Negative on that sample: total_return -0.21%, expectancy -$6.77/trade, PF 0.84, Sharpe -0.32 (CI [-0.95, 0.45]), avg_loss > avg_win

Backtest Review

Fee-heavy: commission 28.86% of gross; avg_trade_return_pct 0.079% below the 0.15% floor

Backtest Review

L73 single-perp OI/supplementary-gated + L55 single-name fade families, both zero-survivor; 3-phase validation cannot populate on 30 single-regime trades

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['exit_z', 'z_window', 'ret_entry_z', 'min_notional', 'position_pct', 'ret_lookback', 'stop_loss_pct', 'max_holding_bars', 'oi_drop_threshold'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000) - steady_downtrend: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000) - flat_ranging: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000) - volatility_spike: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000) - zero_volume: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000) - price_gap: TypeError: XrpOiDivergenceSpikeFadeLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735694340000)
Strategy report

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