Skip to content
All strategies

Strategies

Low-Volatility Anomaly on the Select Sector SPDRs: Monthly Hold of the 3 Lowest 252-Day Return-Vol Sector ETFs, Long-Only, Equal-Weight (USEQ 1-DAY, pure OHLCV, 2 parameters)

Outcome: Abandoned

SectorSpdrLowVolBottom3MonthlyLong

Outcome Summary

SectorSpdrLowVolBottom3MonthlyLong adapted the QuantConnect/Quantpedia 'Volatility Effect in Stocks' idea to the 11 Select Sector SPDR ETFs. It held the 3 lowest-volatility sectors each month at about 33% of equity each, with no leverage, shorts or regime gates. The hypothesis flagged the risk of sandbox timeouts, and the code used fixed-size deques with running sums. Even so, after 3 iterations the strategy still ran past the 300s limit in the Layer 3 sandbox backtest and was abandoned in a verification loop. It never produced a backtest, so its economic edge was never measured.

Hypothesis

Source: QuantConnect Strategy Library #18 'Volatility Effect in Stocks' (Quantpedia, 'Volatility Effect in Stocks - Long-Only Version'). The source mechanism is the low-volatility anomaly: assets with lower trailing volatility earn higher risk-adjusted returns than high-volatility ones. Leverage-constrained and benchmark-tied investors bid up high-beta, lottery-like names and neglect dull ones (Frazzini-Pedersen betting-against-beta; Baker-Bradley-Wurgler). The source ranks the top 50 US large caps by market cap,……Show moreShow less

Source: QuantConnect Strategy Library #18 'Volatility Effect in Stocks' (Quantpedia, 'Volatility Effect in Stocks - Long-Only Version'). The source mechanism is the low-volatility anomaly: assets with lower trailing volatility earn higher risk-adjusted returns than high-volatility ones. Leverage-constrained and benchmark-tied investors bid up high-beta, lottery-like names and neglect dull ones (Frazzini-Pedersen betting-against-beta; Baker-Bradley-Wurgler). The source ranks the top 50 US large caps by market cap, holds the 5 with the lowest 252-day volatility, and rebalances on the first trading day of each month. Three changes make it testable here. (1) UNIVERSE. We have no point-in-time market-cap data, and a hand-typed 50-stock list selected in 2026 is survivorship-biased (L151). It also exceeds the ~10-name compute ceiling (L173). The mechanism is therefore expressed on the 11 Select Sector SPDR ETFs (XLB, XLC, XLE, XLF, XLI, XLK, XLP, XLRE, XLU, XLV, XLY). This universe is defined by a rule, not picked in hindsight: it is the S&P 500's GICS sector partition. A sector enters the ranking only once it has 252 daily bars. That point-in-time rule automatically excludes XLRE before ~2016-10 and XLC before ~2019-06. The low-vol anomaly is documented at the industry and sector level as well as at the stock level (Baker-Bradley-Wurgler 2014 find much of it is between industries). (2) VOLATILITY DEFINITION. The source computes the standard deviation of closing PRICE LEVELS. That is scale-dependent: it ranks cheap stocks as 'low vol' and is a bug. We use the standard deviation of daily log returns over 252 sessions. (3) BREADTH. We hold N=3 names instead of 5 of 50, keeping roughly the source's selectivity ratio (the lowest ~25%). Rebalance on the first session of each month. Each holding is equal-weighted at ~33% of equity, 1x, with no leverage and no shorts. There are no regime, trend or cash gates (L130). A SPY-200d cash gate may be pre-registered later as a separate, separately-scored variant; it is not part of this claim. Flat state: the primary design is fully invested except during the 252-session warm-up. This is declared openly. It is not a never-flat long-short book (L150): there are no sign flips, and turnover is only the names that leave the bottom-3 set, typically 0-1 per month, at ~0.03% round-trip spread cost on commission-free USEQ. Data: USEQ daily bars from ~1999 for 9 of the 11 ETFs, which gives ~26 years and multiple regimes (2000-02, 2008, 2020, 2022). This is the longest clean history available anywhere in the factory. Implementation note (sandbox-timeout lesson from recent failures): keep one fixed-size deque of the last 252 log returns per ETF, updated O(1) per bar. Compute vol only on the monthly rebalance bar, sorting 11 numbers. Never rescan history. Novelty vs corpus: USEQ is 3.3% of experiments. The low-vol/BAB family previously died only as cross-sectional NEUTRAL books on crypto perps (L45/L137) and as a 30-name crypto betting-against-volatility basket. This is a long-only, 11-ETF, rule-defined equity universe with a 2-parameter design.

Implements the hypothesis directly: return-vol (log returns, not price levels), point-in-time eligibility at 252 bars (XLRE/XLC join late), calendar-month rebalance from bar timestamps, equal-weight long-only, gross <= 0.98x equity. Vol kept via O(1) running sum/sumsq per ETF so per-bar cost is independent of span. Iteration 3 fix: the previous submission's code field reached verification as a placeholder string (Layer-1 'invalid decimal literal, line 1'); the full source is now inline in the code field.

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

Long-only low-volatility anomaly on the 11 Select Sector SPDR ETFs (USEQ daily). On the first aligned session of each calendar month, rank ETFs with >=252 daily log returns by 252-session return volatility and hold the 3 lowest at equal weight (~32.7% of equity each, 1x, whole shares). Names leaving the bottom-3 are sold, joiners bought, continuing names held. No regime or cash gates.

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 XLU.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 1 — static analysis): - Syntax error: invalid decimal literal (<unknown>, line 1) (line 1)

Outcome Summary

The hypothesis already asked for O(1) rolling-window updates, but this 11-leg daily strategy still timed out in the sandbox. Before resubmitting, profile the per-bar cost across all legs, including the custom cross-leg alignment barrier and the per-bar position and order cache checks, rather than only the volatility math.

It was abandoned in a verification loop after 3 iterations. Layer 3 (the sandbox backtest) failed with a sandbox_timeout because the smoke test ran past the 300s wall-clock limit on a ~20,000-bar window (2400 days of XLU.USEQ-1-DAY-LAST-EXTERNAL). Backtest review, optimization, analyst review and risk review never ran.

It tested the low-volatility anomaly on the 11 Select Sector SPDR ETFs. Each month it held the 3 sectors with the lowest 252-day log-return volatility, long-only, equal-weight and unleveraged, on USEQ daily bars.

There are no performance numbers. The strategy never passed verification, so no backtest report, optimization report or trade statistics exist.

Analysis

Volatility Effect in Stocks

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