Blogs

Calculating CPI adjusted All Time S&P 500 Returns

For the analysis, each year's ending S&P 500 price and that year's average CPI value will be used. 

Data source for historical sp& closing prices: https://www.macrotrends.net/2324/sp-500-historical-chart-data

Data source for historical CPI: https://www.minneapolisfed.org/about-us/monetary-policy/inflation-calculator/consumer-price-index-1913-

These libraries will be needed:

import pandas as pd
import matplotlib.pyplot as plt

First, get the data from web sources:

src_sp500 = "https://www.macrotrends.net/2324/sp-500-historical-chart-data"
tables_sp = pd.read_html(src_sp500)
sp500 = tables_sp[0]['S&P 500 Index - Historical Annual Data'].sort_values('Year').set_index('Year')

src_cpi = "https://www.minneapolisfed.org/about-us/monetary-policy/inflation-calculator/consumer-price-index-1913-"
tables_cpi = pd.read_html(src_cpi)
cpi = tables_cpi[0][['Year', 'Annual Average CPI(-U)']].set_index('Year')
cpi.index = cpi.index.str.strip('*').astype(int)

Calculate adjusted prices and normalize prices for comparison:

adj_sp = pd.concat([cpi[['Annual Average CPI(-U)']],sp500[['Year Close']]], axis=1).dropna()
adj_sp.columns = ['cpi', 'close']

adj_sp['adj_close'] = adj_sp['close'] / adj_sp.cpi
adj_sp['norm_nom'] = adj_sp['close'] / adj_sp['close'].iloc[0]
adj_sp['norm_adj'] = adj_sp['adj_close'] / adj_sp['adj_close'].iloc[0]

Use log scale graph for visualization:

adj_sp[['norm_nom', 'norm_adj']].plot()
plt.yscale('log')
plt.title('CPI Adjusted vs. Nominal S&P500')
plt.show()

Calculate the average return over time (exluding dividends):

adj_sp['adj_change'] = adj_sp['adj_close'].pct_change()
adj_sp['nom_change'] = adj_sp['close'].pct_change()

CPI adjusted avg annual return: 4.29 %
Nominal avg annual return: 7.42 %