Skip to content

View translation

BtcIntradaySessionSeasonalityLS

Hypotheses

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)

Hypotheses

A LONG-SHORT, SINGLE-INSTRUMENT BTC probe that continues the deliberate exit from the trend family — which the meta-learner has now closed (L62: single-instrument trend survival 0.003; every non-momentum trend construction this session landed base Sharpe ≈0.4–0.7 and died, and the confluence 'edge-booster' thesis was directly falsified at 0.634). It explores the intraday counterpart to the pending turn-of-month sleeve: TIME-OF-DAY SESSION SEASONALITY — the tendency for crypto returns to cluster in specific UTC windows driven by recurring session flows (US equity-hours risk-on, Asia-hours behavior, and the fixed 00:00/08:00/16:00 UTC funding-settlement times that concentrate positioning activity). The signal is purely the clock position of the bar, ORTHOGONAL to price path/trend/mean-reversion, so it is a genuine diversifier to the portfolio's one promoted (momentum) strategy rather than a correlated trend clone. It runs on the only artifact-free, non-fragile substrate this session found — single-instrument Binance USD-M pure-OHLCV (COIN-M times out at coding, HL is history-capped, Deribit option data spans only ~34 days, multi-instrument produces non-physical returns). To resist overfit, the winning window is chosen ADAPTIVELY from a trailing sample (not a hardcoded hour), and turnover is deliberately capped at ONE round trip per day to control fee drag. It fills the under-represented short-horizon bucket (8.9%). Honest framing: this is an EXPLORATION probe of an untested family whose edge may be small/decayed — but it is the correct move after trend, reversion, pairs, funding, options, cross-sectional and factor-composite families are all exhausted. It avoids the graveyards: NOT trend (L62), NOT reversion/pairs/funding/factor (dead), NOT a liquidation/quarterly feed (L61). Exactly 3 tunable parameters: the session-block width (hours), the trailing lookback for selecting the window, and the ATR stop multiple.

Hypotheses

Iteration 6 addresses the backtest gate's finding directly: judged on the equity curve the strategy returned -10.55% on a curve so flat that the mtm-derived Sharpe (+0.03) disagreed in sign with it. The implementation was working (block attribution, entry/exit alignment and one-round-trip-per-day cadence all verified), so the defect is in WHICH windows get selected, not in the plumbing. Iteration 5's cost-net LCB fixed the ranking but a 60-day mean plus a noise haircut still rates a single strong episode inside the lookback as 'defensible', which is exactly how a calendar strategy ends up trading non-recurring drifts and paying fees for it. The smallest change that targets that is a within-sample persistence test: split the trailing sample chronologically and require both halves to drift the same direction as the full sample AND the recent half alone to clear the cost hurdle before a window is eligible. Recurrence is the entire claim of a session-seasonality edge, so a window that fails it should not be traded, and on days where no window qualifies the strategy simply stands aside. No new tunable is introduced (the split is structural, underscore-free because it is not a parameter at all), Layer 1/2 structure, imports and the continuous t-stat signal are untouched, and trade cadence stays capped at one round trip per day. Honest note: this is the fifth refinement of the selection statistic on the same mechanism; if the stability filter still leaves the equity curve non-positive, I would read the intraday session-seasonality premise on BTC 1H as falsified rather than under-tuned, since it would mean no UTC window carries a persistent drift larger than the ~0.10% round trip.

Hypotheses

Negative expectancy / edge absent on a reliable 654-trade / 6.7-year sample: profit_factor 0.9834 (<1), expectancy -$9.26/trade, Sharpe 0.023, Sortino 0.015, recovery_factor -0.17, information_ratio -0.91, losing in 5 of 7 calendar years. The mechanism is orthogonal and correctly implemented (654 signaled = 654 submitted, one round trip/day, adaptive window), so this is a fair test of BTC-1H intraday session seasonality — and the premise is falsified: regime attribution shows losses concentrated in the calm (-15.5%) and normal (-4.2%) vol terciles, exactly where a recurring time-of-day drift should be cleanest, only flat in stressed. The equal-weighted avg_trade_return_pct 0.2207% is contradicted by the negative size-weighted USD expectancy (losers carry larger notional), so this is edge-absent rather than fee-fragile. This is iteration 6 and the developer's own note concedes a non-positive curve should be read as the premise falsified, not under-tuned; the 3 tunables (block width, lookback, ATR stop) cannot invert a PF-0.98 drift-absent signal. QA's edge concern is confirmed on full history. Not worth 2 hours of optimization.

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.

Verification Results

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.

