Section A.1 The Dow Jones
The MeasuringWorth Foundation has compiled the value of the Dow Jones Industrial Average at the end of each day from February 16, 1885 to the present, with adjustments at several points to make the values comparable. The following cells download and read this data.
DATA_PATH = "https://github.com/AllenDowney/ThinkStats/raw/v3/data/"
filename = "DJA.csv"
download(DATA_PATH + filename)
$ djia = pd.read_csv(filename, skiprows=4, parse_dates=[0], index_col=0)
djia.head()
DJIA
Date
1885-02-16 30.9226
1885-02-17 31.3365
1885-02-18 31.4744
1885-02-19 31.6765
1885-02-20 31.4252
To compute annual returns, weโll start by selecting the closing price on the last trading day of each year (dropping 2024 because we donโt have a complete year).
$ annual = djia.groupby(djia.index.year).last().drop(2024)
annual
DJIA
Date
1885 39.4859
1886 41.2391
1887 37.7693
1888 39.5866
1889 42.0394
... ...
2019 28538.4400
2020 30606.4800
2021 36338.3000
2022 33147.2500
2023 37689.5400
[139 rows x 1 columns]
Next weโll compute the annual price return, which is the ratio of successive year-end closing prices.
$ annual['Ratio'] = annual['DJIA'] / annual['DJIA'].shift(1)
annual
DJIA Ratio
Date
1885 39.4859 NaN
1886 41.2391 1.044401
1887 37.7693 0.915861
1888 39.5866 1.048116
1889 42.0394 1.061960
... ... ...
2019 28538.4400 1.223384
2020 30606.4800 1.072465
2021 36338.3000 1.187275
2022 33147.2500 0.912185
2023 37689.5400 1.137034
[139 rows x 2 columns]
And the relative return as a percentage.
annual['Return'] = (annual['Ratio'] - 1) * 100
Looking at the years with the biggest losses and gains, we can see that most of the extremes were before the 1960sโwith the exception of the 2008 financial crisis.
$ annual.dropna().sort_values(by='Return')
DJIA Ratio Return
Date
1931 77.9000 0.473326 -52.667396
1907 43.0382 0.622683 -37.731743
2008 8776.3900 0.661629 -33.837097
1930 164.5800 0.662347 -33.765293
1920 71.9500 0.670988 -32.901240
... ... ... ...
1954 404.3900 1.439623 43.962264
1908 63.1104 1.466381 46.638103
1928 300.0000 1.482213 48.221344
1933 99.9000 1.666945 66.694477
1915 99.1500 1.816599 81.659949
[138 rows x 3 columns]
Hereโs what the distribution of annual returns looks like.
from empiricaldist import Cdf
cdf_return = Cdf.from_seq(annual['Return'])
cdf_return.plot()
decorate(xlabel='Annual return (percent)', ylabel='CDF')
Immediately we see why capping returns at 10% might be a bad ideaโthis cap is exceeded almost 45% of the time, and sometimes by a lot!
$ 1 - cdf_return(10)
0.4492753623188406
