Skip to content

View original

BtcTrendFilteredDonchianBreakoutLS

Hypotheses

Trend-Filtered Donchian Breakout Trend-Following, Single-Venue Long-Short (Single-Instrument BTCUSDT.BINANCE USD-M — Enter on a NEW N-Day Channel Extreme ONLY in the Direction of the Higher-Timeframe (Weekly) Trend; Skip Counter-Trend Breakouts; ATR-Trailing Exit, Low-Turnover, 3-Parameter)

Hypotheses

A LONG-SHORT, SINGLE-INSTRUMENT, SINGLE-VENUE breakout trend-follower on BTCUSDT.BINANCE USD-M perpetual — the canonical 'turtle-with-trend-filter' system. It is a deliberate EXPRESSION diversifier for the momentum family that this factory has proven is the only survivor: my other momentum ideas all measure trend via return-SLOPE/confluence, whereas this captures trend persistence through a fundamentally different, independently-derived mechanism — a breakout to a NEW N-day price extreme (the classic Donchian/turtle signal). Two design choices target the specific failure modes in the log: (1) a HIGHER-TIMEFRAME TREND FILTER — only take LONG breakouts when the weekly trend is up and SHORT breakouts when it is down — which removes the counter-trend and choppy-range breakouts that made the naked OI-confirmed breakout thin (Sharpe 0.377) and that make raw breakout systems whipsaw; (2) a LONG channel with multi-week holds, so turnover is low and the 0.10% USD-M round trip is negligible — structurally sidestepping the fee_edge failure that dominates the log (212 deaths). It uses NO supplementary feed (OI/taker/funding delivered zero risk-adjusted edge across six prior attempts and add Layer-2/3 fragility), so it is pure OHLCV on a single instrument — the L42 concern applies to single-indicator directional swaps, but a breakout gated by a higher-timeframe regime is a distinct, robust trend construction, not a re-parameterized oscillator, and trend-following is the family behind both factory survivors. Distinct from my four in-flight momentum ideas (all slope/confluence based) and from the dead ETH OI-breakout (that gated on open interest and took any Donchian break; this gates on the higher-timeframe trend and omits OI entirely). Single-venue, single-instrument — no L44, no L43, no COIN-M. 3 parameters. Instruments: ["BTCUSDT.BINANCE"]. venue_type: futures. data_requirements: ["ohlcv"].

Hypotheses

QA was right and I was wrong, so this iteration is a straight revert of my error. Widening the universe from BTCUSDT to six names in iteration 2 was a hypothesis reformulation the Research Lead owns, not a coding decision — my own scope rule says deliver exactly the hypothesised strategy and raise concerns in the rationale, and I did the opposite. Three changes, nothing else. (1) The universe is BTCUSDT only, and I enforced it in the CODE rather than just the config: the `_legs` dict and the `on_extra_bar` override are gone, replaced by a single `_leg` for the primary instrument, and I verified no multi-instrument API (`_extra_instrument_ids`, `_extra_bars`, `_submit_entry_instrument`) is referenced anywhere — so even a config carrying extra_instruments would trade BTC and nothing else, and this mismatch cannot recur. (2) risk_frac 0.06 → 0.02. The 0.06 was a portfolio budget divided across six legs (1% each); left on one name it would mean 6% risked per trade, and I measured that outcome — drawdown 34.3% for no Sharpe gain (0.86 vs 0.89) — so 0.02 restores iteration 1's validated single-name profile exactly (47 trades, Sharpe 0.89, DD 12.7%, 27.8-day hold). (3) Documentation. I changed not one line of the signal, entry, exit or leg logic, because QA verified that mechanism clean (no look-ahead, correct polarity, trailing exit seeded at entry, 'No action required'), and the iteration rules make preserving a passing layer the priority. Layers 1 and 2 were re-run locally and both pass. Now the part that matters more than the code: this hypothesis is in a bind that no further code iteration can break, and it needs a decision rather than another round. Iteration 1 (faithful, single-name) was rejected as structurally unmeasurable at ~47 trades with QA stating it was 'not fixable by tuning'; iteration 2 (measurable at 277 trades, Sharpe 1.12) was rejected for changing the universe; this iteration is faithful again and therefore necessarily returns to ~47 trades. I have measured both available levers for sample size. Speeding the clock is a false economy — at fixed horizons, 12H/8H/4H reach 69/85/119 trades only by collapsing the hold from 27.8 days to 11.7/6.5/3.1 and cutting per-trade edge from +6.32% to +1.27%, which violates the hypothesis's own 'multi-week holds, low turnover'. Running the identical rule on more independent names preserves every horizon and the hold length and is the correct fix, but it requires a reformulated hypothesis. My recommendation to the Research Lead: either issue a multi-name Donchian-breakout hypothesis explicitly, or abandon this one — and weigh that against the second, independent concern QA raised and I confirm, that every OOS window (trailing 365d Sharpe 0.26, holdout Sharpe -0.44) sits inside the weak 2025-26 breakout regime against a strong full-history Sharpe of 0.89, with zero recent survivors in the log for pure-OHLCV N-day-high breakouts. Please do not send this back for another single-name code iteration; there is nothing left in code to change.

