Skip to content
All strategies

Strategies

SOL Bybit Dual Thrust Intraday Open-Range Breakout, Long-Short, Flat at UTC Day Close (SOLUSDT.BYBIT 1H, pure OHLCV, single leg)

Outcome: Abandoned

SolBybitDualThrustIntradayLS

Outcome Summary

The strategy proposed a pure-OHLCV intraday breakout for SOLUSDT.BYBIT with long and short entries and daily flattening. It produced no backtest or optimization results because Layer 1 static analysis failed. The run was abandoned at iteration 5 before later stages.

Hypothesis

Mechanism distilled from the FMZ digest 'Implementing a Dual Thrust crypto strategy in Python' (by 善, 2019-08-13, sections 'DT策略原理' and 'DT策略的数学表达式'), originally Michael Chalek's Dual Thrust. It is restated for today's fees, not ported. The original is an always-in stop-and-reverse on OKCoin futures. Per L150, always-in is dropped: this version is an INTRADAY open-range breakout that is flat at every UTC day close. Daily anchor: each UTC day's open O_d (the open of the 00:00 UTC 1H bar). Range = max(HH - LC, HC -……Show moreShow less

Mechanism distilled from the FMZ digest 'Implementing a Dual Thrust crypto strategy in Python' (by 善, 2019-08-13, sections 'DT策略原理' and 'DT策略的数学表达式'), originally Michael Chalek's Dual Thrust. It is restated for today's fees, not ported. The original is an always-in stop-and-reverse on OKCoin futures. Per L150, always-in is dropped: this version is an INTRADAY open-range breakout that is flat at every UTC day close. Daily anchor: each UTC day's open O_d (the open of the 00:00 UTC 1H bar). Range = max(HH - LC, HC - LL) over the prior N=2 completed UTC days (HH/LL = highest high / lowest low, HC/LC = highest / lowest close), computed from completed 1H bars only, point-in-time. Upper trigger = O_d + K*Range, lower = O_d - K*Range, with K1 = K2 = 0.5 (the source's demo value, fixed, symmetric, not fitted). Trade at most ONE entry per UTC day, taking the first side touched on a 1H close. Why SOL on Bybit: BINANCE is 67% of the corpus and BTC is over-concentrated. Bybit is 1.2%, and SOLUSDT.BYBIT has 1H history from 2021-10 (~5 years, ~1800 UTC days). OKX SOL/ETH 1H has only ~2 days in the catalog, so OKX is not viable. The mechanism is pure price, so per L160 it needs no supplementary feed on Bybit. It is not HL (L168). Signal and trade are on the same instrument (L143). SOL has one of the widest daily ranges among liquid majors (median ~4-5%), which is what an open-range breakout needs to clear fees. Mechanism in one sentence without instrument or timeframe: 'enter in the direction of an intraday move from the session open that exceeds half of the recent multi-day range, exit at session close.' This differs from the pipeline's channel-break-plus-clock runs (a 10-day high break with a 12h clock), which use no session-open anchor and hold across days. Expected flat time: ~80%. Triggers fire on roughly 45-55% of days; average hold ~10h of 24h.

Implements the hypothesis unchanged. Iteration 5 changes only the docstring, and that change records the diagnosis under L155(b)/(c). I reproduced the Layer-3 timeout locally (the real subprocess backtest took 421 s) and profiled it with cProfile: 548 s total, with 475 s inside nautilus ParquetDataCatalog.query. That query runs an fsspec glob over 131,667 bar directories (235k ls calls and 1.3M stat calls). Another ~50 s is spent on imports. The strategy's per-bar work is O(1) scalar state and does not show up in the profile. Neither the per-bar cost nor the config can shorten a catalog-wide directory scan, so this is infrastructure, not a strategy defect. The fix belongs in the catalog query path, for example querying by the exact bar-type directory or caching the file list. A 7-month local run (2026-03 to 2026-09) completed with 178 trades, avg_trade_return_pct -0.019%, PF 0.70, Sharpe -1.08 and max DD 25%. On that recent window the edge is below fees, which the analyst should weigh once a full sandbox run gets through.

verification_loop: Verification failed (Layer 1 — static analysis): - Syntax error: invalid decimal literal (<unknown>, line 1) (line 1)

Implementation

Dual Thrust intraday open-range breakout on SOLUSDT.BYBIT 1H. The range is max(HH-LC, HC-LL) over the prior 2 completed UTC days. The signal is (close - today's 00:00 UTC open) / range. It goes long at >= +0.5 and short at <= -0.5, with at most one entry per UTC day, and is flat at every UTC day close. Notional is 0.4 x 2x leverage = 0.8x equity, capped at 1.0x.

Verification Results

Verification failed (Layer 1 — static analysis): - Syntax error: invalid decimal literal (<unknown>, line 1) (line 1)

Optional: set _entered_day only once an entry is actually submitted (e.g. in on_position_opened).

should_enter sets _entered_day/_pos_day before position_size and the min-notional check run. If the order is dropped (size 0 or below $5), that UTC day's single entry is still used up. This is harmless at 95% equity sizing but hides dropped signals.

Consider a risk-based size cap or a stop at the opposite trigger (the source's reverse level) if drawdown floors bind at analysis.

There is no intraday stop. Each trade carries 95% of equity of unhedged SOL exposure for up to ~23h (sandbox largest loss is about -$16k). This matches the hypothesis (the exit is the session close; the SAR stop was dropped), and it is not the L148 always-in pattern: the strategy is flat about 81% of the time, sizing happens once per day, and worst-case gross is 0.95 x 1 leg x 1.0 leverage, which is at or below equity. Per-trade risk is not capped at 1-2% of equity, though.

None required.

min_bars_required is overridden to 20. That is fine, because the strategy gates itself on having two full, consecutive prior UTC days (48+ bars) before any signal fires.

The sandbox's own ledger does not add up. avg_trade_return_pct is +0.088% over 351 trades, which implies about +31%, but total_return is -46% and PF is 0.88 (L116/L140 sign and magnitude mismatch). The per-trade number can't be compared with the Bybit fee floor (~0.11% taker round trip plus impact of about $26k, commission $36.8k) until the analyst reconciles it against the full backtest. Even at face value, 0.088% is below the 0.15% floor. Losses are concentrated in the calm-vol tercile (-70%) and the strategy is flat in the stressed tercile, which fits an open-range breakout that gets chopped on low-range days. min_range_pct (currently 0) is the natural filter to check first. PF 0.88 on 351 trades is not in the L125 polarity-suspicion zone (<0.70).

Analysis

Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.73 disagrees in sign with total_return -100.00% — 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

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (833 days of SOLUSDT.BYBIT-1-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).

Outcome Summary

Ensure generated strategy source is syntactically valid before verification.

It was abandoned after iteration 5 when Layer 1 static analysis found an invalid decimal literal on line 1. Later stages were not reached.

The strategy tried an intraday, long-short SOL Bybit open-range breakout based on half the prior two completed UTC days' range from the daily open, flattening at UTC day close.

No backtest or optimization metrics were recorded because verification did not complete.

Abandon Reason

verification_loop: Verification failed (Layer 1 — static analysis): - Syntax error: invalid decimal literal (<unknown>, line 1) (line 1)

Analysis

用Python实现一个Dual Thrust数字货币量化交易策略

Backtest Review

Sharpe
0.73
Total return
-100.00%
Max drawdown
100.00%
Trades
751
Win rate
48.9%
Profit factor
0.85

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