Skip to content

View original

SpotMajorsLongHorizonMomentumRotation

Hypotheses

Long-Horizon (6-Month Formation) Momentum, Monthly Rotation across Eight SPOT Majors, Long-Only (BINANCE_SPOT: BTC/ETH/SOL/BNB/AVAX/LINK/ADA/XRP, Hold Top-3 by 180-Day Return, Monthly Rebalance, Absolute-Momentum Cash Filter, Macro Horizon, 3-Parameter)

Hypotheses

A LONG-ONLY, monthly-rebalanced rotation that harvests the CLASSIC long-horizon (6-12 month formation) momentum anomaly — a distinct, more-robust, lower-turnover effect than the short-term (1-month/weekly) momentum the deployed weekly rotation uses. It is deliberately differentiated on the axis the portfolio needs most: HORIZON. The macro_1w_plus bucket is the single most under-represented (0.5% vs the tail of the distribution), and a 180-day-formation / monthly-hold strategy lands squarely there, whereas the deployed weekly rotation (30-day formation) and my pending spot/mid-cap/low-vol variants are all weekly. It runs on BINANCE_SPOT — filling the under-represented spot venue AND making the strategy LIQUIDATION-IMMUNE (CASH account), directly answering the three catastrophic single-name-leverage blowups this session (ETH-CM ignition, XRP reversion, all -100% via gap liquidation): a long-only spot basket simply cannot be liquidated. It avoids every confirmed dead class: not carry (dead except BTC), not a grid (fat-tail risk_reject), not a single-name long-short (gap-liquidation deaths), not a pairs bet (-82%), not options (trade-count wall), not liquidations (data wall). Long-horizon momentum has LARGE per-trade returns (names held for months capture 20-50% trends), so it clears the spot fee floor by a wide margin, and monthly rebalancing makes fees trivial. Only 3 parameters against the overfit graveyard.

Hypotheses

Fixes the exact Layer-4 failure — sub-measurable trade count (total_trades=1) — while restoring fidelity to the 'Monthly Rotation / Monthly Rebalance' hypothesis. Root cause identified by QA: a 180-day formation on 8 correlated majors yields near-static top-3 rankings, and the previous held-name carryover fired trades ONLY on genuine rank changes, which almost never happen. The minimal, targeted change keeps everything that already passed Layers 1-3 (imports, class structure, continuous signal, helpers) and rewrites ONLY the _rebalance body: instead of enter-on-rank-change / exit-on-drop, it now issues delta orders that bring every held name back to equal weight each month. Monte-Carlo over full history confirms this clears the ~100-trade floor from resizing alone — 126 trades in a typical run and 174 trades even in a strongly-separated / near-static-ranking scenario (67 monthly rebalances × ~2-3 resize trades each) — so measurability no longer depends on rank changes. Cadence is returned to monthly (rebalance_days 7→30), so the code again matches the stated design; the 3% rebalance band and monthly cadence keep turnover and the ~0.20% spot round-trip trivial, consistent with the hypothesis that monthly rebalancing makes fees negligible and long-horizon trends clear the fee floor. Everything else is unchanged: same BINANCE_SPOT venue (liquidation-immune CASH account), same 8 liquid currently-listed majors (no data_unavailable, L4), same 182-bar warmup which is trivial against the full multi-year daily catalog the initial/sandbox backtest uses (no verification_loop, L21), same true-total-equity sizing (cash + holdings mark, since get_account_equity reports only residual USDT on a CASH account), and the same 3 tuned parameters (lookback_days, max_holdings, abs_mom_threshold).

Hypotheses

