Skip to content
All strategies

Strategies

SPY/IWM Size-Spread Mean Reversion on DAILY Bars: Beta-Hedged Log-Spread Z-Score (Point-in-Time Rolling Stats), Enter |z|>=2, Exit |z|<=0.5 or 10-Session Clock, Dollar-Neutral Long/Short, Flat ~80% (SPY.USEQ + IWM.USEQ 1D)

Outcome: Abandoned

SpyIwmSizeSpreadMeanReversionDaily

Outcome Summary

The strategy adapted an FMZ intraday SPY/IWM mean-reversion idea to daily bars. It removed the source's look-ahead by using rolling beta and z-score statistics, and it aimed for a dollar-neutral pair whose per-trade capture would clear USEQ costs. Across 3 iterations the code never passed Layer 3 verification: each time, the sandbox backtest went over the 300s limit on a ~2400-day IWM.USEQ daily window. The strategy was abandoned in the verification loop, so the backtest, optimization, analyst and risk stages were never reached and no performance metrics exist.

Hypothesis

Adapted from the FMZ digest article by 善, 'A mean-reversion intraday trading strategy using SPY and IWM' (https://www.fmz.com/digest-topic/3991, sections '策略' and 'Python实现'). The source trades SPY vs IWM on 1-MINUTE bars: a rolling 100-bar OLS of SPY price on IWM price gives the hedge ratio, spread = SPY - beta*IWM, z-score of the spread, enter at |z|=2, exit at |z|=1. The author says it has two flaws: the z-score uses the full-sample mean and std, which is look-ahead, and there are no transaction costs. We keep……Show moreShow less

Adapted from the FMZ digest article by 善, 'A mean-reversion intraday trading strategy using SPY and IWM' (https://www.fmz.com/digest-topic/3991, sections '策略' and 'Python实现'). The source trades SPY vs IWM on 1-MINUTE bars: a rolling 100-bar OLS of SPY price on IWM price gives the hedge ratio, spread = SPY - beta*IWM, z-score of the spread, enter at |z|=2, exit at |z|=1. The author says it has two flaws: the z-score uses the full-sample mean and std, which is look-ahead, and there are no transaction costs. We keep the mechanism, which is that large-cap and small-cap US equity indices are driven by the same macro factor, so short-run divergence in their beta-adjusted spread tends to close. We fix the flaws and move it to a timeframe where it can clear costs. (1) TIMEFRAME: at 1m, a 100-bar spread std is only a few bps. Reverting from z=2 to z=1 captures about 1 std, roughly 0.03-0.05% of notional, which is below the two-leg USEQ round trip of about 0.06-0.10% (spread plus impact on each leg). The 1m and 1h catalogs also hold only about 6 weeks and about 2 years of data. We therefore use DAILY bars, which cover SPY.USEQ and IWM.USEQ back to IWM's inception in May 2000 (about 26 years). (2) NO LOOK-AHEAD: the hedge ratio, spread mean and spread std are all rolling and computed from sessions strictly before the decision bar's close. (3) HEDGE RATIO: we use a rolling 60-session OLS beta of IWM daily log-returns on SPY daily log-returns, not a regression of price levels, because a price-level OLS on two non-stationary series gives a spurious and drifting ratio. Spread_t = ln(IWM_t) - beta*ln(SPY_t), and z_t = (spread_t - mean20)/std20 over the prior 20 sessions. (4) EXECUTION: both legs are traded at the next session's open on the USEQ Reg-T margin account, with whole shares. Size is dollar-neutral after beta weighting: IWM notional N and SPY notional beta*N, rounded to whole shares. SPY and IWM are the two most liquid ETFs in the US, so the fractional-share and cost concerns the author raised do not apply at $100k. Scope note: lesson L137 warns against multi-leg neutral books. This is not a basket. It is a 2-leg pair of the two deepest US ETFs, so costs on USEQ are about 1/10 of crypto costs per leg and the per-trade capture below is about 15-30x the round trip. That is why a 2-leg design is kept here: the pair spread is the user's mechanism, and it cannot be expressed on a single leg without adding the index beta (L143). Parameters: 4 core parameters (hedge_window=60, z_window=20, z_entry=2.0, z_exit=0.5), plus a time stop of 10 sessions and a blow-up stop at |z|>=4.0. The optimizer should not widen the hedge_window/z_window grid beyond about ±50%.

This iteration preserves the previous strategy and removes the per-bar O(z_window) spread-statistics loop. Rolling level moments are maintained incrementally, making beta and z-score calculation O(1) per bar while retaining prior-session-only statistics and exact same-timestamp extra-leg alignment.

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

Daily USEQ pair-trading strategy using a point-in-time rolling beta-hedged log-spread z-score between IWM and SPY. It enters at extreme divergences, exits on reversion, blow-up, or a ten-session time stop, and sizes whole-share dollar-neutral legs.

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

A multi-instrument daily strategy has to fit inside the sandbox time budget. Find out why the smoke test hangs or runs slowly, for example extra-leg bar alignment or per-bar position and cache lookups, before iterating on signal logic, even when the rolling statistics are already O(1).

It was abandoned in the verification loop after 3 iterations. The Layer 3 sandbox backtest went over the 300s wall-clock limit on a ~20,000-bar window (2400 days of IWM.USEQ-1-DAY-LAST-EXTERNAL), which ended the run before the backtest, analyst and risk stages.

A dollar-neutral, beta-hedged SPY/IWM pair on daily USEQ bars. It traded the z-score of the log-spread ln(IWM) - beta*ln(SPY), using a rolling 60-session return-based beta and a 20-session point-in-time mean and std. It entered at |z|>=2 and exited at |z|<=0.5, after 10 sessions, or at a |z|>=4 blow-up stop.

No performance numbers exist. The strategy never produced a backtest report or an optimization report, so it has no return, Sharpe or trade-count figures.

Analysis

一个运用SPY与IWM之间均值回归的日内交易策略

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