Verification Results

No change required if the base dispatches to the override; otherwise rename. Non-blocking.

Verification Results

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.

Verification Results

Sandbox is decidedly negative (total_return -14.5%, Sharpe -0.86, PF 0.69, avg_trade_return_pct -0.020%, win_rate 0.46 over 110 trades) and the mechanism itself is fee-fragile: the selection cost hurdle is fee_round_trip*edge_mult = 0.0010*0.5 = 0.05%, i.e. a window need only clear HALF the ~0.10% Binance USD-M round trip on its recent half before it is eligible (the LCB does add a sqrt(2 ln k)*stderr noise haircut, which raises the effective bar, but the structural floor is still sub-round-trip). Regime attribution shows losses in exactly the calm/normal terciles where a recurring seasonal drift should be cleanest (calm -8.4%, normal -10.0%) and only a flat stressed tercile. The developer's own honest note concedes that if the iteration-6 stability filter still leaves the curve non-positive they would read the BTC-1H intraday session-seasonality premise as falsified rather than under-tuned. This is an exploration probe of an untested family whose edge may be small/decayed — the full backtest + optimizer should decide, but the analyst should be prepared to abandon on edge grounds if the persistent-drift signal remains absent on full history.

Backtest Review

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

Backtest Review

Large, reliable sample (654 trades / 6.7 years, 58,560 bars, metrics_reliable=true) — a fair test of the premise.

Backtest Review

profit_factor 0.9834 (<1) with negative expectancy -$9.26/trade and avg_trade_pnl_usd -9.26 — a losing strategy net of costs.

Backtest Review

Sharpe 0.023, Sortino 0.015 ~ zero; recovery_factor -0.17, calmar -0.026, information_ratio -0.91 (underperforms buy&hold).

Backtest Review

Loses in 5 of 7 calendar years (2022 -11.3%, 2025 -14.1%, 2026 -4.5%).

Backtest Review

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.

Backtest Review

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.

Backtest Review

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)

Iteration History

Verification failed (Layer 4 — QA review): - Decisively no edge -- the adaptively-selected session window is anti-predictive out-of-sample (checklist #7, L6/L7). Sandbox: total_return -9.44%, Sharpe -1.61 (CI [-3.06, 0.03]), avg_trade_return_pct -0.584%, profit_factor 0.10 (gross losses ~10x gross wins), win_rate 0.24, over 21 trades (avg_loss 657 vs avg_win 214). The failure is exactly the mechanism's core risk: picking the highest-|t| time-of-day block from a trailing sample and trading its sign does not persist out-of-sample -- in-sample-selected intraday seasonality is noise on BTC, and the derived multiple-testing bar (t_crit = sqrt(2*ln n_blocks) ~= 1.89) did not prevent it (the selection went mostly short in the recent year and lost 10:1). No full-history dry-run was provided to rebut the negative sandbox, so my bar (positive sandbox OR demonstrated positive full history) is met by neither. Critically, this is the intraday counterpart of the turn-of-month sleeve the SAME developer already falsified on BTC in the prior review (no boundary concentration, mid-month peak, recent regime negative across the whole parameter space) -- the calendar-seasonality family is now showing the same no-edge result at both the month and day scales.

Iteration History

Verification failed (Layer 4 — QA review): - The full-history evidence I required disqualifies the mechanism, and the developer correctly recommends abandonment. Fee-viability is falsified: at the shipped default (W=12, L=120) the developer's full-history dry-run is 745 trades, avg -0.010%/trade, PF 0.99 -- breakeven-to-negative gross of slippage. The selected window's gross (pre-fee) drift across all 36 configs is +0.038% to +0.127%/trade, at or below the 0.10% round-trip taker cost and far below the 0.15% analyst floor; the developer states even the best of 36 configurations does not clear the floor on full history. The intraday session drift is real but an order of magnitude too small to pay for taker execution. The positive Layer-3 sandbox (+4.41%, avg_trade_return_pct +0.361%, PF 1.37) is a non-representative recent-year slice -- all-short (28/0 trades), kurtosis 28.5 -- directly contradicted by the breakeven full history. My bar requires a positive sandbox OR a demonstrated positive full history; the full history the developer measured is breakeven-negative, so the sandbox positive does not survive. The failure is not tunable: flipping direction is also negative full-history (not a sign error), and a persistence filter changes nothing. And this is the THIRD calendar-anomaly probe dead on BTC -- monthly (turn-of-month) falsified by a full-parameter sweep, day-of-week a one-outlier artifact, this intraday breakeven.
Strategy report

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