Strategies
Large-versus-small-cap monthly momentum spread
Outcome: Abandoned
LargeSmallCapMonthlyMomentumSpread
Outcome Summary
This strategy tested whether 12-month relative momentum between large caps (SPY) and small caps (IWM) gives a tradable monthly spread. The six style ETFs named in the source were not in the USEQ universe, and the hypothesis noted that earlier two-leg USEQ runs had timed out. All three iterations failed at Layer 3 verification by exceeding the 300s sandbox limit, so the run was abandoned before any backtest, optimization or analyst verdict. The strategy's docstring says a 2026-10-02 measurement put almost all of the runtime in ParquetDataCatalog file discovery rather than in the O(1) per-bar strategy loop, which suggests the problem is in the infrastructure, not the strategy code.
Hypothesis
Test the source's 12-month relative-momentum rule using SPY as the large-cap proxy and IWM as the small-cap proxy. The six style ETFs named in the source are absent from the configured USEQ universe. Prior two-leg USEQ runs have timed out, so this premise can be judged only after the pipeline produces a measured backtest.
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 SPY.USEQ-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
On the first daily bar of each calendar month, compare the 252-session total price return of SPY (large cap) and IWM (small cap). Go long the stronger leg and short the weaker leg, with 50% of gross exposure on each side in whole shares, and hold the pair until the next month's rebalance. The signal is the continuous return spread SPY_ret - IWM_ret.
This implements the source's 12-month relative-momentum rule with SPY and IWM as the large- and small-cap proxies. The trading logic is unchanged from the version that passed Layers 1, 1.5 and 2; the only edit is a docstring recording the timeout diagnosis. I ran the sandbox-equivalent backtest locally (USEQ, 2017-06 to 2024-01) under cProfile. Total wall time was 504 s, of which 494 s was BacktestRunner.run. Of that, 470 s was ParquetDataCatalog.bars() -> get_file_list_from_data_cls(), which runs fsspec glob('data/catalog/data/bar/**/*.parquet') over about 134k bar directories (372k ls calls and 2.5M stat/info calls). The runner makes two such calls for any two-leg strategy (the primary load_normalised plus the batched extra-leg query), at about 200 s each on the current host (load average 33-42 on 18 cores). The strategy's own callbacks for about 1,700 daily bars took seconds. This explains why every two-leg USEQ daily run has timed out (lesson 182). No signal, buffer or rebalance edit can bring the run under 300 s, because the cost is paid before the first bar is delivered.
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 SPY.USEQ-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
Two-leg USEQ strategies keep timing out in Layer 3, and the strategy's own notes put the cause in catalog file discovery inside the backtest runner (about 494 of 504 s), not in per-bar strategy work. Fixing catalog loading would do more than another code iteration.
After 3 iterations it was abandoned in a verification loop. The Layer 3 sandbox smoke test went over its 300s wall-clock limit on a ~20,000-bar window (2,400 days of SPY.USEQ daily bars), so the backtest-review, analyst and risk stages never ran.
A monthly long-winner/short-loser spread between SPY (large-cap proxy) and IWM (small-cap proxy) on USEQ. Each month it compared their 12-month (252-session) relative momentum, bought the leader and shorted the laggard.
Not measured: no backtest completed. The backtest report is empty, there is no optimization report, and no return, Sharpe or trade-count figures exist.
Analysis
Momentum and Style Rotation Effect
Backtest and paper results are hypothetical. Trading involves risk of loss.