Skip to content

View original

OiInflowWeeklyRotationMajorsLongSpot

Hypotheses

Open-Interest-Inflow Long-Only Spot Rotation over Majors (Weekly Rebalance, Signal from Perp OI Growth + Uptrend Regime Gate, Execution on BINANCE_SPOT, 3-Parameter)

Hypotheses

A LONG-ONLY, multi-instrument WEEKLY rotation strategy executed on Binance SPOT majors, whose ranking factor is a genuine non-price futures feed with confirmed multi-year history: perpetual open-interest growth. Each week, rank a fixed basket of liquid majors by the trailing growth in their perp open interest (fresh capital / conviction inflow), and hold the top-3 that are ALSO above their long-term moving average (regime gate to avoid buying inflows into a crash). This is deliberately in the PROMOTED-WINNER family (long-only rotation) rather than the 0/53-survival dollar-neutral basket class (L12) — turnover is low, only one long leg per name, no shorting, so per-rebalance fees are a fraction of the market-neutral rank-and-rotate that repeatedly died. Critically, the SORT factor is OI inflow, NOT relative strength — the exact 'new signal input no promoted basket already uses' that L24 requires to avoid the duplicate-momentum-rotation graveyard. It is a completely different family from the abandoned taker-flow divergence reversal it replaces: multi-instrument not single-name, weekly not intraday, long-only spot not long-short futures, rotation not fade, OI-inflow factor not order-flow-vs-price divergence. It fills the highest-survival, most under-represented venue (BINANCE_SPOT at 6%) while sourcing an edge from a futures-only microstructure feed — a real cross-venue signal/execution split.

Hypotheses

The QA block was that the hypothesis's required factor — per-name perp OI growth — was absent, replaced by dollar-turnover growth, on the belief that per-instrument OI cannot be injected. That belief is wrong, and the previous file even hints at it: it already listed "open_interest_by_instrument" in _supp_keys but only ever read supp["open_interest"] (the primary series). The per-leg map is built by subprocess_entry._add_per_leg_open_interest for every leg whenever a strategy references the key, and supp_collector._OI_VENUES includes BINANCE_SPOT, which maps each spot leg to its matching USDT perp. I verified the data for all ten basket members: BTC 28,923 hourly points from 2020-09, the other nine 37k-41k from 2021-12, every one current to 2026-09. So the ranking factor is now the real thing: per-name OI inflow, with the close*volume turnover proxy deleted outright (the only remaining mentions of volume are docstring prose explaining the removal). This also repairs QA item 3: because every leg carries OI, the market regime gate is now the growth of basket-aggregate perp OI rather than degrading to BTC-above-its-MA for most of the window, and when OI history is insufficient the book stays FLAT rather than falling back to a price proxy. The per-name long-term MA gate stays because the hypothesis itself specifies it ('hold the top-3 that are ALSO above their long-term moving average'). I checked the factor actually differentiates before submitting: replayed over the real per-name OI series it gives 245 weekly rebalances, an average of 5.55 of 10 names with OI building, and 1.18 name changes per rebalance (~290 sleeve trades) — a live, low-turnover rank, not the alphabetical-tiebreak collapse a single shared series produced. I also fixed the uptime-relative cadence ((self._proc - 1) % rebalance_period) to a calendar bucket derived from the bar timestamp, per the schedule rule, so rotation dates survive restarts and replay. Point-in-time discipline is unchanged (np.searchsorted as-of, no abs() matching), buffers are bounded, and _param_bounds now mirrors every clamp. On the advisory: the previous +1226% run was long-only majors beta, and with the rank now driven by OI rather than turnover the return profile should be judged fresh — I have deliberately not tuned anything toward that old number.

Hypotheses

L45/L49/L19 long-only multi-instrument majors basket carried by crypto beta with NEGATIVE alpha over its own benchmark — not worth 2 hours of optimization. Despite the correctly-wired OI signal, information_ratio is -0.948 versus the equal-weight-basket benchmark (benchmark_meaningful=true): the OI sort subtracts risk-adjusted value over a naive equal-weight hold of the same 10 names, so the +19.8% headline is long-crypto beta (beta 0.12), not signal. It carries a 64.75% max drawdown (CI to 84%), above the 50% hard-abandon bar (L19), and the OI-growth regime gate failed to cut the 2022 crash (-56.8% year, luna -30.5%, ftx -28.9%, rate-shock -42.5%). It is not significant: Sharpe 0.19 with bootstrap CI [-0.456, 0.826] straddling zero, PSR 0.643, and over ~9 years it returned only +19.8% (CAGR 3.7%) — underperforming buy-and-hold with stressed-regime Sharpe -0.36. The base Sharpe is the ceiling the ~225-trial deflation only lowers; there is no parameter region that turns a beta stream with negative alpha and a 65% drawdown into an edge. Failure pattern: no_edge/risk_reject long-only majors rotation basket, beta-carried with negative IR vs benchmark, >50% drawdown (L45/L49/L19).

