Skip to content
All strategies

Strategies

OKX 14-Swap Price-Volume Correlation Cross-Section: Long Low-Corr / Short High-Corr, Weekly Dollar-Neutral (1-DAY)

Outcome: Abandoned

OkxDailyPriceVolumeCorrelationCrossSection

Outcome Summary

The hypothesis proposed a new mechanism family for the corpus: a long-short price-volume correlation cross-section across 14 OKX perps, with 1.0x gross exposure, weekly rebalances and 25% per-leg catastrophe stops. The developer used rolling deques and indexed order queries to keep the work bounded, but across 3 iterations the code never got past Layer 3 sandbox verification, where it went over the 300s limit on a 2,400-day daily window. The run was abandoned for a sandbox timeout before any backtest, backtest review, optimization, analyst or risk review stage ran, so the factor's edge was never measured.

Hypothesis

Cross-sectional long-short factor on 14 OKX USDT perpetual swaps using daily OHLCV bars. Each coin has contiguous daily history from 2020 or early 2021 through 2026-10-02 (checked in the catalog: BTC/ETH/BCH/TRX/ETC from 2020-01-02, SOL from 2021-01-24, all with a max gap of 1 day). The source is the BigQuant price-volume correlation factor (https://bigquant.com/wiki/doc/I5oStgChtF): factor = -1 x corr_20d(close/close[-1], log(volume/volume[-1] + 1)). In each coin, it measures whether up-days come with volume……Show moreShow less

Cross-sectional long-short factor on 14 OKX USDT perpetual swaps using daily OHLCV bars. Each coin has contiguous daily history from 2020 or early 2021 through 2026-10-02 (checked in the catalog: BTC/ETH/BCH/TRX/ETC from 2020-01-02, SOL from 2021-01-24, all with a max gap of 1 day). The source is the BigQuant price-volume correlation factor (https://bigquant.com/wiki/doc/I5oStgChtF): factor = -1 x corr_20d(close/close[-1], log(volume/volume[-1] + 1)). In each coin, it measures whether up-days come with volume surges (attention- or FOMO-driven buying, high correlation) or whether volume surges come on down-days or are unrelated to direction (low or negative correlation). Every rebalance_days daily bars, rank the 14 coins by PVC_i = Pearson corr over corr_lookback days of (daily simple return, daily log volume change). Go long the n_per_side coins with the LOWEST PVC and short the n_per_side coins with the HIGHEST PVC. The legs are equal-weighted, dollar-neutral, and gross exposure equals 1.0x equity (each side 50%). The factor sign is pre-registered and fixed, not tunable, so the optimizer cannot flip it. Coins that remain in the same bucket at a rebalance are kept, not re-traded, which cuts turnover. This is a new mechanism family for the corpus: the only related hypothesis was a single-asset BTC Wyckoff divergence. It is not momentum, not calendar-keyed, not a supplementary-feed gate on one perp, and not options. It also fills under-represented buckets: OKX venue (2.0% vs >=5% target), long_short (16.7%), and multi-instrument. Execution: market orders at the daily close bar, positions held for about 1 week. OKX funding is accrued as a cost or credit by the engine; it is not a signal. Risk: each leg has a fixed 25% adverse catastrophe stop (relevant for short squeezes), and a stopped leg stays flat until the next rebalance. Max single-leg exposure is 1/(2*n_per_side) of equity (16.7% at the baseline n=3). Leverage is set via config.leverage = 1.0 and is NOT an optimization_plan parameter. Implementation note: keep a rolling deque of the last corr_lookback+1 closes and volumes per instrument, updated in on_bar/on_extra_bar, and compute correlations only on rebalance bars. This is O(14 x lookback) per rebalance; never rescan history (avoids the sandbox timeout).

Chosen to fill under-represented buckets: OKX at 2.0% (target >=5%), long_short at 16.7% (long_only is 83% against a <=55% ceiling), and multi-instrument. BINANCE is avoided (62%) and so is BTC concentration (BTC is just 1 of 14 equal legs). The mechanism family (return-volume co-movement as a cross-sectional rank) has essentially no history in the corpus. Lesson compliance: L186/L181, every leg's OKX USDT-swap 1-DAY bars were verified in the catalog with contiguous history and no gaps; coins with only about one week of OKX history (XRP, DOGE, LTC, FIL, NEAR, OP) were deliberately excluded. L179: the trigger is a market observation (a rank), not a calendar window, because the rebalance cadence only sets when ranks are re-read. L111: no supplementary gate. L102: no options. Leverage is kept OUT of optimization_plan.fixed because it is a config field, not a strategy parameter; a fixed leverage entry is what failed the recent LTC-BCH and OKX lottery runs at Layer 1.5.

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

Implementation

Cross-sectional OKX 14-perp factor on daily bars. Every rebalance_days (bucket = days_since_epoch // rebalance_days), coins are ranked by the Pearson correlation over corr_lookback days of the daily return and log1p(volume/prev volume). The strategy goes long the n lowest-PVC coins and short the n highest, equal-weight and dollar-neutral at 1.0x gross. Retained legs are kept unless they drift beyond tolerance. Each leg has a 25% reduce-only catastrophe stop that rests at the venue, and a stopped leg stays flat until the next bucket. All state is held in scalar attributes per leg.

Iteration 3 addresses the Layer-3 sandbox_timeout. I reproduced it locally with the same run_backtest_in_subprocess call on 2020-01-02..2025-01-24, which took 338s in total. A cProfile of subprocess_entry on a 1.6-year window ran 179s. 166s of it went to ParquetDataCatalog.query (fsspec spec.walk/local.ls/info: 371k ls and 2.4M stat calls across 17 catalog queries, plus 70s in bar_stamping.load_normalised). The strategy's entire on_bar path took about 1.5s for 8,456 bars. The timeout is therefore catalog I/O for……Show moreShow less

Iteration 3 addresses the Layer-3 sandbox_timeout. I reproduced it locally with the same run_backtest_in_subprocess call on 2020-01-02..2025-01-24, which took 338s in total. A cProfile of subprocess_entry on a 1.6-year window ran 179s. 166s of it went to ParquetDataCatalog.query (fsspec spec.walk/local.ls/info: 371k ls and 2.4M stat calls across 17 catalog queries, plus 70s in bar_stamping.load_normalised). The strategy's entire on_bar path took about 1.5s for 8,456 bars. The timeout is therefore catalog I/O for 14 legs and is independent of strategy code (lesson 155(b)/(c): plumbing, not a signal fix). Per-bar strategy cost is already O(14 x lookback) only on rebalance bars and O(lookback) otherwise, with bounded deques and indexed open/in-flight order queries. The only code change is a small genuine saving: on rebalance bars the primary leg's correlation, already computed for the per-bar signal, is reused rather than recomputed. Instruments, legs, sign and the parameter plan are unchanged, so it stays faithful to the hypothesis. The catalog query cost needs an engineering fix (cache the catalog file list, or query by explicit bar-type paths) or a higher sandbox cap for 14-leg books.

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

A 14-instrument daily strategy has to keep per-bar and per-rebalance work bounded (for example, no scanning of cached order or bar history inside on_bar) to finish the 300s sandbox, even when the hypothesis already says to use rolling deques.

After 3 iterations it was abandoned in the verification loop. Its Layer 3 sandbox smoke test went over the 300s wall-clock limit on a ~20,000-bar window (2,400 days of BTCUSDT.OKX 1-day bars), which points to per-bar work that grows with history.

A weekly-rebalanced, dollar-neutral cross-sectional factor on 14 OKX USDT perpetual swaps that goes long the coins with the lowest 20-day price-volume correlation and short those with the highest, based on the BigQuant PVC factor with a fixed, pre-registered sign.

There are no performance numbers: the strategy never finished a backtest, so the backtest report is empty and the optimization report is null.

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