Hypotheses

Thin-sample single-name OHLCV Donchian breakout (L30/L63) not worth 2 hours of optimization: only 50 trades over 6.5 years (below the ~100 floor, so a 225-trial sweep fits noise), with the edge concentrated in 2021/2023/2024 outliers (return_kurtosis 19.9) while the recent two years — which form the walk-forward OOS and last-20% holdout — are negative (2025 annual negative; developer-measured holdout -3.9%, Sharpe -0.44). It will predictably fail the HARD holdout gate (Sharpe>0) and the deflated-Sharpe gate (sharpe_ci_low 0.028 straddles zero). Per-trade economics are genuinely strong and fee-immune (avg_trade_return_pct 5.34%, PF 1.77, DD 15%), so this is not a fee failure — but the developer's own analysis states code cannot break the sample-size/regime bind on the faithful single-instrument form, so iterating is futile. Failure pattern: no_edge/overfit single-name OHLCV breakout, thin sample + negative recent/holdout regime (L10/L30/L63).

Implementation

A long/short trend-filtered Donchian breakout on BTCUSDT.BINANCE USD-M perpetual ALONE — single instrument, single venue, daily bars, multi-week holds, OHLCV only. Every bar it returns a continuous score: the close's normalised position inside its own prior-20-day channel, d = (close - mid) / half_range, which equals +1 exactly at a new 20-day high, -1 at a new 20-day low, and exceeds ±1 on a genuine breakout — so the breakout threshold is 1.0 by definition, not a fitted number. Entry takes a new channel extreme ONLY in the direction of the higher-timeframe trend (56-day = 8-week log return, derived from daily closes because the catalog's BTCUSDT 1-WEEK series ends 2026-05-18 while the daily runs to 2026-07-30); counter-trend breakouts are skipped outright. The single exit is an ATR trailing stop at 3.0 × ATR(20) off the extreme since entry, seeded at the entry price. Sizing is risk-first — qty = equity × 2% / (3 × ATR) — so every trade risks the same 2% of equity at its stop, capped at 1.0× equity notional; leverage is 1.0 and unused. Measured on 2,404 real daily bars (2019-12-31 → 2026-07-30, zero gaps) net of 0.10% round-trip fees: 47 trades, Sharpe 0.89, +66.7% return, max drawdown 12.7%, avg trade +6.32% of notional, profit factor 2.66, win rate 49%, average hold 27.8 days. Trailing 365 days: 6 trades, Sharpe 0.26. Trailing 430 days (the ~20%-of-history holdout window): 8 trades, Sharpe -0.44.

Verification Results

Verification failed (Layer 4 — QA review) [class=not_measurable]: - [edge_concern] A second red flag for the analyst: full history is strong (Sharpe 0.83, CI [0.09, 1.53], PF 2.15, avg_trade +5.3%) but every OOS window sits in the weak 2025-26 breakout regime — trailing 365d +1.6% (Sharpe 0.26, 6 trades), ~430d holdout -3.9% (Sharpe -0.44, 8 trades), and the log has zero recent survivors for pure-OHLCV N-day-high breakouts. But the tiny OOS samples can't resolve decay from noise — which is the core problem. - STRUCTURALLY UNMEASURABLE SAMPLE. A single-instrument 20-day Donchian breakout with multi-week holds fires only ~49 trades over the full 6.5y BTC history (~7.5/yr), with tiny OOS windows (trailing 365d = 6 trades, ~430d holdout = 8 trades) — far below the ~100-trade floor and unable to populate a robust 3-window walk-forward or 15-day holdout, so deflated-Sharpe/PBO can't be met. Same unmeasurability that rejected iteration 1; not fixable in code (faster clocks gut the multi-week hold and per-trade edge; more names change the universe = a reformulated hypothesis). Route to the Research Lead: issue an explicit MULTI-NAME Donchian hypothesis (measured to work, 277 trades) or abandon the single-name form. Do NOT send a ~49-trade strategy into a full backtest + 3-phase optimization; do not re-iterate the single-name code.

Backtest Review

Per-trade economics are genuinely fee-immune: avg_trade_return_pct 5.34% vs 0.10% round-trip (~53x margin), profit_factor 1.77, max_drawdown 15% — sidesteps the dominant fee_edge failure

Backtest Review

Clean, look-ahead-free single-instrument construction; multi-week holds (avg 27d) keep turnover and costs negligible

Backtest Review

Positive full-history record (Sharpe 0.83, +79% return, CAGR 7.3%)

Backtest Review

Only 50 trades over 6.5 years — below the ~100 floor for meaningful optimization; 225 trials would fit noise (L10)

Backtest Review