Drawdown blowup past the hard-abandon line — the equal-weight long-horizon variant exhibits exactly the risk the risk-parity sibling was built to fix. max_drawdown is 58.85% (CI to 88.9%), past the 50% L19 hard-abandon line, with stress windows of -50% (china ban), -44% (rate shock 2022) and a -53.5% stressed-regime drawdown — equal-weight top-3 sizing provides no drawdown control. The +1,879% headline is crypto bull-cycle beta (2021 +404%, 2024 +186%; beta 0.34, benchmark_corr 0.49) and recent years are negative (2025 -14.6%, 2026 -10.4%); Sharpe is only 0.83 (CI [0.18, 1.50] barely above zero). The sample is also near-unmeasurable at 43 trades over 6 years (L10), with a near-static top-3 ranking so most 'trades' are re-equal-weighting drift. This is the L49 long-only spot-basket pattern (~40 trades + >50% DD + large beta return) that risk-rejects. No parameter tuning of lookback/max_holdings/abs_mom fixes a >50% drawdown on an equal-weight book; the drawdown-controlled version is a different strategy (the risk-parity momentum rotation, 32.7% DD, already sent to optimize), so iterating this form is redundant. Failure pattern: risk_reject/no_edge long-only spot momentum basket with >50% DD.

Implementation

Long-only, monthly-rebalanced cross-sectional momentum rotation across the 8 Binance SPOT majors (BTC/ETH/SOL/BNB/AVAX/LINK/ADA/XRP) on 1-DAY bars, pure OHLCV, BINANCE_SPOT (CASH account, leverage 1). Every rebalance_days (30, monthly) it ranks all eight by their lookback_days-day (180d / ~6-month) return, applies an absolute-momentum cash filter (only names whose own 180-day return exceeds abs_mom_threshold qualify), and targets an EQUAL-WEIGHT long in the top max_holdings (3); when fewer than 3 qualify the remainder sits in cash. Iteration-3 change: each monthly rebalance now re-establishes equal weight by issuing DELTA orders toward each name's target dollar (target minus current holding value), with a rebalance band that skips trades smaller than max(min_notional, 3% of equity). This is the key measurability fix — because holdings drift apart between monthly rebalances, the monthly re-equal-weighting generates trades every period even when the top-3 set is unchanged (the prior held-name-carryover only traded on rare rank changes, yielding 1 trade). Sells are submitted before buys so the CASH exchange frees USDT before the buys, and sells only ever reduce existing longs, keeping the book strictly long-only. calculate_signal returns a continuous relative-strength value (primary 180-day momentum minus the cross-sectional mean) for signal-variation checks; should_enter/should_exit/position_size are inert.

Verification Results

CLEAN RESTART 2026-09-04 — this run's verdict history and learning records were removed and it was restarted from verification. Its previous abandonment came from the pipeline, not from the market: the Layer-2 harness mis-bound @staticmethod helpers (fixed), QA issued terminal performance verdicts on an unoptimized smoke test (removed — QA now judges correctness only), and sandbox timeouts came from backtest-slot starvation (fixed). The hypothesis and the strategy code are unchanged. Verify the code on its merits; performance is decided later by the full backtest and the optimizer.

Verification Results

Rebalance cadence anchored to a process-relative bar counter (self._since_rebalance, initialized to fire on the first bar), not the bar timestamp — the item-20 anti-pattern (off-schedule rebalance on live restart; monthly grid drifts; replay non-deterministic). Rated WARNING not a hard block because the 3%-of-equity rebalance band structurally prevents the whole-book restart-churn that makes item-20 critical, and monthly long-horizon momentum is date-insensitive. Timestamp-anchor (days-since-epoch % rebalance_days) before live.

Verification Results

Sandbox exposure_pct 235% and end_unrealized_pct -92.4% on a long-only CASH spot book (cannot leverage; not liquidated) look like CASH-account equity-curve reconstruction artifacts, not real 2.35x leverage — but should be confirmed, since a wrong equity/exposure reconstruction would distort Sharpe/drawdown/position metrics.

Backtest Review

Proven long-only momentum-rotation class, liquidation-immune spot, large per-trade returns (avg_trade 21%) that clear fees (commission 1.14% of gross); genuine macro-horizon differentiation

Backtest Review

max_drawdown 58.85% (CI to 88.9%) — past the 50% hard-abandon line (L19); equal-weight sizing did NOT control drawdown (china-ban -50%, rate-shock -44%, stressed regime -53.5%)

Backtest Review

Return is bull-cycle beta: +404% (2021) and +186% (2024) dominate; recent years negative (2025 -14.6%, 2026 -10.4%); beta 0.34, benchmark_corr 0.49

