Notebook

Can Warren Buffett Also Predict Equity Market Downturns?

SEBASTIEN LLEO and WILLIAM T. ZIEMBA

July 26, 2015

Abstract

In a 2001 interview, Warren Buffett suggested that the ratio of the market value of all publicly traded stocks to the Gross National Product could identify potential overvaluations and underval- uations in the US equity market. In this paper, we investigate whether this ratio is a statistically significant predictor of equity market downturns.

See also

Link to the original paper: http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2630068

Blog post on Alpha Architect: http://blog.alphaarchitect.com/2015/08/03/daily-academic-alpha-warren-buffett-market-predictions/

In [183]:
import pandas as pd
import numpy as np
import scipy as sp
from math import sqrt
import matplotlib.pyplot as pyplot
In [191]:
datasource = local_csv('MarketCap_GDP.csv', date_column='Month').sort_index(ascending=True)
mkt_gnp = datasource['Wilshire 5000']/datasource['GNP']
In [192]:
# Horizont in months, 60 months = 5 years
mkt_gnp_h=4

# Moving Average
mkt_gnp_mean=pd.rolling_mean(mkt_gnp, mkt_gnp_h)

# Moving Unbiased Standard Deviation (normalized by N-1 by default)
mkt_gnp_std=pd.rolling_std(mkt_gnp, mkt_gnp_h)

# Interval of Confidence 95%
mkt_gnp_threshold  = mkt_gnp_mean + 1.96 * mkt_gnp_std / sqrt(mkt_gnp_h)

data = pd.concat([mkt_gnp, mkt_gnp_mean, mkt_gnp_std, mkt_gnp_threshold], axis=1)
data.columns = ['MV t GNP', 'Mean', 'Std', 'Interval of Confidence 95%']
data
Out[192]:
MV t GNP Mean Std Interval of Confidence 95%
Month
1970-12-01 00:00:00+00:00 0.725000 NaN NaN NaN
1971-03-01 00:00:00+00:00 0.790825 NaN NaN NaN
1971-06-01 00:00:00+00:00 0.776280 NaN NaN NaN
1971-09-01 00:00:00+00:00 0.761026 0.763283 0.028273 0.790991
1971-12-01 00:00:00+00:00 0.764300 0.773107 0.013510 0.786347
1972-03-01 00:00:00+00:00 0.792599 0.773551 0.014292 0.787557
1972-06-01 00:00:00+00:00 0.775514 0.773360 0.014248 0.787323
1972-09-01 00:00:00+00:00 0.766719 0.774783 0.012818 0.787344
1972-12-01 00:00:00+00:00 0.783606 0.779610 0.011070 0.790458
1973-03-01 00:00:00+00:00 0.700819 0.756665 0.037864 0.793771
1973-06-01 00:00:00+00:00 0.630627 0.720443 0.069721 0.788770
1973-09-01 00:00:00+00:00 0.655578 0.692657 0.067234 0.758546
1973-12-01 00:00:00+00:00 0.570040 0.639266 0.054533 0.692708
1974-03-01 00:00:00+00:00 0.541042 0.599322 0.052911 0.651174
1974-06-01 00:00:00+00:00 0.468423 0.558771 0.077407 0.634630
1974-09-01 00:00:00+00:00 0.340308 0.479954 0.102439 0.580344
1974-12-01 00:00:00+00:00 0.361972 0.427936 0.093919 0.519977
1975-03-01 00:00:00+00:00 0.437797 0.402125 0.060832 0.461741
1975-06-01 00:00:00+00:00 0.486547 0.406656 0.067703 0.473005
1975-09-01 00:00:00+00:00 0.412291 0.424652 0.051915 0.475528
1975-12-01 00:00:00+00:00 0.426099 0.440684 0.032304 0.472342
1976-03-01 00:00:00+00:00 0.482211 0.451787 0.038095 0.489120
1976-06-01 00:00:00+00:00 0.479555 0.450039 0.036075 0.485393
1976-09-01 00:00:00+00:00 0.470644 0.464627 0.026158 0.490262
1976-12-01 00:00:00+00:00 0.473938 0.476587 0.005253 0.481735
1977-03-01 00:00:00+00:00 0.427128 0.462816 0.024075 0.486410
1977-06-01 00:00:00+00:00 0.428867 0.450144 0.025618 0.475250
1977-09-01 00:00:00+00:00 0.405691 0.433906 0.028694 0.462026
1977-12-01 00:00:00+00:00 0.397880 0.414891 0.015482 0.430064
1978-03-01 00:00:00+00:00 0.359958 0.398099 0.028630 0.426157
... ... ... ... ...
2007-09-01 00:00:00+00:00 1.032372 1.013905 0.022032 1.035496
2007-12-01 00:00:00+00:00 0.998040 1.014189 0.021745 1.035499
2008-03-01 00:00:00+00:00 0.888948 0.988211 0.068190 1.055037
2008-06-01 00:00:00+00:00 0.868948 0.947077 0.080323 1.025794
2008-09-01 00:00:00+00:00 0.809447 0.891346 0.078737 0.968508
2008-12-01 00:00:00+00:00 0.626172 0.798379 0.119667 0.915652
2009-03-01 00:00:00+00:00 0.562250 0.716704 0.145867 0.859654
2009-06-01 00:00:00+00:00 0.647093 0.661241 0.105189 0.764326
2009-09-01 00:00:00+00:00 0.740374 0.643972 0.073707 0.716205
2009-12-01 00:00:00+00:00 0.765504 0.678805 0.092913 0.769859
2010-03-01 00:00:00+00:00 0.805690 0.739665 0.067323 0.805641
2010-06-01 00:00:00+00:00 0.704576 0.754036 0.042554 0.795739
2010-09-01 00:00:00+00:00 0.773505 0.762319 0.042232 0.803706
2010-12-01 00:00:00+00:00 0.859277 0.785762 0.064660 0.849129
2011-03-01 00:00:00+00:00 0.898611 0.808992 0.087029 0.894280
2011-06-01 00:00:00+00:00 0.885145 0.854134 0.056176 0.909187
2011-09-01 00:00:00+00:00 0.737493 0.845131 0.073592 0.917251
2011-12-01 00:00:00+00:00 0.812876 0.833531 0.074273 0.906319
2012-03-01 00:00:00+00:00 0.905322 0.835209 0.076281 0.909965
2012-06-01 00:00:00+00:00 0.865958 0.830412 0.072610 0.901570
2012-09-01 00:00:00+00:00 0.910213 0.873592 0.045065 0.917756
2012-12-01 00:00:00+00:00 0.899968 0.895365 0.020046 0.915011
2013-03-01 00:00:00+00:00 0.989508 0.916412 0.052273 0.967639
2013-06-01 00:00:00+00:00 1.000035 0.949931 0.052123 1.001012
2013-09-01 00:00:00+00:00 1.043833 0.983336 0.060352 1.042481
2013-12-01 00:00:00+00:00 1.142834 1.044052 0.069930 1.112583
2014-03-01 00:00:00+00:00 1.150807 1.084377 0.074359 1.157249
2014-06-01 00:00:00+00:00 1.180673 1.129537 0.059412 1.187761
2014-09-01 00:00:00+00:00 1.161063 1.158844 0.016354 1.174871
2014-12-01 00:00:00+00:00 1.212180 1.176181 0.027009 1.202650

