Sector Mean Reversion: Buying What the Market Hates Worked for 26
We tested a simple contrarian idea on US stocks from 2000 to 2025: at the start of each quarter, find the two worst-performing sectors by 12-month return and buy every large-cap stock in them. Quarterly rebalance, equal weight, 104 periods. The result was 10.59% annualized vs 8.02% for the S&P 500, a 1270% total return, and a portfolio that was fully invested in 101 of 104 quarters. The strategy works because beaten-down sectors tend to recover. It fails when they keep falling.
Contents
- Method
- What is Sector Mean Reversion?
- The Screen
- What We Found
- 26 years. +2.57% annual alpha over the S&P 500.
- Year-by-year returns
- 2000-2003: The strategy's clearest demonstration
- 2009: The other great year
- 2015: The worst year
- 2020: Tech-driven market, strategy misses it
- Backtest Methodology
- Limitations
- Takeaway
- Part of a Series
- References
- Run This Screen Yourself
Method
- Data source: Ceta Research (FMP financial data warehouse)
- Universe: NYSE + NASDAQ + AMEX, market cap > $1B USD
- Period: 2000-2025 (26 years, 104 quarterly periods)
- Rebalancing: Quarterly (January, April, July, October), equal weight all qualifying stocks in selected sectors
- Benchmark: S&P 500 Total Return (SPY)
- Cash rule: Hold cash if fewer than 5 stocks qualify across the bottom 2 sectors
What is Sector Mean Reversion?
The idea is straightforward. At each quarterly rebalance, we rank all sectors by their equal-weighted 12-month trailing return. We buy every stock in the bottom 2 sectors. Next quarter, we re-rank and rotate.
The academic foundation is Moskowitz and Grinblatt (1999), who showed that much of the momentum anomaly is explained by industry-level momentum. The corollary: when industry-level momentum is negative enough, mean reversion tends to follow. Sectors that underperform for a full year carry two things, suppressed valuations and depressed sentiment. Both tend to normalize over the following 12 months.
The mechanics are different from stock-level mean reversion. You're not picking individual oversold names. You're tilting the entire portfolio toward the most out-of-favor corners of the market. With an average of 603 stocks per quarter across the two selected sectors, this is a broad bet on sector sentiment normalization, not a concentrated value play.
The sectors that show up most often in the bottom 2 tell the story:
| Sector | Quarters Selected (of 104) |
|---|---|
| Utilities | 32 |
| Energy | 29 |
| Real Estate | 26 |
| Basic Materials | 21 |
| Communication Services | 20 |
| Technology | 20 |
Utilities and Energy dominate. These are capital-intensive, rate-sensitive sectors that cycle in and out of favor. Real Estate follows the same pattern. What rarely shows up: Consumer Discretionary and Healthcare, which tend to hold their own even in down markets.
The Screen
The screen below runs live. It ranks sectors by their current 12-month equal-weighted return across NYSE, NASDAQ, and AMEX large caps. The bottom rows are what the backtest would buy today.
WITH prices AS (
SELECT e.symbol, e.adjClose, CAST(e.date AS DATE) AS trade_date
FROM stock_eod e
JOIN profile p ON e.symbol = p.symbol
WHERE p.sector IS NOT NULL AND p.sector != ''
AND p.marketCap > 1000000000
AND p.exchange IN ('NYSE', 'NASDAQ', 'AMEX')
AND CAST(e.date AS DATE) >= CURRENT_DATE - INTERVAL '400' DAY
AND e.adjClose IS NOT NULL AND e.adjClose > 0
),
recent AS (
SELECT symbol, adjClose AS recent_price
FROM prices
QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY trade_date DESC) = 1
),
year_ago AS (
SELECT symbol, adjClose AS old_price
FROM prices
WHERE trade_date <= CURRENT_DATE - INTERVAL '252' DAY
QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY trade_date DESC) = 1
),
stock_returns AS (
SELECT r.symbol, pr.sector, (r.recent_price / ya.old_price - 1) * 100 AS return_12m
FROM recent r
JOIN year_ago ya ON r.symbol = ya.symbol
JOIN profile pr ON r.symbol = pr.symbol
WHERE ya.old_price > 0 AND r.recent_price > 0
AND (r.recent_price / ya.old_price - 1) BETWEEN -0.99 AND 5.0
)
SELECT pr.sector,
ROUND(AVG(sr.return_12m), 2) AS avg_return_12m_pct,
COUNT(DISTINCT sr.symbol) AS n_stocks,
ROW_NUMBER() OVER (ORDER BY AVG(sr.return_12m) ASC) AS rank_worst
FROM stock_returns sr
JOIN profile pr ON sr.symbol = pr.symbol
GROUP BY pr.sector
HAVING COUNT(DISTINCT sr.symbol) >= 5
ORDER BY avg_return_12m_pct ASC
Run this screen on Ceta Research
What We Found
The strategy outperformed in bear markets and crashed harder in the worst downturns. That's the tradeoff in buying beaten-down sectors: you get the recoveries and you absorb the extended declines.

