Strategies
BTC Intraday Session Seasonality — Trade the ONE Recurring Time-of-Day Return Window per Day (Adaptively Selected, Not Hardcoded), a Non-Trend / Non-Reversion Calendar Edge on the Under-Represented Short Horizon (BINANCE USD-M, 1H Bars, Long-Short, 3-Parameter)
Outcome: Abandoned
BtcIntradaySessionSeasonalityLS
Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.03 disagrees in sign with total_return -10.55% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on…
Hypothesis
Implementation
Long/short BTC USD-M perp on 1H bars that trades exactly ONE adaptively selected UTC session window per day. The UTC day is split into calendar blocks of block_hours; each completed block's realised return feeds that block's trailing daily sample (lookback_days). Per block the strategy keeps mean, stderr, t-stat, a multiple-testing-corrected cost-net lower confidence bound (|mean| - sqrt(2 ln k)*stderr - fee hurdle), and a split-sample stability flag requiring both halves of the trailing sample to drift the same way and the recent half alone to clear the trading cost. Once per calendar day it selects the eligible (stable, net-positive-LCB) window with the largest defensible post-cost drift and trades its sign: market entry at the window's first bar close, exit at the window's end, with an ATR stop and a hard calendar cap. Sizing is ATR-risk-capped at 1% of equity per trade, capped at 1x equity notional. Exactly three tunables (block_hours, lookback_days, atr_stop_mult), clamps mirrored in _param_bounds.
Verification Results
Consider setting _edge_mult to >= 1.0 so the recurrence hurdle clears the full round trip, or raise _fee_round_trip to the realized round-trip cost. Advisory only — this is an edge/profitability concern, not a correctness defect.
The cost hurdle for window eligibility is fee_round_trip * edge_mult = 0.0010 * 0.5 = 0.05% of notional, which is below the full ~0.10% round-trip taker cost on Binance USD-M (and below the 0.15% viability floor). A window whose recent-half drift is only ~0.05% can be selected and traded, meaning some traded windows are structurally fee-negative before the estimation-noise haircut is considered. The multiple-testing LCB haircut mitigates this but does not raise the base floor above the round trip.
No change required if the base dispatches to the override; otherwise rename. Non-blocking.
min_bars_required(self) overrides a framework method (Layer-1 base_shadow warning). Benign here since the override returns a valid warm-up (24), but confirm the base template honors the override rather than its own implementation.
Backtest Review
- Sharpe
- 0.02
- Total return
- 4.51%
- Max drawdown
- 29.54%
- Trades
- 654
- Win rate
- 48.6%
- Profit factor
- 0.98
Mechanism is genuinely orthogonal to trend/reversion (clock-position calendar signal) and correctly implemented: 654 entries signaled = 654 submitted, one round trip per day as designed, adaptive window selection (not hardcoded).
Large, reliable sample (654 trades / 6.7 years, 58,560 bars, metrics_reliable=true) — a fair test of the premise.
profit_factor 0.9834 (<1) with negative expectancy -$9.26/trade and avg_trade_pnl_usd -9.26 — a losing strategy net of costs.
Sharpe 0.023, Sortino 0.015 ~ zero; recovery_factor -0.17, calmar -0.026, information_ratio -0.91 (underperforms buy&hold).
Loses in 5 of 7 calendar years (2022 -11.3%, 2025 -14.1%, 2026 -4.5%).
Regime attribution falsifies the premise: losses concentrated in the calm (-15.5%) and normal (-4.2%) terciles where a recurring seasonal drift should be cleanest; only flat in stressed. QA's edge concern borne out.
avg_trade_return_pct 0.2207% (equal-weighted % notional) is contradicted by the negative size-weighted USD expectancy — losers carry larger notional; this is edge-absent, not merely fee-fragile.
This is iteration 6; the developer's own note concedes a non-positive curve means the premise is falsified, not under-tuned.
Analysis
Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.03 disagrees in sign with total_return -10.55% — 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
Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['_risk_frac', '_atr_period', '_gate_scale', 'block_hours', '_param_bounds', 'atr_stop_mult', 'lookback_days', '_min_stop_frac', '_max_gross_frac', '_min_sample_frac'] 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: 1735690980000) - steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690980000) - flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690980000) - volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690980000) - zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690980000) - price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690980000)
Backtest and paper results are hypothetical. Trading involves risk of loss.