Skip to content
All strategies

Strategies

Small-Portfolio 12-1 Month Momentum on the Nine Original Select Sector SPDRs: Long Top-3 / Short Bottom-3, Equal-Weight 50/50 Gross, Monthly Rebalance (USEQ DAILY, long-short, 2 parameters)

Outcome: Abandoned

SectorSpdr12m1MomentumTop3Bottom3LS

Outcome Summary

SectorSpdr12m1MomentumTop3Bottom3LS adapted QuantConnect's small-portfolio momentum strategy to the nine original sector SPDRs, going long the top-3 and short the bottom-3 by 12-1 month return with a monthly rebalance on the zero-commission USEQ venue. Over 3 iterations the code never passed verification, because each Layer 3 sandbox backtest ran past the 300s wall-clock limit on the ~20,000-bar window. The run was abandoned in a verification loop, so no backtest, optimization, analyst or risk stage produced results, and the momentum hypothesis was never tested.

Hypothesis

Source: QuantConnect Strategy Library #162 'Momentum Effect in Stocks in Small Portfolios' (after Quantpedia), section 'Method'. The source ranks US stocks by trailing 12-month return and goes long the top 10 and short the bottom 10, equal weight, 50% gross per side, rebalanced yearly. We keep the mechanism (a small, equal-weight long-winners / short-losers portfolio ranked on 12-month return, 0.5 gross per side) and make three changes, each forced by this factory's evidence. (1) UNIVERSE: the source needs a……Show moreShow less

Source: QuantConnect Strategy Library #162 'Momentum Effect in Stocks in Small Portfolios' (after Quantpedia), section 'Method'. The source ranks US stocks by trailing 12-month return and goes long the top 10 and short the bottom 10, equal weight, 50% gross per side, rebalanced yearly. We keep the mechanism (a small, equal-weight long-winners / short-losers portfolio ranked on 12-month return, 0.5 gross per side) and make three changes, each forced by this factory's evidence. (1) UNIVERSE: the source needs a point-in-time all-US-stocks universe with fundamentals and market cap, which we do not have. Lesson 151 kills hand-picked stock lists and lesson 173 says cross-sectional books over ~10 names time out. So we use the nine ORIGINAL Select Sector SPDR ETFs (XLB, XLE, XLF, XLI, XLK, XLP, XLU, XLV, XLY). That set is defined by one listing event (all nine launched together in December 1998) and not by later performance. It partitions the S&P 500, so every name in it is liveable and nothing was selected with hindsight. XLC and XLRE are excluded because they launched in 2018 and 2015 and would change the cross-section partway through. Sector momentum (Moskowitz & Grinblatt 1999) is the industry-level form of the same effect and carries most of the stock-level momentum premium. (2) N: with 9 names, top-3 / bottom-3 is the same one-third tails as the source's top/bottom decile of a small portfolio. (3) REBALANCE: the source rebalances yearly, which gives about 26 rebalances over our history and only about 5 in the 20% holdout, too few to measure. We rebalance MONTHLY with a 12-month formation window that skips the most recent month (12-1, the standard Jegadeesh-Titman construction, which avoids the 1-month reversal). Ranks are persistent, so only about 1-2 legs change each month. DATA: USEQ daily bars exist in the catalog for all nine ETFs from 1998-12 onward, which gives about 26 years after a 252-session warm-up. PER-TRADE ARITHMETIC: the average holding per leg is about 3-5 months. The historical top-minus-bottom-third sector spread is about 0.3-0.6% per month, and each leg's absolute move is about 1.5-3% per month. The expected mean per-leg trade return is about +0.8% of notional (winners held longer than losers, per leg) against a USEQ round-trip cost of about 0.04% (zero commission, about 1bp half-spread plus impact on these ETFs). That is about 20x the cost, so this is not a fee_edge candidate. The risk is momentum crashes, not fees. EXPECTED TRADE COUNT: about 300 rebalances with about 2 leg round trips each, so roughly 500-700 lifetime round trips and about 100+ in the holdout. FLAT STATE: the strategy is fully flat only during the 252-session warm-up, and after that it always holds 3 longs and 3 shorts. This is a deliberate exception to lesson 150. That lesson's cost argument (a double round trip on each sign flip) does not bind here: legs flip at most monthly, and the cost is about 0.04% on a zero-commission venue. Declared time in market is about 96% of history. No gate, filter or supplementary feed is used (lesson 130). A long-only 'top-3 only' variant, if wanted, must be pre-registered and scored separately. It is not part of this claim.

Preserves the existing validated implementation and fixes the Layer-3 timeout by caching the momentum calculation and portfolio ranking until the next calendar-month rebalance. Daily bars still update the synchronized rolling buffer, while ordinary bars avoid repeated momentum scans and sorting. The monthly schedule remains anchored to bar timestamps for restart parity.

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

Monthly 12-1 momentum ranking across the nine original Select Sector SPDR ETFs. Holds equal-weight long positions in the top three sectors and short positions in the bottom three, with 50% gross exposure per side.

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

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['skip_days', 'n_per_side', 'min_notional', 'lookback_days', 'gross_per_side'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000) - steady_downtrend: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000) - flat_ranging: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000) - volatility_spike: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000) - zero_volume: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000) - price_gap: AttributeError: '_MockCache' object has no attribute 'orders_inflight' (bar timestamp: 1735706040000)

Outcome Summary

The multi-instrument per-bar path has to stay cheap enough to finish the 20k-bar smoke test in 300s: re-rank only at month boundaries and avoid per-bar order-cache queries across all legs, which here ran on every bar through calculate_signal/_reconcile.

It was abandoned in a verification loop after 3 iterations, because the Layer 3 sandbox backtest went over the 300s wall-clock limit on a ~20,000-bar (2,400-day) XLB.USEQ daily window. Backtest review, optimization, analyst review and risk review never ran.

Capture 12-1 month sector momentum by going long the top-3 and short the bottom-3 of the nine original Select Sector SPDR ETFs (USEQ daily), equal-weight at 0.5 gross per side, rebalanced monthly.

No performance was measured: the backtest report is empty and there is no optimization report, so no return, Sharpe or trade count exists. The hypothesis only projected roughly +0.8% mean per-leg trade return against about 0.04% round-trip cost and 500-700 lifetime round trips.

Analysis

Momentum Effect in Stocks in Small Portfolios

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