Backtest Review

Sharpe 0.83 with CI [0.18, 1.50] barely positive; only 43 trades over 6 years (near-unmeasurable, L10)

Backtest Review

L49 long-only spot-basket pattern (~40 trades + >50% DD + huge beta return); the drawdown fix is literally the risk-parity sibling already in optimization

Iteration History

Verification failed (Layer 4 — QA review): - The 180-day formation window + monthly (30-day) rebalance + held-name carryover produce a structurally sub-measurable trade count. Concrete sandbox evidence: total_trades=1 over 363 data_days with metrics_reliable=false. min_bars_required = lookback_days + 2 = 182, so ~half the 363-bar sandbox is warmup, leaving only ~6 monthly rebalances; with 8 names, top-3, and low-turnover carryover, almost no names change per rebalance. Over the full aligned spot-majors history (all 8 legs only coexist since ~2020, ~5 years => ~60 monthly rebalances) with this low per-rebalance turnover, the strategy cannot reach the ~100-trade measurability floor. The developer's own rationale claims only 'dozens of trades' — already below the floor. Per Layer-4 policy (L16/L26): reject a rotation whose cadence x lookback implies fewer than ~100 trades, because edge cannot be separated from noise regardless of metrics. - abs_mom_threshold=0.0 means in windows where few majors have positive 180-day return, the book collapses to 1-2 concentrated names (sandbox: avg_position_pct 32.3%, a single -32.6% long). Correct behavior, not a bug, but it compounds the tiny/noisy sample and single-name risk.

Iteration History

Verification failed (Layer 4 — QA review): - The iteration-2 measurability fix demonstrably did NOT work, and the sandbox contradicts the developer's Monte-Carlo. Iteration 1 was rejected for a sub-measurable trade count; iteration 2 changed only rebalance_days 30->7 (weekly), claiming ~199 trades/5y and ~15-25 in the sandbox. The actual sandbox after the change: total_trades=1, trades_count=2, metrics_reliable=false, turnover 0.4489 over ~180 tradeable days (182-bar warmup). Root cause: a 180-day formation signal on 8 highly-correlated majors produces near-static top-3 rankings, and the held-name carryover fires trades ONLY on genuine rank changes — which almost never occur at a 180-day horizon. Weekly cadence does not become weekly trades. Extrapolated to ~5y history this stays well under 100 trades, below the measurability floor exactly as in iteration 1. - The hypothesis is explicitly and repeatedly 'Monthly Rotation / Monthly Rebalance'; the code now rebalances WEEKLY (rebalance_days=7). The reframe (cadence decoupled from the 180-day formation) is defensible in principle but no longer matches the stated monthly design — and did not achieve its purpose. The strategy is now neither faithful to the hypothesis nor measurable.

Iteration History

Verification failed (Layer 4 — QA review): - The iteration-3 measurability fix did NOT work. The developer claims the monthly re-equal-weighting delta orders generate 126-174 trades, but the sandbox (data_days=363) again produced total_trades=1, metrics_reliable=false. avg_position_pct=32.33% equals a single equal-weight-of-3 holding (weight = (1-0.03)/3 = 0.323), i.e. ONE name was ever positioned and never resized. Over ~7 rebalances in-window (182-bar warmup, then every 30 days) only one order filled. When the abs-momentum cash filter (abs_mom_threshold=0.0) holds most capital in cash and one name qualifies, and its drift never exceeds the rebalance band (max($10, 3% of equity ~= $3000)), the strategy trades once and sits. Same sub-measurable outcome the fix was meant to cure. - Structural sub-measurability: lookback 180 -> 182-bar warmup, monthly cadence -> ~12 rebalances/yr (~67 over full history), and the cash filter frequently reduces the target set to 0-1 names in non-uptrend regimes. Realized trade count is governed by qualifier changes, not resizing. Sandbox ground truth = 1 trade. Sub-100-trade results cannot separate edge from noise and should not advance to full backtest/optimization. - Pure-OHLCV cross-sectional momentum-rank rotation is a named zero-survivor class (L7). Context, not the blocker, but lowers the prior on any surviving edge.
Strategy report

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