Implementation

Long-only weekly cross-sectional rotation over 10 liquid Binance SPOT majors (BTC, ETH, SOL, BNB, XRP, ADA, DOGE, LINK, LTC, AVAX) on daily bars, ranked by each name's own perpetual OPEN-INTEREST growth — the log change between the mean of the last `lookback` daily OI samples and the mean of the prior `lookback` samples, i.e. fresh leveraged capital flowing into that name. Signal is sourced from the USD-M perp feed while execution is on spot, the cross-venue split the hypothesis specifies. Each week the book holds the top_n names whose OI is building AND that trade above their own long-term moving average (crash filter), equal-weight at 31% of equity each. A market-wide gate on basket-AGGREGATE perp OI growth keeps the book flat whenever fresh money is leaving the complex. Rebalances fire on a calendar-anchored weekly grid derived from the bar timestamp; names held across consecutive weeks are never re-traded, so only the delta pays spot fees. Leverage 1.0, no shorts.

Verification Results

Verification failed (Layer 4 — QA review) [class=hypothesis_mismatch]: - [edge_concern] The strong sandbox (+1226%, Sharpe 0.95, avg_trade_return_pct 9.47%, 232 trades) is long-only majors beta/trend, not evidence of the hypothesized OI edge: benchmark_correlation 0.53, beta 0.27, return concentrated in bull terciles, worst losses in 2022 rate-shock/FTX, end_unrealized -61.7%, max_drawdown 44%. It measures a turnover+trend rotation, not the OI-inflow factor. Advisory; the block is fidelity. - Core edge absent: the hypothesis ranks by per-name perp OPEN-INTEREST growth (the explicitly-required novel futures-only signal, L24). Per-instrument OI is never injected (primary only), so the developer substitutes the RANK with per-name dollar TURNOVER growth (close*volume) — an OHLCV participation measure, not OI. The specified OI-inflow ranking edge and its cross-venue signal/execution split are gone. - OI barely participates even in its demoted role: _market_risk_on degrades to BTC-above-MA (pure price) for most of the window per the developer's own disclosure that OI covers only a fraction of history. The executable strategy is a spot-majors volume+trend rotation, not the OI-inflow rotation described. Same per-name-metrics infeasibility that failed the OI-fragility / retail-crowding / top-trader-rotation siblings.

Verification Results

Size new entries from free cash, or exit dropped names in a first pass before submitting entries in a second pass.

Verification Results

New entries are sized at equity*per_name_frac(0.31)*leverage using TOTAL account equity, but on a CASH (spot) account most equity is already tied up in persisting positions. When rotating in a new name before the dropped name's exit fill settles, available cash may be < the computed notional and the BUY can be rejected. Not a signal-correctness bug, but can under-fill rotations.

Verification Results

Log the count of legs with non-empty OI series at startup so a degradation to primary-only is visible in diagnostics.

Verification Results

The mechanism depends on infrastructure injecting open_interest_by_instrument for every spot leg. If that per-leg map is absent on the real-backtest path, the primary-only fallback (supp['open_interest']) leaves only BTC rankable and the basket rotation silently collapses to a BTC-only book. The sandbox producing 196 trades indicates OI history was present (the gate requires it), but the full run should be confirmed to rank all 10 names.

Backtest Review

The iter-2 fix genuinely wires the per-name perp OI feed (a real non-price futures signal), so this is not a duplicate-momentum-rotation and the OI ranking is implemented as the hypothesis intends.

Backtest Review

avg_trade_return_pct 2.01% clears the spot fee floor, and commissions are only 3.66% of gross, so this is NOT a fee-edge failure.

Backtest Review

max_drawdown 64.75% (CI to 84%) — above the 50% hard-abandon bar (L19); 2022 annual return -56.8%, luna window -30.5%, ftx -28.9%, rate-shock -42.5%. The OI regime gate did NOT protect against the crash.

