Price Return vs Total Return: The Real Gap
Annualized price return vs total return over ten years: seven household names, to July 31, 2026ranking ·
2026-08-03 · 7×4
$10,000 in the S&P 500 tracker: price only vs dividends reinvested, year-end 2006 to July 2026ranking ·
2026-08-03 · 20×4
Price return vs total return by holding period: S&P 500 tracker, windows ending July 31, 2026ranking ·
2026-08-03 · 5×4
S&P 500 tracker by calendar year: price return vs the points added by reinvested dividendsranking ·
2026-08-03 · 20×3
Annualized price return vs total return over ten years: seven household names, to July 31, 2026
Annualized price return vs total return over ten years: seven household names, to July 31, 2026
| ticker | price_cagr_pct | total_cagr_pct | dividend_points_pct |
|---|---|---|---|
| VZ | -1.51 | 3.96 | 5.46 |
| XOM | 6.11 | 10.82 | 4.71 |
| KO | 7.26 | 10.66 | 3.4 |
| JNJ | 7.42 | 10.39 | 2.98 |
| PG | 5.28 | 8.19 | 2.91 |
| SPY | 13.16 | 15 | 1.84 |
| MSFT | 23.45 | 24.98 | 1.53 |
the exact SQL behind every number
WITH daily AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS d,
argMax(toFloat64(close), window_start) AS close
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'KO', 'JNJ', 'XOM', 'PG', 'VZ', 'MSFT')
AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2016-08-01')
AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, d
),
px AS (
SELECT ticker,
argMin(close, d) AS start_px,
argMax(close, d) AS end_px
FROM daily
GROUP BY ticker
),
divs AS (
SELECT dv.ticker AS ticker,
exp(sum(log(1 + toFloat64(dv.cash_amount) / dl.close))) AS factor
FROM global_markets.stocks_dividends AS dv
INNER JOIN daily AS dl ON dl.ticker = dv.ticker AND dl.d = dv.ex_dividend_date
WHERE dv.ticker IN ('SPY', 'KO', 'JNJ', 'XOM', 'PG', 'VZ', 'MSFT')
AND dv.cash_amount > 0
AND dv.ex_dividend_date >= toDate('2016-08-01')
AND dv.ex_dividend_date <= toDate('2026-07-31')
GROUP BY dv.ticker
)
SELECT px.ticker AS ticker,
round(100 * (pow(px.end_px / px.start_px, 0.1) - 1), 2) AS price_cagr_pct,
round(100 * (pow(px.end_px / px.start_px * divs.factor, 0.1) - 1), 2) AS total_cagr_pct,
round(100 * (pow(px.end_px / px.start_px * divs.factor, 0.1)
- pow(px.end_px / px.start_px, 0.1)), 2) AS dividend_points_pct
FROM px
INNER JOIN divs ON px.ticker = divs.ticker
ORDER BY dividend_points_pct DESC
More from this analysisPrice Return vs Total Return: The Real Gap
$10,000 in the S&P 500 tracker: price only vs dividends reinvested, year-end 2006 to July 2026
ranking 20×4
→
S&P 500 tracker by calendar year: price return vs the points added by reinvested dividends
ranking 20×3
→
Price return vs total return by holding period: S&P 500 tracker, windows ending July 31, 2026
ranking 5×4
→
SPY distributions per share and price, both rebased to 100 at 2015
ranking 11×3
→
See all 2,170 queries →