Skip to content

View translation

CrossSectionalTwoDayReversalMajorsLS

Hypotheses

Cross-Sectional 2-Day Reversal, Majors-Only Confirmed-Data Universe (Long Recent Losers / Short Recent Winners, Dollar-Neutral, Binance USD-M, Pure OHLCV, Daily Rebalance)

Hypotheses

A MARKET-NEUTRAL (dollar-neutral) CROSS-SECTIONAL SHORT-TERM REVERSAL strategy across a tightly-curated universe of ~10 ROCK-SOLID, 2020-listed Binance USD-M major perpetuals, every one confirmed to have full-history data. This finally TESTS the mechanism the analyst has recommended repeatedly (cross-sectional reversal as the regime-appropriate replacement for the dead momentum factor) by removing its only failure cause. CRITICAL: every prior cross-sectional basket this session died PRE-BACKTEST on the data layer (uncollected ARB/AAVE/NEAR/ATOM bars abort the whole run) — NEVER on mechanism; the mechanism has never actually reached an evaluation. The fix is to restrict the universe to symbols with verified full history and to drop-and-continue any that is missing. EVERY design choice respects this session's kills: (1) PURE OHLCV — NO supplementary data, immune to the FIVE consecutive data-insufficiency abandons (open_interest x3, account-ratio, liquidations) that proved every Binance-futures-derived stream unusable as a primary signal. (2) MAJORS-ONLY CONFIRMED-DATA universe — no thin alts, so the basket cannot abort on a missing symbol (the only thing that killed the prior reversal baskets). (3) REVERSAL, not momentum — cross-sectional momentum is dead on majors (correlations tightened post-2024, compressing the long-top/short-bottom spread to noise); the SAME tightening STRENGTHENS reversion, so majors-only is the thesis, not a compromise. (4) DENSE firing — every basket member is ranked and rebalanced daily, so the strategy fires continuously and every walk-forward OOS window is densely populated (avoiding the event-sparsity that killed drawdown-accumulation and conjunction-gated MR). (5) Differentiated from the existing 7-day reversal by a SHORT 2-day signal horizon (short-term reversal is an empirically distinct factor from weekly reversal) and a simple equal-weight construction (no vol-norm complexity). (6) Per-leg price PnL across DIFFERENT assets is creditable and non-cancelling — NOT a same-asset basis, NOT a cross-asset ratio (which is non-stationary and closed). NOT cross-venue/HL, NOT COIN-M, NOT a funding/OI/supplementary signal. Intentionally minimal: 3 tunables (reversal_lookback, rebalance_days, basket_fraction).

Hypotheses

Iteration 7 addresses the reported gate (metrics unreliable: Sharpe 0.03 vs total_return -62.03%). A ~zero arithmetic daily mean compounding to -62% over the window implies a daily sigma near 3% -- impossible for a genuinely dollar-neutral 50%-gross majors spread, so the realised book was not neutral. Iteration 6 already fixed the sizing base (MTM equity) and the inter-period drift (re-mark every bar); the one neutrality leak left was the per-leg adverse stop (leg_stop_pct): it flattened a single leg mid-period and dropped it from the target set until the next rank refresh, leaving an unhedged directional stub of a quarter of gross held for days, and it always fired on the leg that had just moved hardest, so the surviving book was biased in exactly the direction that had just hurt. That is the missing variance. It is also structurally anti-reversal -- it exits a mean-reversion leg at the point of maximum expected bounce -- so it is removed entirely, leaving the rank refresh as the only exit (which is what the hypothesis specifies). Supporting changes pin realised exposure to intended: basket_fraction 0.50 -> 0.30 and rebalance_band 0.35 -> 0.15, so a leg never sits above 1.15x target and gross is capped near 35% of equity; book sigma lands at ~0.5-0.8%/day where sigma^2/2 drag is negligible and arithmetic and geometric returns agree in sign, making the headline metrics coherent. Both clamps are now declared in _param_bounds so the optimizer cannot re-inflate gross out of the coherent regime. rebalance_days 4 -> 2 aligns the holding period with the 2-day signal horizon (the reversal decays well inside 4 days; stale ranks were paying spread for unsupported exposure). Everything that already passed Layers 1-3 is untouched: imports, class structure, the continuous dispersion signal, calendar-anchored scheduling, synchronized per-name close buffers, single-delta-order exposure control, and the inert should_enter/should_exit/position_size.

Hypotheses

backtest_no_trades: metrics unreliable: Incoherent: Sharpe 0.13 disagrees in sign with total_return -41.20% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.

Implementation

Dollar-neutral cross-sectional 2-day reversal across six full-history Binance USD-M majors (BTC, ETH, SOL, BNB, XRP, DOGE) on daily bars. Every rebalance period (calendar-anchored, days-since-epoch // rebalance_days) all six names are ranked by trailing 2-day return; the book goes long the bottom 2 (recent losers) and short the top 2 (recent winners), equal-weight per leg, and is re-marked to that exact target signed notional every aligned bar with a single delta order per name. Sizing is off mark-to-market equity (balance + open unrealized PnL) at basket_fraction = 30% gross with leverage 1.0, so gross exposure is bounded at ~35% of equity by construction and the book is always exactly 2 long / 2 short. Pure OHLCV, no supplementary data, no stops -- the periodic rank refresh is the only exit.

Verification Results

Either fold rebalance_band into a fixed constant (like TOP_K) to match the stated 3-tunable minimal design, or update the hypothesis to acknowledge it as a 4th tunable.

Verification Results

Hypothesis states 3 tunables (reversal_lookback, rebalance_days, basket_fraction) but the code exposes a 4th, rebalance_band, plus min_notional/size_round. rebalance_band is a legitimate exposure-control knob (clamped and declared in _param_bounds) so this is structural, not a mismatch, but the optimizer surface is wider than the hypothesis advertises.

Verification Results

Return reversal_lookback + 1 for clarity; functionally the all_ready guard already prevents premature signals.

Verification Results

min_bars_required() returns 2 but _trailing_return needs reversal_lookback+1 (=3) closes to produce a value. This is handled gracefully (calculate_signal returns _last_disp / all_ready gate skips until buffers fill), so no incorrect trade fires, but the warm-up gate understates the true requirement.

Verification Results

Fee/turnover viability is the real risk here. The sandbox shows avg_trade_return_pct 0.024% (well under the 0.15% USD-M floor), 2916 trades, profit_factor 0.92, commission 3.78% of gross, total_return -41%. This is the exact high-turnover cross-sectional-reversal signature that has died repeatedly this session (per prior abandons the gross spread does not clear round-trip cost). The mechanism daily-rebalances a 6-name majors basket into a ~30% gross dollar-neutral book, so the per-trade edge is the tiny cross-sectional 2-day reversal spread against a full round-trip on every leg each period. On full history the analyst should verify the per-trade gross move actually exceeds ~0.10% round-trip before optimizing; if avg_trade_return_pct stays sub-fee it is a structural edge-below-cost death, not a parameterization issue (only 3-4 tunables, none of which raise per-trade edge). Also note the sandbox metrics are flagged incoherent (metrics_reliable=false: Sharpe from mtm_equity_curve disagrees in sign with equity-curve total_return) — this is a reporting/basis artifact the developer has been iterating on, but it means the headline Sharpe cannot be trusted; judge the real backtest on the equity curve.

Analysis

Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.03 disagrees in sign with total_return -62.03% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.

Iteration History

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).

Iteration History

Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.13 disagrees in sign with total_return -41.20% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.
Strategy report

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