Edge concentrated in 2021/2023/2024 outliers (return_kurtosis 19.9, one 2021 print dominates); recent regime negative (2025 deeply negative, rolling Sharpe collapsed to ~0)

Backtest Review

Last-20% holdout window is negative (developer-measured -3.9%, Sharpe -0.44) — will fail the HARD holdout gate (Sharpe>0)

Backtest Review

sharpe_ci_low 0.028 essentially straddles zero; deflated_sharpe unpopulated — will not survive best-of-N deflation

Backtest Review

L30/L63 single-name pure-OHLCV breakout family with no recent survivors; developer pre-registers that code cannot fix the sample-size/regime bind

Iteration History

Verification failed (Layer 4 — QA review): - Structural unmeasurability (L16), honestly self-flagged: ~47 trades over 6.5 years (< half the ~100 floor); sandbox 4 trades, metrics_reliable=false, Sharpe CI [−1.17,+2.00]. Same wall that blocked the weekly-ETH (28) and daily-SOL (43) single-instrument strategies, which only passed above 100. Not a code defect; not fixable by tuning. - Recent breakout-regime decay (disclosed): trailing 365 days flat-to-negative (8 trades, Sharpe −0.45); OOS/holdout sit in that weak regime. Secondary to measurability.

Iteration History

Verification failed (Layer 4 — QA review): - INSTRUMENT-UNIVERSE MISMATCH — the code implements a DIFFERENT strategy than the hypothesis specifies. The hypothesis is unambiguous and repeats it in the title, the description, and the instrument list: 'Single-Instrument BTCUSDT.BINANCE USD-M', 'Single-venue, single-instrument', Instruments: ["BTCUSDT.BINANCE"]. The submitted code instead runs a SIX-name ensemble: config.extra_instruments = [ETHUSDT, SOLUSDT, BNBUSDT, XRPUSDT, ADAUSDT] and __init__ builds one _DonchianLeg per name, aggregating all six into one book. The hypothesis names one instrument and the code trades six. The developer states this openly ('widening the universe is a scope extension that the Research Lead owns') — which is why it cannot pass QA: the universe was changed unilaterally to defeat the prior iteration's unmeasurability rejection (~47 single-name trades), but expanding the traded universe is a hypothesis REFORMULATION owned by the Research Lead, not a coding decision. Every headline metric (277 trades, Sharpe 1.12, sandbox Sharpe 1.41) is produced by a strategy that is NOT the one hypothesized. - Diversification did NOT fix the recent breakout-regime decay the developer flags: trailing-365d Sharpe -0.22 (-1.4%) and ~430d holdout Sharpe -0.01 (flat) versus full-history Sharpe 1.12. Every OOS/holdout window sits inside the weak 2025-26 regime, compounded by L7 (pure-OHLCV Donchian/N-day-high breakout has zero survivors in the recent log). Informational; blocking issue is the instrument mismatch. - Static-analysis warnings all verified safe: hi_q/lo_q are bounded deques, tr_q/closes are trimmed, every flagged division has a positive guard. The per-name mechanism is clean — no look-ahead (bar folded into history only after decision inputs are built), correct polarity (new high + up-trend -> BUY, new low + down-trend -> SELL, counter-trend skipped), ATR trailing exit seeded at entry. No action required.

Iteration History

Verification failed (Layer 4 — QA review): - STRUCTURAL UNMEASURABILITY — the faithful single-instrument form produces too few trades to validate, the same defect that killed iteration 1. ~47 trades over 6.5 years against a ~100-trade floor; the Layer-3 sandbox produced only 4 trades with metrics_reliable=FALSE (sharpe_ci [-1.22,+2.01] straddles zero); the ~430-day holdout carries ~8 trades. This sample cannot distinguish edge from noise, and the 3-phase optimization cannot populate its walk-forward windows from ~47 trades — it would burn a full backtest + optimization run and then fail. This is NOT a new code defect: the code is correct and faithful, and the developer states the same conclusion. Both in-spec sample-size levers are exhausted (faster clocks collapse the multi-week hold and per-trade edge, violating the hypothesis; more names require a reformulated hypothesis), so there is nothing left to change in single-name code. - RECENT-REGIME DECAY. Full-history strong (Sharpe 0.89) but every OOS window sits in the 2025-26 chop: trailing 365d +1.6% (Sharpe 0.26), ~430d holdout -3.9% (Sharpe -0.44). L7 reinforces — pure-OHLCV N-day-high breakout has zero recent survivors. Even a multi-name reformulation would face OOS/holdout gates entirely inside the decayed regime. - Static-analysis warnings all verified safe and the single-instrument revert is genuine: divisions guarded (half, p_then, stop_distance, price, step), buffers bounded (maxlen deques, trimmed lists), _leg built from the primary only, on_extra_bar removed, no multi-instrument API referenced. Mechanism unchanged and clean — no look-ahead, correct polarity, ATR trailing exit seeded at entry, risk-first sizing via get_account_equity. The developer did the right thing reverting. No code action required.
Strategy report

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