26 years. +2.57% annual alpha over the S&P 500.
| Metric | Strategy | S&P 500 |
|---|---|---|
| CAGR | 10.59% | 8.02% |
| Total Return | 1270% | — |
| Volatility | 26.94% | — |
| Max Drawdown | -48.3% | -45.5% |
| Sharpe Ratio | 0.319 | 0.357 |
| Win Rate vs SPY | 55.8% | — |
| Up Capture | 131.6% | — |
| Down Capture | 113.7% | — |
| Avg Stocks per Period | 603.7 | — |
| Cash Periods | 3 of 104 | — |
A few numbers worth holding together. The strategy beats the S&P 500 by 2.57% annually over 26 years, with a higher up capture (131.6%) and a higher down capture (113.7%). You get more of the upside and more of the downside. The Sharpe ratio (0.319 vs 0.357) is actually lower than the benchmark, the excess return comes with excess volatility. This is a high-beta contrarian tilt, not a smooth ride.
The win rate of 55.8% means the strategy beat SPY in roughly 6 of every 11 quarters. That's a real edge, but there are long stretches where it doesn't show up.
Year-by-year returns

| Year | Strategy | S&P 500 | Excess |
|---|---|---|---|
| 2000 | +10.55% | -10.50% | +21.05% |
| 2001 | +23.85% | -9.17% | +33.02% |
| 2002 | -13.18% | -19.92% | +6.74% |
| 2003 | +62.53% | +24.12% | +38.41% |
| 2004 | +11.25% | +10.24% | +1.02% |
| 2005 | +8.72% | +7.17% | +1.55% |
| 2006 | +24.05% | +13.65% | +10.41% |
| 2007 | +1.56% | +4.40% | -2.85% |
| 2008 | -39.48% | -34.31% | -5.17% |
| 2009 | +66.01% | +24.73% | +41.28% |
| 2010 | +14.81% | +14.31% | +0.51% |
| 2011 | +6.24% | +2.46% | +3.77% |
| 2012 | +17.58% | +17.09% | +0.49% |
| 2013 | +19.43% | +27.77% | -8.34% |
| 2014 | +7.34% | +14.50% | -7.15% |
| 2015 | -28.35% | -0.12% | -28.22% |
| 2016 | +26.56% | +14.45% | +12.11% |
| 2017 | +25.61% | +21.64% | +3.97% |
| 2018 | -3.56% | -5.15% | +1.59% |
| 2019 | +30.35% | +32.31% | -1.97% |
| 2020 | -0.78% | +15.64% | -16.42% |
| 2021 | +30.66% | +31.26% | -0.60% |
| 2022 | -22.04% | -18.99% | -3.05% |
| 2023 | +25.16% | +26.00% | -0.84% |
| 2024 | +22.31% | +25.28% | -2.97% |
| 2025 | +13.70% | +17.88% | -4.18% |
2000-2003: The strategy's clearest demonstration
When the dot-com bubble burst, the market rotated hard into the sectors that tech investors had ignored for years. Utilities and Energy were cheap on fundamentals and hated on momentum. The strategy loaded up on both.
2000: +10.55% vs SPY -10.50%. The market was selling tech. The strategy was buying utilities. 2001: +23.85% vs SPY -9.17%. A second straight year of large outperformance as beaten-down defensives kept recovering. 2002: -13.18% vs SPY -19.92%. Even in the final leg of the crash, the portfolio held up better. 2003: +62.53% vs SPY +24.12%. Post-dot-com recovery, beaten-down cyclicals that had been left for dead surged. The three-year cumulative gap over the S&P 500 was enormous.
This is the strategy working exactly as designed. Sectors that fell hardest during the bubble came back first when sentiment normalized.
2009: The other great year
2009 produced +66.01% vs the S&P 500's +24.73%, a 41-point gap. After the financial crisis, the strategy had rotated into Real Estate and Financial Services, the sectors most demolished by the crash. When those sectors recovered, the rebound was violent.
The pattern is the same as 2003: buy what was destroyed, wait for the recovery. The strategy doesn't predict the recovery. It just systematically positions in the sectors most likely to mean-revert if recovery happens.
2015: The worst year
2015 was -28.35% against a near-flat SPY (-0.12%). The 28-point gap is the largest single-year underperformance in the 26-year record.
The culprit was Energy. Oil prices began their serious decline in mid-2014. By the start of 2015, Energy was one of the worst-performing sectors over the prior 12 months, exactly the trigger for the strategy to load up on it. Oil then kept falling throughout 2015. The sector that looked like it should revert kept declining. That's the core risk in mean reversion: you buy at the first sign of cheapness, but there may be more downside ahead.
2016 told the other side: +26.56% vs SPY +14.45%, driven partly by Energy's actual recovery once oil stabilized. You had to hold through the pain to get the gain.
2020: Tech-driven market, strategy misses it
2020 was flat for the strategy (-0.78%) while SPY returned +15.64%. The COVID crash was brief and violent, followed by a recovery driven almost entirely by tech and growth stocks. The sector mean reversion approach wasn't positioned for that. The bottom sectors in early 2020 included Energy (oil went negative in April) and sectors that didn't recover quickly. The strategy sat out the tech-driven bounce.
Backtest Methodology
| Parameter | Choice |
|---|---|
| Universe | NYSE + NASDAQ + AMEX, Market Cap > $1B USD |
| Signal | Bottom 2 sectors by equal-weighted 12-month trailing return |
| Portfolio | All qualifying stocks in selected sectors, equal weight |
| Rebalancing | Quarterly (January, April, July, October) |
| Cash rule | Hold cash if < 5 stocks qualify |
| Benchmark | S&P 500 Total Return (SPY) |
| Period | 2000-2025 (26 years, 104 quarters) |
| Data | Ceta Research (FMP financial data warehouse) |
Limitations
Sector momentum can persist. The biggest risk here isn't model risk. It's the scenario where a sector underperforms for structural reasons, not cyclical ones. Energy in 2015 and 2020 is the cleanest example. The strategy assumes underperformance is temporary. Sometimes it isn't.
High volatility, lower Sharpe. At 26.94% annualized volatility and a Sharpe of 0.319, this is a bumpier ride than the market. You earn the alpha, but you feel it in drawdowns. The -48.3% max drawdown exceeds the S&P 500's -45.5%.
Large portfolio, diffuse bets. With 603 stocks on average, the strategy is closer to a sector tilt than a stock-picking approach. You're making a macro bet on two sectors normalizing. Individual stock selection doesn't matter much. That's a feature for some investors and a limitation for others.
Down capture > 100%. The strategy captured 113.7% of SPY's downside. In bad markets, it tends to fall harder. The positive alpha comes from the recoveries being even stronger (131.6% up capture), but the sequence of returns matters. A retiree drawing down a portfolio feels bad years more acutely than good ones.
No transaction costs. The backtest doesn't include transaction costs or market impact. With 603 stocks and quarterly rebalancing, turnover is meaningful. Real-world execution would reduce returns.
Survivorship bias. Exchange membership uses current profiles, not historical. Delisted companies (including failures) aren't tracked over time.
Takeaway
Sector mean reversion works on US stocks over 26 years. 10.59% CAGR, +2.57% annual alpha, 1270% total return. The strategy earns its keep by systematically buying what the market has rejected at the sector level and waiting for sentiment to normalize.
The trade-off is clear. You get higher up capture (131.6%) and higher down capture (113.7%). The Sharpe ratio is lower than the benchmark. The max drawdown is worse. A year like 2015 (-28.35%) can erase multiple years of alpha in a single period.
The strategy suits investors who can tolerate a volatile ride and who believe that sector-level dislocations eventually correct. The 26-year record suggests they usually do. But "usually" isn't "always," and the worst years come when the market tells a new structural story that the backward-looking signal misses.
Part of a Series
This analysis is part of our Sector Mean Reversion global exchange comparison. We tested the same strategy across multiple exchanges: - Sector Mean Reversion on Indian Stocks (BSE + NSE) - Sector Mean Reversion on Korean Stocks (KSC) - Sector Mean Reversion on Taiwanese Stocks (TAI + TWO) - Sector Mean Reversion on Swedish Stocks (STO) - Sector Mean Reversion: Global Exchange Comparison
References
- Moskowitz, T. & Grinblatt, M. (1999). "Do Industries Explain Momentum?" Journal of Finance, 54(4), 1249-1290.
Run This Screen Yourself
Via web UI: Run the sector screen on Ceta Research. The query is pre-loaded. Hit "Run" to see current sector rankings.
Via Python:
import requests, time
API_KEY = "your_api_key" # get one at cetaresearch.com
BASE = "https://tradingstudio.finance/api/v1"
query = """
WITH prices AS (
SELECT e.symbol, e.adjClose, CAST(e.date AS DATE) AS trade_date
FROM stock_eod e
JOIN profile p ON e.symbol = p.symbol
WHERE p.sector IS NOT NULL AND p.sector != ''
AND p.marketCap > 1000000000
AND p.exchange IN ('NYSE', 'NASDAQ', 'AMEX')
AND CAST(e.date AS DATE) >= CURRENT_DATE - INTERVAL '400' DAY
AND e.adjClose IS NOT NULL AND e.adjClose > 0
),
recent AS (
SELECT symbol, adjClose AS recent_price
FROM prices
QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY trade_date DESC) = 1
),
year_ago AS (
SELECT symbol, adjClose AS old_price
FROM prices
WHERE trade_date <= CURRENT_DATE - INTERVAL '252' DAY
QUALIFY ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY trade_date DESC) = 1
),
stock_returns AS (
SELECT r.symbol, pr.sector,
(r.recent_price / ya.old_price - 1) * 100 AS return_12m
FROM recent r
JOIN year_ago ya ON r.symbol = ya.symbol
JOIN profile pr ON r.symbol = pr.symbol
WHERE ya.old_price > 0 AND r.recent_price > 0
AND (r.recent_price / ya.old_price - 1) BETWEEN -0.99 AND 5.0
)
SELECT pr.sector,
ROUND(AVG(sr.return_12m), 2) AS avg_return_12m_pct,
COUNT(DISTINCT sr.symbol) AS n_stocks,
ROW_NUMBER() OVER (ORDER BY AVG(sr.return_12m) ASC) AS rank_worst
FROM stock_returns sr
JOIN profile pr ON sr.symbol = pr.symbol
GROUP BY pr.sector
HAVING COUNT(DISTINCT sr.symbol) >= 5
ORDER BY avg_return_12m_pct ASC
"""
resp = requests.post(f"{BASE}/data-explorer/execute", headers={
"X-API-Key": API_KEY, "Content-Type": "application/json"
}, json={
"query": query,
"options": {"format": "json", "limit": 100},
"resources": {"memoryMb": 16384, "threads": 6}
})
task_id = resp.json()["taskId"]
while True:
result = requests.get(f"{BASE}/tasks/data-query/{task_id}",
headers={"X-API-Key": API_KEY}).json()
if result["status"] in ("completed", "failed"):
break
time.sleep(2)
print("Sector rankings (worst to best, 12-month return):")
for r in result["result"]["rows"]:
flag = " <-- BUY" if r["rank_worst"] <= 2 else ""
print(f"#{r['rank_worst']} {r['sector']:30s} {r['avg_return_12m_pct']:+.1f}% ({r['n_stocks']} stocks){flag}")
Get your API key at cetaresearch.com. The full backtest code (Python + DuckDB) is on GitHub.
Data: Ceta Research, FMP financial data warehouse. Universe: NYSE + NASDAQ + AMEX. Quarterly rebalance, equal weight, 2000-2025.