Skip to content
All strategies

Strategies

Faithful port of QuantConnect BasePairsTradingAlphaModel: BTC/ETH price-ratio band reversion vs a 500-bar EMA of the ratio, ±1% bands, 1-day insight hold, alternating direction (OKX USDT swaps, DAILY)

Outcome: Abandoned

BtcEthOkxLeanPairsRatioBand

Outcome Summary

This strategy ported LEAN's pairs-trading alpha model onto the BTC/ETH ratio on OKX perpetual swaps: a 500-bar EMA with ±1% bands, one-day holds and alternating direction. The hypothesis's own pre-study found only 19 toggles in about 5.3 years and a mean per-trade spread return of about +0.11%, roughly the round-trip cost and statistically insignificant (t ≈ 0.3). After 2 iterations the run was abandoned at the coding stage because coding timed out three times ('coding_stuck_3_timeouts'), so it never reached verification or backtesting and has no measured performance.

Hypothesis

This states QuantConnect LEAN's BasePairsTradingAlphaModel faithfully (Apache-2.0, credit: QuantConnect Corporation, https://github.com/QuantConnect/Lean/blob/856327ff33869cba98393781000c4ab1d2af423d/Algorithm.Framework/Alphas/BasePairsTradingAlphaModel.py). The source is a complete, tradeable pairs rule, not a utility library. Its has_passed_test() returns True, so the base model trades every pair in its universe with no cointegration test. We run it on ONE pair: the BTCUSDT.OKX and ETHUSDT.OKX USDT perpetual……Show moreShow less

This states QuantConnect LEAN's BasePairsTradingAlphaModel faithfully (Apache-2.0, credit: QuantConnect Corporation, https://github.com/QuantConnect/Lean/blob/856327ff33869cba98393781000c4ab1d2af423d/Algorithm.Framework/Alphas/BasePairsTradingAlphaModel.py). The source is a complete, tradeable pairs rule, not a utility library. Its has_passed_test() returns True, so the base model trades every pair in its universe with no cointegration test. We run it on ONE pair: the BTCUSDT.OKX and ETHUSDT.OKX USDT perpetual swaps. OKX is 0.3% of the corpus against BINANCE's 67%, and both legs have daily history from 2020-01-02. Pair order follows the code. Symbols are sorted, so asset1 = BTCUSDT.OKX, asset2 = ETHUSDT.OKX, and ratio = close(asset1) / close(asset2) = BTC/ETH. Default parameters, exactly as written: lookback = 1, resolution = DAILY, threshold = 1 (percent). Derived values: prediction_interval = 1 day; mean = EMA(500) of the ratio (the 500 is hard-coded); upper = mean x 1.01; lower = mean x 0.99. Identity indicators on the daily closes feed the ratio and EMA. There is no signal until the EMA(500) is ready, which is about mid-May 2021. State machine: the pair starts FLAT_RATIO. It never re-emits the direction it is already in, and it never resets to flat. It only toggles when the opposite band is crossed. Naming quirk: the code calls the ratio > upper case 'LONG_RATIO' but trades it as SHORT asset1 / LONG asset2. Translate the actions, not the enum names. Insights last prediction_interval = 1 day. Under LEAN's default EqualWeighting portfolio construction, targets go to zero when insights expire. So each trade is held for one daily bar, and the book is flat until the next toggle. Sizing: each leg = 50% of equity, leverage 1.0, dollar-neutral. OKX fees are 0.02% maker / 0.05% taker per leg. Point-in-time pre-study on our catalog: 19 toggles in about 5.3 years. The mean next-day spread return was about +0.11% per trade, with standard deviation about 1.5% (t ≈ 0.3). That is about the same as the round-trip cost. The book is expected to be flat about 99% of the time.

The translation keeps LEAN's indicator definitions: Identity closes, ratio = asset1/asset2 with sorted symbols, EMA(500) seeded with an SMA, and bands at mean*(1±threshold/100). It also keeps the state machine and the one-day insight lifetime. The state advances every bar whether or not a position is open, as LEAN's update() does. What the platform forced us to change: (1) fills use market orders at the signal bar's close, while LEAN fills daily-resolution market orders at the next open; (2) each leg is 50% of……Show moreShow less

The translation keeps LEAN's indicator definitions: Identity closes, ratio = asset1/asset2 with sorted symbols, EMA(500) seeded with an SMA, and bands at mean*(1±threshold/100). It also keeps the state machine and the one-day insight lifetime. The state advances every bar whether or not a position is open, as LEAN's update() does. What the platform forced us to change: (1) fills use market orders at the signal bar's close, while LEAN fills daily-resolution market orders at the next open; (2) each leg is 50% of equity, matching EqualWeighting of a two-insight group; (3) each leg is submitted on its own instrument; (4) the ETH close is used only when its bar timestamp equals the BTC bar's (alignment barrier). One rare edge case: if a change to the opposite band happens on the same bar that the previous one-day trade exits, that change is not traded, whereas LEAN would re-target. With about 19 changes in 5 years this makes little difference. I expect this strategy to fail on fees and sample size: the pre-study found 19 trades at +0.11% per trade (t≈0.3), about the round-trip cost of two legs. I implemented it as asked anyway. All state is plain scalars (EMA, count, state, entry timestamp), so a restart gives the same decisions.

coding_stuck_3_timeouts

Implementation

Faithful port of QuantConnect LEAN's BasePairsTradingAlphaModel on BTCUSDT.OKX / ETHUSDT.OKX daily bars. The ratio is BTC/ETH. Its mean is a LEAN-style EMA(500), seeded with an SMA and ready after 500 bars, with bands at ±1% of the mean. The state machine alternates: it starts flat, never repeats the direction it is already in, and changes only when price crosses the opposite band. Ratio above the upper band means short BTC / long ETH; below the lower band means long BTC / short ETH. Each change opens a dollar-neutral pair (50% of equity per leg, leverage 1) that is held for one daily bar, matching the insight expiry under EqualWeighting. The book then stays flat until the next change.

Iteration History

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

The pre-study already put the edge at about round-trip cost on only 19 trades (t ≈ 0.3), so this hypothesis was a weak candidate even before the coding timeouts; screening out edges this thin before coding would save pipeline capacity.

The run was abandoned at the coding stage with reason 'coding_stuck_3_timeouts' after 2 iterations. Verification, backtesting, analyst review and risk review were never reached.

A faithful port of QuantConnect LEAN's BasePairsTradingAlphaModel on the BTC/ETH OKX USDT-swap price ratio: when the daily ratio crosses a ±1% band around its 500-bar EMA, it enters a dollar-neutral pair trade (50% of equity per leg) betting on reversion, holds it for one daily bar, and only toggles direction when the opposite band is crossed.

No backtest or optimization results exist (the backtest report is empty). The only figures are from the hypothesis's own pre-study: 19 toggles in about 5.3 years, a mean next-day spread return of about +0.11% per trade (standard deviation about 1.5%, t ≈ 0.3), which is roughly equal to the round-trip cost.

Analysis

BasePairsTradingAlphaModel

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