177 rows × 4 columns

In [193]:
plotdata = pd.concat([mkt_gnp, mkt_gnp_threshold], axis=1)
plotdata.columns=['MV to GNP','Interval of Confidence 95%']
plotdata
plot=plotdata.plot()

# S&P 500 Crashes between October 1, 1970 and March 31, 2015
plot.axvspan('1971-04-28', '1971-11-23', color='gray', alpha=0.5, lw=0)
plot.axvspan('1973-01-11', '1974-10-03', color='gray', alpha=0.5, lw=0)
plot.axvspan('1975-07-15', '1975-09-16', color='gray', alpha=0.5, lw=0)
plot.axvspan('1976-09-21', '1978-03-06', color='gray', alpha=0.5, lw=0)
plot.axvspan('1978-09-12', '1978-11-14', color='gray', alpha=0.5, lw=0)
plot.axvspan('1979-10-05', '1979-11-07', color='gray', alpha=0.5, lw=0)
plot.axvspan('1980-02-13', '1980-03-27', color='gray', alpha=0.5, lw=0)
plot.axvspan('1980-11-28', '1981-09-25', color='gray', alpha=0.5, lw=0)
plot.axvspan('1983-10-10', '1984-07-24', color='gray', alpha=0.5, lw=0)
plot.axvspan('1987-08-25', '1987-12-04', color='gray', alpha=0.5, lw=0)
plot.axvspan('1989-10-09', '1990-01-30', color='gray', alpha=0.5, lw=0)
plot.axvspan('1990-07-16', '1990-10-11', color='gray', alpha=0.5, lw=0)
plot.axvspan('1997-10-07', '1997-10-27', color='gray', alpha=0.5, lw=0)
plot.axvspan('1998-07-17', '1998-08-31', color='gray', alpha=0.5, lw=0)
plot.axvspan('1999-07-16', '1999-10-15', color='gray', alpha=0.5, lw=0)
plot.axvspan('2000-03-24', '2001-04-04', color='gray', alpha=0.5, lw=0)
plot.axvspan('2007-10-09', '2009-03-09', color='gray', alpha=0.5, lw=0)
plot.axvspan('2010-04-23', '2010-07-02', color='gray', alpha=0.5, lw=0)
plot.axvspan('2011-04-29', '2011-10-03', color='gray', alpha=0.5, lw=0)

# 80% level 
plot.axhline(y=0.8, color='r')

# 120% level 
plot.axhline(y=1.2, color='g')
plot.plot(mkt_gnp_mean)

# Draw a marker at the signal points
# The signal indicator S t takes the value 1 if the measure crosses the threshold on quarter t ...
s0 = mkt_gnp > mkt_gnp_threshold
# ... but not on quarter t − 1, and 0 otherwise.
s1 = mkt_gnp.shift(1) < mkt_gnp_threshold.shift(1)
signals = s0 & s1
signals_index = mkt_gnp[signals].index
pyplot.plot(signals_index, mkt_gnp[signals_index], 'D', markersize=5, color='b')
print "Number of signals: %d" % len(mkt_gnp[signals_index])
Number of signals: 29