MajorsIndexAbsoluteMomentumDirectionalLS
Hypotheses
Equal-Weight Majors-Index Absolute Momentum, Directional Long/Flat/Short the Whole Basket (Multi-Instrument BINANCE USD-M — Build a Synthetic Equal-Weight Index of 6 Liquid Majors, Trade the SIGN of the Index's Own Trend by Holding ALL Names Long or ALL Short, Vol-Targeted, Chandelier Backstop, 2-Parameter)
Hypotheses
A DIRECTIONAL, MULTI-INSTRUMENT ABSOLUTE (time-series) momentum strategy that trades the trend of a synthetic EQUAL-WEIGHT INDEX of 6 liquid BINANCE USD-M major perps (BTC, ETH, SOL, BNB, XRP, ADA). It is materially different from both the abandoned cross-sectional reversal and my pending cross-sectional momentum rotation: those are RELATIVE-VALUE, market-neutral books (long winners/short losers within the group); THIS is an ABSOLUTE directional bet on the aggregate — it holds ALL 6 names LONG when the index is in an uptrend, ALL 6 SHORT when in a downtrend, and flat otherwise. The core idea is denoising: single-instrument momentum (even on BTC) has died repeatedly on thin, best-of-N-noise edges (Sharpe straddling zero, ~127 trades), because a single name's price path is idiosyncratic; averaging 6 majors into one equal-weight index cancels much of that idiosyncratic noise, leaving a cleaner, higher-signal trend that is far more likely to clear the deflated-Sharpe/PBO gates while still being the MOMENTUM factor the factory demonstrably rewards (dual-TF BTC momentum and cross-sectional majors momentum are its two survivors). Diversification across 6 names also removes the single-name blow-up that risk-rejected the leveraged alt reversals. It is vol-targeted with a chandelier backstop so drawdown is capped and it never averages down. Low-frequency (trend flips are occasional) so the ~0.10% per-leg perp cost is immaterial versus multi-percent index trends. Deliberately 2-parameter (trend lookback, vol-target), the smallest sensible search surface, to attack the overfit deaths directly.
Hypotheses
I measured this instead of guessing, and the measurement rules out the reported cause. On the exact sandbox configuration (6 legs, 1-DAY, 2400-day window) an EMPTY no-op strategy took 160.0s and THIS strategy took 138.0s over 2401 bars with 2179 signal calls — the real strategy came in FASTER than the empty one, i.e. its own per-bar cost is inside run-to-run noise of zero. There is therefore no per-bar work to remove: the panel is trimmed to a bounded 180 rows, every window (index return, vol, ATR) is a fixed slice of that bounded panel, and there is no supplementary series, no sort and no history-scaling scan anywhere. The window is also ~2400 bars, not the 20000 the message templates, since 2400 days of 1-DAY bars is 2400 bars. What the measurement DOES reveal is a genuine leg-count fragility worth recording: the harness floor for a 6-leg config is ~160s before any strategy code runs, versus ~67s for a single-leg strategy measured the same way, because BacktestRunner issues one catalog.bars() call per bar type and NautilusTrader fsspec-globs the entire 35k-directory bar tree on each one. A six-leg book pays that six times and is left with only ~140s of slack under the 300s cap, so modest contention from concurrent sandbox runs — the glob is I/O-bound on a shared tree — is enough to push it over. That is not addressable from strategy code: the only lever a strategy controls is the number of legs, and this hypothesis is defined by its six-major universe, so cutting legs to buy wall-clock would change the very denoising being tested. I therefore did not churn already-zero-cost code, which would risk regressing logic that has cleared Layers 1 and 2 for no measurable gain. I also verified a suspected latent bug and cleared it: _maybe_enter passes None as the bar argument to _submit_entry_instrument, but the base never dereferences that argument, so it is harmless. The edits are this measurement note and a declared _param_bounds mirroring the constructor clamps. If it times out again the fix is infrastructure — cache the globbed file list across catalog.bars() calls within one run, or query each leg's own directory — and it will hit every multi-leg strategy in the factory.
Hypotheses
failed deflated Sharpe: DSR=0.0574, expected-max=1.41 over 225 trials — the selected Sharpe is indistinguishable from best-of-N noise, and this failure is joined by an UNWAIVABLE hard gate (PBO 0.6455 > 0.5, parameter selection more likely than not overfit). is_significant=false and the candidate does not survive programme-level FDR (keeps 3 of 228, candidate_p 0.9426). This is the classic overfit signature, not a fee/edge-below-cost death: per-trade economics are fine (avg_trade_return_pct 13.3%, PF 2.37) but the edge does not generalize — optimization made it WORSE (Sharpe fell to 0.793) and the long-lookback winner (trend_lb 126/vol_lb 121) did not hold, while walk-forward OOS 1.20 is carried entirely by a single window (per-window 0.17/0.00/3.43). Per the overfit-vs-dead-premise rule, high-search-overfit with a failed hard gate is ABANDON, not revise: the equal-weight-index denoising claim did not add robustness the deflation could strip, and the five nearest siblings (cross-sectional, residual, per-name TSMOM ensemble, long-horizon basket) were all abandoned overfit — reframing the same mechanism onto another universe would simply overfit again. Failure pattern: overfit / no-generalization (multi-instrument momentum basket, 0/N).
Implementation
Directional absolute-momentum strategy on a synthetic equal-weight index of six liquid Binance USD-M majors (BTC, ETH, SOL, BNB, XRP, ADA) on daily bars. Each aligned day the six legs' closes/highs/lows are appended as one synchronized panel row, and the index is built as a chained equal-weight return series (mean of the legs' simple returns compounded), which is what makes it a genuine equal-weight index rather than a price-level average dominated by the highest-priced leg. The signal is the index's trailing log return over trend_lb days; its SIGN sets the whole book — all six names long in an index uptrend, all six short in a downtrend, flat otherwise. Sizing is vol-targeted on the index (gross = min(target_vol / realized index vol, leverage)) split equally across the six legs, so exposure shrinks as index volatility rises. The book exits when the index momentum sign flips, or when a deliberately wide chandelier backstop is breached — tracked in relative units by re-basing the index to 1.0 at entry so the state is restart-safe. One entry, one exit, no rebalancing or averaging down while a position is open.
Verification Results
sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (2400 days of BTCUSDT.BINANCE-1-DAY-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
Absolute-directional time-series momentum (survivor factor), materially distinct from the L45 market-neutral basket graveyard
Backtest Review
Genuinely significant: Sharpe 1.09 with bootstrap CI [0.38, 1.81] (positive lower bound) and PSR 0.996 — unique in this batch
Backtest Review
Strong sample (780 trades / 6yr), only 2 tunable parameters, avg_trade_return_pct 5.0% (fee-immune), capacity ~$1.09B
Backtest Review
Regime-robust: positive Sharpe in all three vol terciles (0.87/1.20/1.32); PF 1.68, recovery_factor 10.5, DD 22%
Backtest Review
L36 leverage/compounding signature: avg_trade 5% and return_kurtosis 18.3, with the multi-year record concentrated in a few +30–40% days (vol-target hitting its leverage cap into gaps) — fragile if those days don't recur
Backtest Review
Recent regime weak: 2026 rolling Sharpe negative through most of the year, rescued by a +13% final bar
Backtest Review
end_unrealized_pct 41 (~19% of the headline is open-position MTM at backtest end) — realized track record is weaker than the headline
Backtest Review
benchmark_meaningful false / IR null (multi-instrument directional), so judge on absolute risk-adjusted metrics only
Analysis
Distinct from the L45 market-neutral basket graveyard: this is an absolute-directional time-series momentum book (the survivor factor family), and its per-trade economics clear fees trivially (avg_trade_return_pct 13.3%, PF 2.37, commission only 0.93% of gross).
Analysis
No sensitivity cliffs and holdout technically positive (Sharpe 0.769 on 36 trades), so it is not a fee-death or a broken mechanism.
Analysis
HARD gate failure that cannot be waived: PBO 0.6455 > 0.5 — the parameter selection is more likely than not overfit.
Analysis
Fails multiple-testing decisively: deflated_sharpe 0.0574 (<<0.95), is_significant=false, and it does NOT survive programme-level FDR (Benjamini-Hochberg keeps 3 of 228; candidate_p 0.9426). The selected Sharpe is indistinguishable from best-of-N noise over 225 trials (expected-max Sharpe 1.41).
Analysis
Optimization made it WORSE, the tell of curve-fitting: optimized Sharpe fell to 0.793 from the initial 0.79/1.09, and the long-lookback winner (trend_lb 126 / vol_lb 121 vs base 30) did not generalize.
Analysis
Walk-forward OOS avg 1.20 is a mirage carried entirely by one window (per-window OOS 0.17 / 0.00 / 3.43) — not consistent across windows.
Analysis
Soft floors also broadly missed: Sharpe 0.79 < 1.5, win_rate 0.429 < 0.45, max_drawdown 25.0% > 10%, OOS Sharpe 1.20 < 1.5.
Analysis
Family prior: the five most-similar prior hypotheses (cross-sectional, residual-momentum, per-name TSMOM ensemble, long-horizon basket) were ALL abandoned overfit — the denoising claim did not rescue robustness.
Analysis
Benjamini-Hochberg at q=0.10 over 228 programme candidates keeps 3. A candidate that does not survive here is not distinguishable from the programme's own noise, however good its individual statistics look.
Iteration History
Verification failed (Layer 3 — sandbox backtest): 'float' object is not callable
Bar type used: BTCUSDT.BINANCE-1-DAY-LAST-EXTERNAL, Bars processed: 0
Ensure your strategy produces trades with the given data and parameters.
Backtest and paper results are hypothetical. Trading involves risk of loss.