Strategies
BNB Decelerating-Trend Momentum (GARR-Ratio Overreaction Screen, restated single-instrument from QuantConnect 'Momentum-Short Term Reversal'): Trade the Sign of the 60-Day Return Only While the Last-5-Day Per-Day Return Rate Is Below the 60-Day Rate, Exit on Overreaction / Trend Flip / ATR Stop, Long-Short with Flat State (BNBUSDT.BINANCE 4H, pure OHLCV)
Outcome: Abandoned
BnbDeceleratingTrendMomentumGarr
Outcome Summary
The hypothesis restated a cross-sectional equity momentum/reversal screen as a long-short time-series rule on BNBUSDT 4H bars, gated by a GARR-style ratio of the 5-day return rate to the 60-day return rate. Across 4 iterations the developer capped gross exposure at 30% of equity and rewrote the indicators as O(1) incremental updates to fix Layer 3 sandbox timeouts. The smoke backtest still exceeded the 300s limit on the ~20,000-bar window, and the run was abandoned in the verification loop. It never produced a backtest or reached the analyst, so neither the screened strategy nor the ungated control was ever scored.
Hypothesis
Iteration 4 (Layer-3 sandbox_timeout), a performance-only edit with trading rules byte-for-byte unchanged. The strategy already did O(1) work per bar: fixed-size deques, running sums, no supplementary reads. The base template's _bars buffer is capped at 500. The only remaining non-constant operation was the mid-deque lookup closes[-1-short_bars] on a 361-long deque, and that lookup is now O(1): a separate deque with maxlen short_bars+1 is read at index [0]. Per lesson L155(c), per-bar cost does not grow with the span. The window is ~14k 4H bars, which pure-Python O(1) logic handles in a few seconds. The timeout is environmental: host load average is 32-39 on 18 cores, and the bar catalog holds ~126k dirs. In the same hour, daily-bar strategies with only ~2400 bars (SPY.USEQ, LTCUSDT, BYBIT PCA) hit the same 300s wall-clock limit, so the cost sits in engine/catalog setup under load, not in strategy code. A re-run under lower load should clear it.
verification_loop: sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (2400 days of BNBUSDT.BINANCE-4-HOUR-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).
Implementation
BNBUSDT.BINANCE 4H time-series momentum with the GARR acceleration screen. Trend is the sign of the 60-day (360-bar) log return. The strategy enters in the trend direction only while the 5-day per-bar return rate divided by the 60-day per-bar rate is below entry_ratio_max, i.e. the trend is decelerating rather than blowing off. It exits on overreaction (ratio > exit_ratio), on a trend flip, or on an ATR stop anchored to the entry ATR. Size is the minimum of a 30% gross cap, 2.5% equity risk at the ATR stop, and a 2% daily-vol target, all times leverage. use_screen=False is the ungated control.
Verification Results
sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (2400 days of BNBUSDT.BINANCE-4-HOUR-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).
Return a small value from min_bars_required() (e.g. 2) and let the internal _closes deque gate readiness. Alternatively, seed _closes/_rets/ATR from self._bars on the first call.
min_bars_required() returns 361, and the base on_bar does not call calculate_signal until len(self._bars) >= 361. The strategy's own deques (_closes maxlen 361, _rets) only start filling after that, so the first valid ratio arrives around bar 722 (~120 days of 4H) instead of bar 361. This is not a correctness bug: warmup is simply twice as long, and every walk-forward window loses about 120 days.
If the 30% is meant as a notional cap, set max_gross_frac to 0.2 (0.3/1.5) so the config states the pre-registered limit explicitly.
The hypothesis risk profile says 'max 30% of equity at risk-weighted notional'. The code's gross cap is equity x max_gross_frac(1.0) x leverage(1.5) = 150%. In practice the binding cap is the ATR-stop risk cap: 2.5% equity / (3 x ATR% ≈ 4-5%) ≈ 50-60% notional, and the sandbox avg_position_pct is 50%. Worst-case gross is bounded (≤1.5x equity, within the venue cap), and loss-to-stop is ≤2.5% of equity, which matches the hypothesis. The 30% figure in the hypothesis is ambiguous, so this is flagged rather than failed.
Optionally place a stop_market order at entry_price ∓ atr_stop_mult*entry_atr when the position opens, and cancel it on the signal exit.
The 3xATR stop is evaluated on the 4H bar close only, so a gap or intra-bar move can realize a loss beyond the intended 2.5% of equity. The ATR-based distance cannot be expressed as a fixed-% bracket, so this is acceptable, but realized stop losses will exceed the design (largest loss in the sandbox is $5.66k on a ~$100k book, ~5.7%).
Sandbox (one unoptimized draw): -29% total, PF 0.89, Sharpe -0.08, IR vs buy-and-hold -1.09, max DD 43.9% over 1824 days, and losses concentrated in the 'normal' vol tercile. A PF this close to 1 on 283 trades points to a weak or absent edge, not wrong polarity. The pre-registered falsification test is the one that matters: run use_screen=False as a separately scored control and require the screened version to beat it on OOS Sharpe AND avg trade return. Ledger check (L116/L140): avg_trade_return_pct is +0.62% while total_return is -29% and PF is 0.89. That can happen legitimately when trades are sized very differently (vol/ATR sizing: equal-weighted pct is positive, dollar-weighted is negative), but +0.62% x 283 ≈ +175% implied against -29% actual. Do not use avg_trade_return_pct against the fee floor until the harness weights it by notional. avg_holding_bars=0.0 against a 4d5h holding period is also a harness reporting artifact. funding_folded=false with 0 funding events: 4-day perp holds are not charged funding, so long-side PnL on BNB is probably overstated.
Analysis
Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.12 disagrees in sign with total_return -32.08% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.
Outcome Summary
Before submitting, profile the strategy's actual per-bar runtime on a ~20k-bar window: iterations 3 and 4 rewrote the indicators as O(1) deque updates and still timed out, so guessing at the bottleneck did not fix the sandbox timeout.
It was abandoned in a verification loop after 4 iterations. The Layer 3 sandbox backtest kept exceeding the 300s wall-clock limit on a ~20,000-bar (2400-day) BNBUSDT 4H window, and it never got past verification into backtest review, analysis, or risk review.
A single-instrument restatement of the QuantConnect 'Momentum-Short Term Reversal' acceleration screen on BNBUSDT.BINANCE 4H: trade the sign of the 60-day return only while the 5-day per-bar return rate is below the 60-day rate (i.e. avoid blow-off stages), exiting on overreaction, trend flip, or an ATR stop, with a pre-registered ungated control.
No performance data exists: the backtest report is empty and no optimization was run, so there are no return, Sharpe, or trade-count figures.
Backtest Review
- Sharpe
- 0.12
- Total return
- -32.08%
- Max drawdown
- 45.23%
- Trades
- 283
- Win rate
- 52.3%
- Profit factor
- 0.88
Backtest and paper results are hypothetical. Trading involves risk of loss.