Sector Rotation and Market Breadth

Sector Rotation and Market Breadth

Sector rotation is the strategy of shifting investment between economic sectors as market conditions change. Different sectors perform best at different stages of the economic cycle: defensive sectors (utilities, healthcare) outperform during recessions; cyclical sectors (technology, consumer discretionary) lead during expansions.

Market breadth measures the overall health of the market — not just whether major indexes are up, but whether most stocks are participating in the move. Narrow breadth (only a handful of large stocks rising) often precedes market corrections.

Sector Rotation Theory

The economic cycle typically moves through phases:

Cycle Phase Leading Sectors
Early expansion Technology, Consumer Discretionary
Mid expansion Industrials, Materials
Late expansion Energy, Healthcare
Recession Utilities, Consumer Staples

By measuring which sectors are outperforming, you can identify which phase of the cycle we're in — and position accordingly.

Step 1 — Sector Performance Comparison

Computing returns by sector requires weighting individual stock returns appropriately. An equally-weighted sector average treats a $1B market cap company the same as a $1T one — simple but useful as a starting point.

WITH stock_returns AS (
    SELECT
        sp.company_id,
        sp.price_date,
        (sp.close_price - LAG(sp.close_price) OVER (PARTITION BY sp.company_id ORDER BY sp.price_date))
        / NULLIF(LAG(sp.close_price) OVER (PARTITION BY sp.company_id ORDER BY sp.price_date), 0) AS daily_return
    FROM stock_prices sp
    WHERE sp.price_date >= CURRENT_DATE - INTERVAL '90 days'
),
sector_returns AS (
    SELECT
        c.sector,
        DATE_TRUNC('month', sr.price_date) AS month,
        COUNT(DISTINCT sr.company_id) AS stocks,
        ROUND((AVG(sr.daily_return) * 21 * 100)::NUMERIC, 2) AS approx_monthly_return_pct,
        ROUND((STDDEV(sr.daily_return) * SQRT(252) * 100)::NUMERIC, 2) AS annualized_vol_pct
    FROM stock_returns sr
    JOIN companies c ON c.company_id = sr.company_id
    WHERE sr.daily_return IS NOT NULL
    GROUP BY c.sector, DATE_TRUNC('month', sr.price_date)
)
SELECT *,
    RANK() OVER (PARTITION BY month ORDER BY approx_monthly_return_pct DESC) AS sector_rank_this_month
FROM sector_returns
ORDER BY month, sector_rank_this_month;

What This Returns

Monthly sector performance rankings. sector_rank_this_month = 1 is the best-performing sector in that month. Tracking how the rank changes month-to-month reveals rotation — Technology leading for months, then Energy taking over, for example. annualized_vol_pct shows which sectors are riskiest.

Purchase this course to unlock the full lesson.

Sign up