BtcBasisMomentumContinuationLS
Hypotheses
BTC Basis-Momentum Directional, Long-Short (Single-Instrument BTCUSDT.BINANCE Perp — NEW Information Source: Trade the Perp in the Direction of the RISING/FALLING Mark-vs-Index PREMIUM (Basis Rate-of-Change = Leveraged-Demand Build), Continuation Not Fade, ATR-Trailing, 3-Parameter)
Hypotheses
A LONG-SHORT directional strategy on the BTCUSDT.BINANCE USD-M perpetual driven by a genuinely NEW, well-covered, NON-OPTIONS INFORMATION SOURCE — the perp BASIS (mark-vs-index premium, premium_index) — used as basis-MOMENTUM per the meta-learner's L38 mandate. It is deliberately CONTINUATION-aligned, not a fade: this session has shown every BTC contrarian/fade (liquidation, OI-divergence, DVOL-reversal, false-breakout, deleveraging, positioning-divergence) has no edge, while the momentum/trend direction is the only survivor — so a new-source signal traded WITH the flow is the untested, better-aligned angle. The signal: the RATE OF CHANGE of the perp premium is a direct, leading read of leveraged demand — a rising basis means aggressive leveraged BUYING is building (bullish pressure accumulating), a falling/negative basis means leveraged demand is draining or shorts are pressing (bearish). Trading the perp in the direction of the basis-momentum captures that leveraged-flow continuation. It is distinct from every prior idea: not price-only (basis is the primary signal), not a fade, not the dead OI/momentum CONFIRM (basis ROC is the primary directional driver, price only filters), not options (diversifying my four pending options ideas), and premium_index is well-covered on Binance (avoiding the taker-ratio/L-S coverage ceilings and DVOL history limits). It trades the liquid BTC perp (dev-safe, signal=execution instrument), single instrument, long-short (fills the 13.5% bucket), 4H cadence for a measurable ~100-200 trade sample, with an ATR trail to ride continuation. 3 parameters.
Hypotheses
ITERATION 3 -- fixes the Layer-4 QA rejection that the sandbox result was computed on SYNTHETIC premium data, so the hypothesis was never actually tested. I reproduced the cause in the repo: the sandbox loader src/agents/pipeline_processor.py::_collect_supplementary_data does NOT load premium_index (its return dict has funding_rates, liquidations, open_interest, the L/S ratios, taker_ratio, metrics, hl_funding_rates, deribit_dvol, deribit_funding -- no premium_index), while the REAL backtest loader src/backtesting/supp_collector.py:606 DOES ('premium_index': _load_parquet('premiumIndexKlines')). Because the strategy code contains the string 'premium_index', the sandbox's best-effort synthetic injector supplied _gen_synthetic_premium_index (src/verification/synthetic_scenarios.py:339 -- 'sampled every ~60 bars'), and that fabricated series is what iteration 2 standardized and traded. I verified the real data on disk: data/supplementary/premiumIndexKlines/BTCUSDT holds 3,460,081 1-minute rows spanning 2019-12-24 to 2026-06-26 (486,246 rows in the last year), and data/supplementary/fundingRate/BTCUSDT/all.parquet holds 7,029 real 8h funding prints spanning 2020-01-01 to 2026-05-31 -- and funding IS surfaced by the sandbox loader.
THE CHANGE (smallest fix that makes the run honest, everything else untouched):
1. FEED-AUTHENTICITY GATE in _ensure_series. A basis series is by construction high-frequency (1-minute premiumIndexKlines; 8h funding settlement). Each candidate feed is now measured and a series whose MEDIAN SAMPLE SPACING exceeds max_spacing_hours (LOCKED 9h) is REJECTED as not a basis feed. The synthetic premium is spaced ~10 days, so it is rejected outright instead of being standardized into a believable-looking fabrication; the real 1-minute premium (0.017h) and the real 8h funding series both pass. On rejection the strategy falls through to funding_rates for the SAME QUANTITY -- funding is the realized time-average of this premium over the settlement interval, i.e. a resolution downgrade of the identical signal, not a different edge and not a price-only proxy. The accepted source and its measured spacing are logged at build time and repeated in the on_stop summary line, so 'which series did this actually trade on' is a fact in the log rather than something QA has to infer. Net effect: the Layer-3 sandbox now runs on the REAL 8h funding basis series (7,029 prints, ~90 samples per 30-day z-window) and the full backtest runs on the REAL 1-minute premium_index -- neither can silently run on synthetic data again.
2. REVERTED THE COUNT-AWARE Z-WINDOW, which QA correctly identified as masking untestability. The standardization window in _basis_z is again a plain trailing z_days requiring min_samples points inside it; if it is not full the signal is unmeasurable and no position is taken. Sparsity is now handled at the source by the gate above rather than by stretching the window (the old code could standardize a ~10-day-spaced series over ~600 days). Both surviving feeds fill the 30-day window comfortably (1-min premium ~43k points; 8h funding ~90 vs min_samples 60), so this removal cannot reintroduce the earlier zero-trade failure.
3. TRADE COUNT (QA's second point: 7 trades is unmeasurable). The 7-trade sample was an artifact of the ~600-day-stretched z-score on a ~36-point synthetic series, which left the score almost frozen. On the real feed the ROC is measured every 8h (sandbox) / every minute (backtest) against a genuine 30-day distribution, so the +/-1 sigma crossings occur at the modeled ~30-60 entries per year rather than a handful.
4. PERFORMANCE for the real 3.5M-row series: a fast parse path for the plain timestamp+close kline shape, numpy sort/dedupe instead of a 3.5M-entry Python dict, and decimation to at most one sample per hour (1-minute resolution is far finer than a 12h smoothing window needs) before the vectorized smoothing/ROC/prefix-sum precompute. Per-bar cost is unchanged: two searchsorted calls and O(1) arithmetic.
REGRESSION SAFETY: no imports changed (stdlib math/collections/decimal + numpy + nautilus_trader only), the class/method structure, the continuous signal, the cross-entry, the three exits, and the gap-aware sizing are byte-identical to the version that passed Layers 1-3. One caveat for the Research Lead: the durable fix is a one-line addition of 'premium_index': _load_parquet('premiumIndexKlines') to _collect_supplementary_data so the sandbox mirrors supp_collector -- I did not touch pipeline code, so the sandbox will test the 8h funding resolution of the basis while the full backtest tests the 1-minute premium.
Hypotheses
Catastrophic, decisive net loser that breaches the hard-abandon drawdown line. max_drawdown 58.1% (CI to 83.6%, past the >50% L19 rule), profit_factor 0.719 (< 1.0), total_return -53.3%, avg_trade_return_pct -0.314% (negative), expectancy -$105/trade across a decisive 527 trades, Sharpe -0.299, alpha -0.082, information_ratio -0.850, and losses in 6 of 7 years (only 2025 positive) with rolling Sharpe deeply negative for most of the history. The feed-authenticity gate is a genuine fix — the signal now trades a real basis series — and the honest verdict is that trading WITH basis-momentum has no edge on BTC: rising basis does not lead price continuation net of costs, and the perp gives it back. The hypothesis's bet ('fades failed, so the continuation polarity must work') is falsified. This is not a tuning problem — there is no parameter region to optimize toward when the edge is negative across every regime and the drawdown is 58%; optimizing best-of--225 trials would only overfit the single good year (2025). Abandon per the >50% DD hard-abandon rule and the PF < 1.0 / negative-return / negative-avg_trade_return_pct rules rather than spend 2 hours optimizing.
Implementation
Long/short BTCUSDT.BINANCE USD-M perpetual traded WITH the momentum of its own mark-vs-index premium (perp basis). Every 4H bar it computes a continuous decision variable: the premium is smoothed over 12h, differenced over roc_hours to measure leveraged-demand BUILD, and standardized against a plain trailing 30-day distribution of that ROC. Price is only a filter -- when the 1-day price move disagrees in sign with the basis ROC the score is damped 0.25x and clipped strictly below the exit level, so it can never open a position and never becomes the signal. Entry is a fresh CROSS of +/- entry_thresh sigma (LONG on rising basis, SHORT on draining basis). Exits: an ATR trailing stop detected intrabar and booked at that bar's close, a basis-momentum reversal with 0.5x hysteresis, and a 7-day max hold measured from the position's own ts_opened. Sizing is gap-aware and risk-first (2% of equity over a 3-ATR adverse excursion), capped at 0.5x equity notional, leverage 1.0. Three tunable parameters: roc_hours, entry_thresh, trail_atr_mult.
Verification Results
Verification failed (Layer 4 — QA review):
- THE SANDBOX RESULT IS ON SYNTHETIC PREMIUM DATA, NOT THE REAL premium_index -- so the hypothesis is not actually tested. The developer's own iteration-2 diagnosis (reproduced offline) is that the sandbox supplementary loader `_collect_supplementary_data` does NOT surface premium_index, so the run falls back to a SYNTHETIC premium sampled once per ~60 bars (~10 days). The count-aware z-window fix then standardizes that sparse synthetic series over a count-extended window of ~600 days (60 min_samples x ~10-day spacing), which is NOT the intended 30-day standardization of the real ~1-minute basis. So the 7-trade metrics (total_return +3.66%, PF 1.90, avg_trade 1.28%, capacity $211M) are computed on a FABRICATED signal and carry no information about the real basis-momentum edge; funding_events_available=114 and the developer's disclosure confirm the premium is synthetic/sparse. The hypothesis is untestable in the sandbox as currently wired.
- UNMEASURABLE REGARDLESS -- 7 trades over 363 days (2 long / 5 short), Sharpe 0.531 with a CI [-1.34, 1.78] straddling zero, return_skew 4.59 / kurtosis 56.2 (one $5,939 win is >150% of the ~$3.7k net). Even setting aside the synthetic-data problem, a 7-trade sample cannot distinguish edge from luck. Separately, note that the count-aware z-window -- a legitimate robustness feature for a genuinely sparse REAL feed -- here has the effect of MASKING the untestability: it turns the honest 0-trade 'no real premium data' state into a misleading 7-trade 'it traded' result on synthetic data.
Verification Results
Marginal sandbox edge; avg_trade_return_pct +0.115% below the 0.15% fee floor
Verification Results
Sandbox tests 8h funding, full backtest tests 1-min premium — different feed resolutions; full backtest is the definitive test
Verification Results
Feed-authenticity gate margin is tight (8h vs 9h) but fails safe (no-trade), never toward synthetic data
Backtest Review
The feed-authenticity gate is a real fix — the result is computed on a genuine basis series, so the negative finding is trustworthy
Backtest Review
Decisive sample (527 trades) and correct long-short balance (271 long / 256 short)
Backtest Review
max_drawdown 58.1% (CI to 83.6%) — past the >50% hard-abandon line (L19)
Backtest Review
profit_factor 0.719 (< 1.0, net loser), total_return -53.3%, avg_trade_return_pct -0.314% (negative), expectancy -$105/trade
Backtest Review
Negative in 6 of 7 years (2020 -21.7%, 2022 -24.6%, 2026 -10.5%); only 2025 positive; rolling Sharpe deeply negative for most of the history
Backtest Review
Sharpe -0.299, alpha -0.082, information_ratio -0.850 — no edge; the continuation polarity on basis-momentum is falsified
Outcome Summary
BtcBasisMomentumContinuationLS bet that since every BTC fade this session had failed, trading WITH the flow revealed by perp basis-momentum — the rate of change of the mark-vs-index premium as a leading gauge of leveraged demand — would be the better-aligned, untested angle. A key iteration-3 fix added a feed-authenticity gate that rejected a synthetic premium the sandbox had been substituting, falling back to the real 8h funding series as a resolution downgrade, so the backtest finally described the genuine basis signal. The verdict was unambiguous and brutal: over 527 trades the strategy lost -53.3% with a profit factor of 0.719, a negative per-trade edge, and a 58.1% max drawdown that breached the hard-abandon line, negative in 6 of 7 years. The reviewer abandoned it at backtest-review, concluding the continuation polarity on basis-momentum is falsified on real data — not a tuning problem but an absent edge — with the feed-authenticity fix being precisely what made that negative finding trustworthy.
Outcome Summary
The premise that 'every fade failed, so the continuation polarity must work' is not self-validating — a rising basis does not lead price continuation net of costs, and a feed-authenticity gate that refuses synthetic data is what turns a nice-looking backtest into an honest, decisive falsification rather than a fabricated result.
Outcome Summary
It was abandoned at the pre-optimization BACKTEST_REVIEW gate on multiple hard rules: max drawdown 58.1% breached the >50% hard-abandon line, profit factor was below 1.0 with negative per-trade return, and — crucially — a feed-authenticity gate ensured the signal ran on a real basis series, so the negative verdict was trustworthy: trading WITH basis-momentum has no edge on BTC and the perp gives back the move.
Outcome Summary
Trade the BTCUSDT.BINANCE perp long/short in the direction of perp basis-momentum — the rate of change of the mark-vs-index premium as a leading read of building/draining leveraged demand — a continuation-aligned bet using a genuinely new, well-covered information source, with price only as a filter.
Outcome Summary
Over a decisive 527-trade sample (271 long / 256 short) it was a catastrophic net loser: profit factor 0.719, total return -53.3%, avg per-trade return -0.314%, expectancy -$105/trade, win rate 36.8%, Sharpe -0.299, information ratio -0.850, and max drawdown 58.1% (CI to 83.6%), with losses in 6 of 7 years (only 2025 positive).
Iteration History
Verification failed (Layer 3 — sandbox backtest): No trades produced
Bar type used: BTCUSDT.BINANCE-4-HOUR-LAST-EXTERNAL, Bars processed: 2180
Diagnostics: should_enter() returned a side 0 times over 2155 evaluated bars -> your ENTRY CONDITION never triggered. Loosen the entry logic / thresholds.
Ensure your strategy produces trades with the given data and parameters.
Backtest and paper results are hypothetical. Trading involves risk of loss.