Backtest Review

Negative alpha and negative information_ratio (-0.948) versus its OWN equal-weight-basket benchmark (benchmark_meaningful=true): the OI sort adds NO risk-adjusted value over a naive equal-weight hold of the same 10 names — the +19.8% headline is just long-crypto beta (beta 0.12, corr 0.33).

Backtest Review

No significance: Sharpe 0.19 with bootstrap CI [-0.456, 0.826] straddling zero, PSR 0.643. Over ~9 years (2017-2026) it made only +19.8% total (CAGR 3.7%), losing to buy-and-hold.

Backtest Review

Return is concentrated in single bull-regime spikes (2024-11-21 +54.9% day, 2024 +90% year) while stressed-vol regime Sharpe is -0.36; recent regime is flat-to-negative (2025 +2.1%, 2026 +1.1%).

Iteration History

BtcPerpOiInflowTrendLongSpot

Iteration History

Verification failed (Layer 4 — QA review): - WHOLE-STRATEGY SWAP — the code does not implement THIS hypothesis. The hypothesis is a MULTI-INSTRUMENT, WEEKLY, CROSS-SECTIONAL rotation: 'rank a fixed basket of liquid majors by the trailing growth in their perp open interest ... and hold the top-3 that are ALSO above their long-term moving average.' The code is a SINGLE-NAME (BTCUSDT.BINANCE_SPOT only, no extra_instruments), 4-HOUR, long/flat timing overlay on one asset. Three defining elements of the hypothesis are all absent: (1) the basket / top-3 selection — there is no universe and no ranking across instruments; (2) the cross-sectional RANK factor — the code z-scores one name's own OI against its own history, which is a time-series timing gate, not the cross-sectional 'rank the basket' mechanic the hypothesis names; (3) the WEEKLY rebalance — config bar_type is 4-HOUR. Per the QA checklist, when a cross-sectional-basket hypothesis's code fails to rank N instruments, and instrument set + timeframe + mechanism all differ, that is a critical mislink/mis-generation. The developer's rationale openly concedes the substitution ('A literal multi-leg cross-sectional OI rotation ... cannot obtain OI for its extra legs ... I therefore implemented the edge as a single-name ... overlay'). - UNMEASURABLE trade count driven by an OI data-coverage limitation. The sandbox produced only 8 trades over 340 data_days, and the developer states this is 'capped at ~8 purely by the 56-day OI coverage.' Eight trades cannot distinguish edge from noise: Sharpe 0.668 with CI [-1.03, +2.18] straddles zero, return_kurtosis 54 and skew 3.27 indicate one or two trades dominate the result, and avg_loss ($2,488) actually exceeds avg_win ($1,878) despite the 75% win rate. Per prior QA learnings (a gate implying <~100 trades over the backtest span is unmeasurable), this must be rejected at Layer 4 rather than burning backtest/optimization iterations on a result that is structurally noise. It also contradicts the hypothesis's central claim of 'confirmed multi-year history / OI catalogued back to ~2021' — the actual on-disk OI is ~56 days, so the premise that this edge can be measured over a multi-year span does not hold with available data.

Iteration History

OiInflowWeeklyCrossSectionalRotationMajorsLongSpot

Iteration History

Verification failed (Layer 4 — QA review): - The cross-sectional OI-inflow rank — the strategy's entire reason for existing — is non-operative in the executed backtest. Only the PRIMARY (BTC) OI series is injected; `open_interest_by_instrument` is absent, so in __init__ every non-primary name falls back to BTC's OI series. `_oi_growth` then returns an IDENTICAL value for all 10 names, and `scored.sort(key=lambda x: (-g, symbol))` collapses to an ALPHABETICAL tiebreak. The executed strategy is 'when BTC OI is rising, hold the 3 alphabetically-first MA-passing majors' — an arbitrary basket, not OI-inflow rotation. The 'new signal input L24 requires' does nothing to differentiate names. - Decisively unmeasurable: 7 trades over 363 days, Sharpe CI [-1.61, +1.62] straddling zero. The config rationale itself admits OI coverage is only ~56 days, so the strategy is flat for ~85% of the window — the same data wall that killed the sibling OI/positioning families. - avg_trade_return_pct 0.0517% does not clear the ~0.20% spot round-trip / 0.25% floor; positive dollar result is a single fat tail.

Iteration History

OiRegimeTurnoverInflowWeeklyRotationMajorsLongSpot
Strategy report

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