Lukas Püttmann    About    Blog

Term spreads and business cycles 3: The view from history

In the first installment in this series, I documented that term spreads tend to fall before recessions. In the second part I looked at monetary policy and showed that it’s the endogenous reaction of monetary policy that investors predict. I worked with post-war data for the US in both parts, but we can extend this analysis across countries and use longer time series.

Start a new analysis and load some packages


The dataset by Jordà, Taylor and Schularick (2016) is great and provides annual macroeconomic and financial variables for 17 countries since 1870. We can use the Stata dataset from their website like this:

mh <- read_dta("")
lbls <- data.frame(var = names(mh),
                   label = vapply(mh, attr, FUN.VALUE = "character",
                                  "label", USE.NAMES = FALSE),
                   stringsAsFactors = FALSE)

mh <- suppressWarnings(tidyr::gather(mh, var, value, -year, -country, -iso, -ifs))
mh <- merge(mh, lbls)
mh <- mh[, c("year", "country", "iso", "ifs", "var", "label", "value")]
mh <- structure(mh, class = c("tbl_mh", class(mh)))
mh$value[is.nan(mh$value)] <- NA

Importing Stata datasets with the haven package is pretty neat. In the RStudio environment, the columns even display the original Stata labels.

There are two interest rate series in the data and the documentation explains that most short-term rates are a mix of money market rates, bank lending rates and government bonds. Long-term rates are mostly government bonds.

Homer and Sylla (2005) explain why we usually study safe rates:

The method of using minimum rates to determine interest rate trends is informative. Today the use of „prime rates“ and AAA averages is customary to indicate interest rate trends. There is a very large range of rates higher than minimum rates at all times, and there is no top limit except legal maxima. Averages of rates, if the did exist, might be merely averages of good credits with bad credits. The lowest regularly reported rates, excluding eccentric rates, comprise a practical limit comparable over time. Minimum rates will not show us where most funds were lending, but they should provide a fair index number for measuring long-term interest rate trends. (p.140)


The level of interest rates is a more complex concept than the trend of interest rates. (p.555)

So let’s plot those interest rates:

mh %>% 
  filter(var %in% c("stir", "ltrate")) %>% 
  ggplot(aes(year, value / 100, color = var)) +
  geom_hline(yintercept = 0, size = 0.3, color = "grey80") +
  geom_line() +
  facet_wrap(~country, scales = "free_y", ncol = 3) +
  theme_tufte(base_family = "Helvetica") +
  scale_y_continuous(labels=percent) +
  labs(y = "Interest rate", 
       title = "Long-term and short-term interest rates over the long run",
       subtitle = "1870-2013, nominal rates in percent per year.",
       caption = "Source:",
       color = "Interest rate:") +
  theme(legend.position = c(0.85, 0.05)) +
  scale_color_manual(labels = c("long-term", "short-term"), 
                     values = c("#ef8a62", "#67a9cf"))

Which gets us:

Long-term and short-term interest rates for 17 countries since 1870

Interest rates were high everywhere during the 1980s when inflation ran high. Rates were quite low in the 19th century. There are also some interesting movements in the 1930s.

Next, select GDP and interest rates, calculate the term spread and lag it:

df <- mh %>% 
  select(-label) %>% 
  filter(var %in% c("rgdpmad", "stir", "ltrate")) %>% 
  spread(var, value) %>% 
  mutate(trm_spr = ltrate - stir) %>% 
  arrange(country, year) %>% 
  mutate(trm_spr_l = dplyr::lag(trm_spr, 1),
         gr_real = 100*(rgdpmad - dplyr::lag(rgdpmad, 1)) / dplyr::lag(rgdpmad, 1))

Add a column of 1, 2, … T for numerical dates:

df <- df %>% 
  left_join(tibble(year = min(df$year):max(df$year), 
                   numdate = 1:length(min(df$year):max(df$year))))

Check for extreme GDP events (to potentially exclude them):

df <- df %>%
  mutate(outlier_gr_real = ifelse((abs(gr_real) > 15) | (abs(gr_real) < -15), 
                                 TRUE, FALSE))

Scatter the one-year-before term spread against subsequent real GDP growth:

df %>% 
  filter(!outlier_gr_real) %>% 
  ggplot(aes(gr_real / 100, trm_spr_l / 100)) +
  geom_hline(yintercept = 0, size = 0.3, color = "grey50") +
  geom_vline(xintercept = 0, size = 0.3, color = "grey50") +
  geom_smooth(method = "lm", size = 0.3, color = "#b2182b", fill = "#fddbc7") +
  geom_jitter(aes(color = numdate), size = 1, alpha = 0.6, stroke = 0,
              show.legend = FALSE) +
  facet_wrap(~country, scales = "free", ncol = 3) +
  theme_tufte(base_family = "Helvetica") +
  scale_y_continuous(labels=percent) +
  scale_x_continuous(labels=percent) +
  labs(title = "Lagged term spread vs. real GDP growth",
       subtitle = "1870-2013, annually.",
       caption = "Source:",
       x = "Real GDP growth",
       y = "Term spread")

Which creates:

Lagged term spread against real GDP growth

Lighter shades of blue in the markers signal earlier dates. The clouds are quite mixed, so correlations don’t seem to just portray time trends in the variables.

The relationship doesn’t look as clearly positive as in our previous analysis. Let’s dig in further using a panel regression. I estimate two models where the second excludes outliers as defined above. I also control for time and country fixed effects.

r1 <- plm(gr_real ~ trm_spr_l, 
          data = df, 
          index = c("country", "year"), 
          model = "within", 
          effect = 'twoways')

r2 <- df %>% 
  filter(!outlier_gr_real) %>% 
  plm(gr_real ~ trm_spr_l, 
      data = ., 
      index = c("country", "year"), 
      model = "within", 
      effect = 'twoways')

stargazer(r1, r2, type = "html")

This produces:

Dependent variable:
Real GDP growth
Term spread (lagged)0.108*0.120**
Adjusted R2-0.075-0.074
F Statistic3.474* (df = 1; 2097)6.627** (df = 1; 2055)
Note:*p<0.1; **p<0.05; ***p<0.01

So also using this dataset we find that lower term spreads tend to be followed by recessions.


Homer, S. and R. Sylla (2005). A History of Interest Rates, Fourth Edition. Wiley Finance.

Jordà, O. M. Schularick and A. M. Taylor (2017). “Macrofinancial History and the New Business Cycle Facts”. NBER Macroeconomics Annual 2016, volume 31, edited by Martin Eichenbaum and Jonathan A. Parker. Chicago: University of Chicago Press. (link)

Related posts: