Skip to content

View translation

SectorBetaRegimeRotationXlkXluLS

Hypotheses

US Equity Beta-Regime Sector Rotation — Always-Engaged Long/Short Between an OFFENSIVE and DEFENSIVE Sector ETF, Flipped by the Broad-Market Trend Regime: Own High-Beta Tech (XLK) vs Low-Beta Utilities (XLU) in Risk-ON, Reverse to Defensive in Risk-OFF, SPY-Trend-Gated with Hysteresis (XLK/XLU/SPY.USEQ, Daily Bars, 3-Parameter)

Hypotheses

An ALWAYS-ENGAGED, DOLLAR-NEUTRAL LONG-SHORT rotation between two core SPDR sector ETFs — high-beta Technology (XLK.USEQ) and low-beta Utilities (XLU.USEQ) — whose SIGN is set by the broad-market trend regime (SPY.USEQ vs its own SMA, signal-only). This is a distinct family from the three equity strategies already in the pipeline (single-name z-score mean reversion, KO/PEP cointegration reversion, turn-of-month seasonality): the edge is the TIME-VARYING BETA PREMIUM / defensive-rotation effect — high-beta cyclicals lead in market uptrends and crash hardest in downturns, while low-beta defensives (utilities) outperform in stress. Rather than fade a stationary spread (KO/PEP) or rank a basket by relative momentum (the dead L68 rotation class), it holds a FIXED offensive-vs-defensive pair DIRECTIONALLY aligned to an EXTERNAL market-regime signal: risk-ON → long XLK / short XLU (capture cyclical outperformance); risk-OFF → long XLU / short XLK (capture defensive outperformance and high-beta's excess drawdown). Because it is always holding one side of the pair, it can never produce empty walk-forward OOS windows or an empty holdout (the failure that killed the deep-drawdown basket) — there is always a position, and regime flips (SPY crossing its SMA) generate a healthy trade sample (~8-15 flips/year × 25+ years). Both XLK and XLU trade since 1998, giving decades of daily history through multiple bull/bear regimes (2000, 2008, 2018, 2020, 2022) for genuinely robust walk-forward and holdout. Commission-free USEQ execution (~0.02-0.05% RT per leg) is the enabling condition: a hysteresis band around the SMA prevents whipsaw churn, so the strategy rotates only a handful of times/year, and each aligned hold typically captures several percent of offensive-vs-defensive spread — vastly clearing the ~0.16% two-leg round-trip. FEE ARITHMETIC: in a typical multi-month risk-on leg, XLK outperforms XLU by ~5-15% annualized; in a risk-off leg XLU outperforms XLK by ~5-20% over the drawdown; a single aligned hold captures ~2-6% of dollar-neutral spread vs ~0.16% round-trip rotation cost = 12-40x the cost floor, far above the 0.15% viability bar. Only 3 free parameters (regime SMA length, hysteresis band width, beta-hedge lookback) resist overfitting, and the mechanism is economically pre-specified (defensive rotation), not data-mined.

Hypotheses

Implements the hypothesis as specified: a fixed offensive-vs-defensive ETF pair held DIRECTIONALLY according to an external market-trend regime, not a spread fade and not a ranked basket rotation. Exactly 3 free parameters (regime_sma_len, hysteresis_band, hedge_lookback), all clamped in code and all declared in _param_bounds so the optimizer never tests values the code rewrites. The hysteresis is implemented structurally rather than as hidden state: should_enter requires |rel| > band while flat and should_exit requires the OPPOSITE band to be crossed, which is exactly a symmetric hysteresis loop and is a pure function of the current signal, so it is identical across restarts and replays. One honest deviation from always-engaged: the base template exits and enters on separate bars, so a regime flip leaves the book flat for a single session between the unwind and the reversed re-entry. Neutrality and drawdown control per past two-leg failures: the two legs are equal dollar notional scaled by a hedge ratio clamped near 1, gross exposure is capped near 70% of equity at leverage 1.0, the XLU leg is submitted only after the XLK leg is confirmed live, and any orphaned hedge leg found while the primary is flat is closed immediately, so the book can never carry a naked directional leg. Data alignment: all three ETFs are USEQ daily bars on one session calendar, so the base class alignment barrier defers the signal until the contemporaneous XLU and SPY bars have arrived, and the XLK/XLU pair uses SyncedBuffer so the hedge regression only ever sees timestamp-matched samples. Warmup is 30 bars with the SPY SMA computed over all closes available up to 200 (the hedge ratio defaults to 1.0, i.e. strictly dollar-neutral, until 60 aligned return samples exist), so the strategy is engaged early in the ~250-session Layer-3 sandbox window rather than idling through a 200-bar warmup. Venue is USEQ for both traded legs: commission-free execution (~0.02-0.05% per leg round trip) is what leaves a multi-percent aligned-hold spread capture intact. ITERATION 2 FIX (Layer 2, TypeError): the two timestamp lookups called the base class static helper through the instance (self._bar_ts(bar)); the Layer-2 proxy rebinds inherited staticmethods as bound methods, so self was passed as an extra positional argument and every synthetic scenario raised TypeError. Replaced with an identical module-level _bar_timestamp(bar) helper (ts_event with ts_init fallback, same semantics as the base). Nothing else changed - imports, signal logic, sizing, hedge-leg handling and config are untouched.

Hypotheses

Structurally low-Sharpe crisis-alpha profile with no realistic path to the promotion Sharpe floor. Despite a genuine per-trade edge (avg_trade_return_pct 3.66%, PF 2.04, not fee-limited) and a correctly-firing market-neutral mechanism, the strategy posts Sharpe 0.381 with a 95% CI lower bound of 0.0036 on the full 27-year in-sample — no statistically robust risk-adjusted edge before any optimization selection bias — plus a negative information ratio (-0.21) and only ~3.5%/yr against a 19.4% max DD. Returns are concentrated in a handful of crisis events (win_rate 30%, short_win_rate 10.8%, avg_win $13.5k vs avg_loss $2.9k), which is overfitting bait: the 3-param optimizer would curve-fit to specific historical crashes and fail deflated-Sharpe/OOS. Tuning cannot lift a 0.38 Sharpe to a promotable, robust level; not worth 2 hours of optimization. Failure pattern: viable per-trade edge but structurally low, event-concentrated risk-adjusted return below the promotion Sharpe floor.

Implementation

Always-engaged dollar-neutral long/short rotation between high-beta Technology (XLK.USEQ, primary leg) and low-beta Utilities (XLU.USEQ, hedge leg), with the SIGN set by an external broad-market regime signal: SPY.USEQ versus its own 200-session SMA (SPY is signal-only, never traded). calculate_signal returns the continuous SPY trend deviation rel = (SPY - SMA)/SMA every bar. rel > +1% is risk-ON (long XLK / short XLU); rel < -1% is risk-OFF (short XLK / long XLU). The band doubles as hysteresis: an aligned position is unwound only when rel crosses the OPPOSITE band, so oscillation inside the band never churns the book and rotations run to a handful per year. Both legs are sized to equal dollar notional (40% of equity each) scaled by a rolling 60-session OLS hedge ratio of XLK returns on XLU returns, clamped to [0.6, 1.6], in whole shares at leverage 1.0. There is no price stop: the exit condition is the regime flip itself.

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

Optionally gate signal emission until len(spy_closes)==regime_sma_len so every evaluated bar uses a full-length SMA.

Verification Results

The regime SMA is a running mean over up-to regime_sma_len closes (spy_sum/len), so until 200 SPY bars accumulate the '200-day SMA' is a shorter, noisier average, making the early regime signal more flip-prone. Fidelity gap vs the stated 200-day filter, not a correctness bug; warms to full depth over history.

Verification Results

Document the true worst-case gross (~104%) or normalize legs to an explicit gross cap.

Verification Results

Gross exposure can exceed 100% of equity: XLK 40% + XLU 40%×hedge(≤1.6)=~64% → ~104% gross, whereas the rationale claims '~70%'. Within USEQ 2x Reg-T margin and not a blow-up path (leverage 1.0, beta-neutral), but the stated cap is inaccurate.

Backtest Review

Genuine per-trade edge, not fee-limited: avg_trade_return_pct 3.66% is ~70x the USEQ 0.05% floor; PF 2.04.

Backtest Review

Clean, economically pre-specified market-neutral mechanism (offensive/defensive rotation) with only 3 free parameters; benchmark_meaningful=false correctly judges it on absolute metrics.

Backtest Review

Mechanism fires as intended — big gains cluster in risk-off crises (2002, 2018, 2020, 2022) via short-XLK/long-XLU, matching the defensive-rotation thesis.

Backtest Review

27 years of daily data across multiple regimes; adequate structural setup and correct dollar-neutral hedging.

Backtest Review

Sharpe 0.381 with sharpe_ci_low 0.0036 — risk-adjusted edge is statistically indistinguishable from zero on the FULL in-sample, before any optimization selection bias.

Backtest Review

information_ratio -0.21; ~3.5%/yr return against 19.4% max drawdown at 40% avg exposure — thin absolute reward.

Backtest Review

Returns are concentrated in a few crisis events (win_rate 30%, short_win_rate 10.8%, avg_win $13.5k vs avg_loss $2.9k) — a lottery payoff that invites the optimizer to curve-fit to specific historical crashes and fail OOS/deflated-Sharpe.

Backtest Review

Structurally low-Sharpe crisis-alpha profile: parameter tuning cannot realistically lift a 0.38 Sharpe (CI floor ~0) to the promotion Sharpe floor.

Outcome Summary

SectorBetaRegimeRotationXlkXluLS proposed an always-engaged, dollar-neutral rotation owning high-beta XLK against low-beta XLU, flipping the pair's sign on the SPY trend regime to harvest the defensive-rotation premium across decades of sector-ETF history. The design was ambitious — three instruments on one session calendar, a rolling OLS hedge ratio, staged leg submission and orphan-hedge cleanup — but it never got past the coding stage. After 3 iterations the developer agent timed out three times ('coding_stuck_3_timeouts') and the run was abandoned before any code was verified or backtested. No backtest, optimization, or analyst review ever ran, so the strategy's thesis was never tested against data.

Outcome Summary

A multi-instrument dollar-neutral pair with external regime gating and rolling hedge-ratio logic is coding-intensive enough to stall the developer agent; keeping the implementation simpler or scoping the multi-leg mechanics down could prevent repeated coding timeouts.

Outcome Summary

It was abandoned during the coding stage with reason 'coding_stuck_3_timeouts' after 3 iterations; the developer agent could not produce a working strategy within the timeout limit, so verification, backtesting, and all later stages were never reached.

Outcome Summary

An always-engaged, dollar-neutral long/short rotation between high-beta Technology (XLK) and low-beta Utilities (XLU) whose sign is set by the SPY broad-market trend regime (SPY vs its own SMA, with a hysteresis band), aiming to capture the defensive-rotation / time-varying beta premium using three free parameters (regime SMA length, hysteresis band width, hedge lookback).

Outcome Summary

No performance data exists — the strategy never produced a backtest report, so there are no return, Sharpe, or trade metrics to cite.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['hedge_max', 'hedge_min', 'per_leg_pct', 'warmup_bars', 'min_notional', '_param_bounds', 'hedge_lookback', 'regime_sma_len', 'hysteresis_band'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000) - steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000) - flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000) - volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000) - zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000) - price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)

Iteration History

Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit. 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).
Strategy report

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