flowchart LR A(Theory) --> B(Empirical model) B --> C(Data) C --> D{Estimation} D --> E[Estimated probability] D --> F[Forecast probability]
1 Introduction
Financial securities prices and yields are thought to contain information about investors’ expectations of the future. In this exercise we will extract information from the yield curve that is useful in forecasting the probability of a future recession. We will apply this idea to the U.S. economy as it is easy for us to obtain a long sample of good data for our analysis.
In the U.S. a recession can be defined as “a significant decline in economic activity that is spread across the economy and lasts more than a few months” (see NBER Business Cycle Dating). The definition of a recession is similar in other countries. For example it is often defined as two consecutive quarters of negative GDP growth.
One of the most important variables forecast by economists is the level of a country’s future economic activity. Governments and central banks require forecasts of future GDP growth for setting economic policy. Banks and other participants in financial markets use forecasts of economic activity to help formulate investment strategies. Large companies use forecasts of growth as an input into their operational and investment strategies. In particular, policy makers, investors and corporate decision-makers want to know what the risk is that the economy may contract in the future.
In the late 1980s, economists came across an intriguing relationship between the slope of the yield curve and future economic growth and the likelihood of a future recession. “[E]very U.S. recession since 1950 has been preceded by a sharp drop in the yield curve spread, the difference between long- and short-term interest rates” (Estrella (2005)). Early research examining the relationship for the U.S. includes Harvey (1989) and Estrella and Hardouvelis (1991). More recent research examines more detailed models (Cooper, Fuhrer, and Olivei (2020)) and panel analysis over several countries (Hasse and Lajaunie (2022)).
2 Theoretical model
Why might we think that the yield curve contains information useful to forecast future recessions?
We can explain the relationship between the slope of the yield curve and recessions with two factors, (1) monetary policy and (2) market expectations of real economic activity and inflation, as explained in Estrella (2005) as follows.
A tightening of monetary policy is normally associated with a rise in short-term interest rates. If interest rates are expected to remain higher for some time, long-term interest rates will rise too as suggested by the expectations hypothesis. However, if short-term interest rates are not expected to be high for long, long-term interest rates will not rise much and the yield curve will flatten. This goes along with the usual consequence of monetary tightening is lower aggregate demand and a slowdown in economic activity. Thus the level of the term spread should be correlated with the likelihood of a future recession.
An alternative way to look at the relationship is to focus on market expectations. Interest rates are determined in part by the real demand for credit and by expected inflation. A rise in short-term interest rates may be a harbinger of a future slowdown in real economic activity and demand for credit, putting downward pressure on future real interest rates. At the same time, slowing activity usually leads to a decline in expected inflation. Given this interpretation, future short-term rates may be expected to decline, which tends to reduce current long-term rates and flatten the yield curve. Once again, the observed correlation between the yield curve and recessions follows.
So we have some theoretical ideas about how the slope of the yield curve or the level of the term spread may relate to future economic growth. It seems we may be able to build a forecasting model where we can use a measure of the term spread to predict the likelihood of future recession in the macroeconomy.
3 Empirical model
From the theory discussed above we can construct an empirical model that we can estimate with data. We specify our empirical model in the econometric form of a probit model.
\[ Recession_{t+6} = \alpha + \beta Spread_{t} + \epsilon_t \]
The explanatory variable, \(Spread_t\), is the 10-year minus 3-month yield spread at time \(t\).
The dependent variable, \(Recession_{t+6}\), is a variable that takes the value of 1 when the economy is in recession and 0 when the economy is not in recession. This is an example of a binary or dichotomous dependent variable. Probit models are one type of model that can be used for dichotomous dependent variables.
We will use a forecasting horizon of 6 months. That means we will predict recessions 6 months into the future, thus the time subscript on the dependent variable is \(t+6\).
\(\epsilon_t\) is a random error term.
\(\alpha\) and \(\beta\) are the parameters we would like to estimate. We estimate the parameters of the model using the maximum likelihood method.
Usually when modelling econometric relationships, we should run diagnostic tests on our estimated model to ensure that the underlying statistical assumptions of the model are satisfied, meaning that statistical inference based onthe model is valid. In this simple case, we will skip the diagnostics step.
Fitted values of the model, \(\widehat{Recession}_{t+6}\), are calculated using the data used for estimation and our parameter estimates, \(\hat\alpha\) and \(\hat\beta\).
\[ \widehat{Recession}_{t+6} = \hat\alpha + \hat\beta Spread_{t} \]
The fitted values represent the probability of a recession occurring. Forecasts of recession probabilities can be calculated in the same way as the fitted values, but with new data.
4 Setting up R
A package is a set of code, data and examples used to extend the functionality of the Base R language.
To use a package, you must first install it. You need only do this on your computer once. We will use the following packages.
Show the code
install.packages('quantmod', 'fBasics', 'lubridate',
'stargazer', 'ggplot2', 'broom', 'scales')
After installing a package, you must load it for use usually at the beginning of each R session1. Use the “library” function.
1 Tip: automate this by placing the library commands in your .RProfile file.
5 Data
We will use data from the Federal Reserve Economic Database (FRED) and download it directly within R using the quantmod package function “getSymbols”.
5.1 NBER recessions
The USRECM data series indicates recessions in the U.S. economy as defined by the National Bureau of Economic Research.
Show the code
urecM <- getSymbols('USRECM',src='FRED', auto.assign=F)
Plot the recession data.
Show the code
plot(urecM["1962/"], main = "NBER defined U.S. recessions", col = "magenta")
5.2 Government bond yield data
We specify the term spread as the difference between the 10-year Treasury bond and the 3-month Treasury bill yields2. We download the time series of both yields from FRED.
2 We could use other measures of the yield curve slope (or term spread), such as 10-year minus 1-year yields, 30-year minus 2-year yields, etc. We could compare different measures of the term spread by how well each forecasts. More complex models may include more than one term spread or other relevant variables.
Show the code
getSymbols(c('DTB3', 'DGS10'), src='FRED', auto.assign=T)
[1] "DTB3" "DGS10"
Next we calculate the spread and convert the data to monthly to match the periodicity of our recession indicator.
Show the code
spread <- usrates$long - usrates$short
spreadM <- to.monthly(spread, indexAt = "firstof")[,1]
colnames(spreadM) <- "spread"
Plot the spread data.
Show the code
plot(spreadM$spread, main="Term spread (10-year - 3-month yield, %)",
col="darkgreen")
We have data from January 1962 to February 2023 for our modelling work. We will use the data from 1962 to 2015 to estimate the model, and reserve the data from 2016 to 2023 for out-of-sample forecasting.
Merge the data for our dependent and explanatory variables into one object.
Show the code
data1 <- merge(urecM,spreadM)
We will forecast 6 months ahead. That is, use the spread in month \(t\) to forecast the probability of a recession 6 months ahead in month \(t+6\). Set our forecast horizon as follows.
Show the code
fh <- 6
Set the dates for the start and end of our full sample.
Set the end date for our estimation sample.
Show the code
estEND <- "2015-12-01"
Set start date for the fitted values produced by our model.
Set start date for the forecasts produced by our model.
Set our full sample of data.
Show the code
data1 <- data1[paste(startM, endM, sep = "/")] #"1962-01-01/2023-02-01"
5.3 Summary statistics
Summary statistics give us an overview of the properties of our data.
Show the code
round(basicStats(data1),2)
USRECM spread
nobs 746.00 746.00
NAs 0.00 0.00
Minimum 0.00 -2.34
Maximum 1.00 4.34
1. Quartile 0.00 0.49
3. Quartile 0.00 2.46
Mean 0.12 1.43
Median 0.00 1.47
Sum 93.00 1069.71
SE Mean 0.01 0.05
LCL Mean 0.10 1.34
UCL Mean 0.15 1.52
Variance 0.11 1.56
Stdev 0.33 1.25
Skewness 2.27 -0.19
Kurtosis 3.15 -0.48
6 Estimation results
Estimate the probit model using the “glm” function (Generalized Linear Models), and examine the results.
Show the code
Call:
glm(formula = USRECM ~ lag.xts(spread, fh), family = binomial(link = "probit"),
data = data1[paste("", estEND, sep = "/")])
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.46878 0.08734 -5.367 8e-08 ***
lag.xts(spread, fh) -0.54307 0.06226 -8.722 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 520.11 on 640 degrees of freedom
Residual deviance: 420.87 on 639 degrees of freedom
(6 observations deleted due to missingness)
AIC: 424.87
Number of Fisher Scoring iterations: 6
We can easily format the estimation results nicely using the stargazer package.
Show the code
stargazer(pmod, type = "html", style = "aer")
USRECM | |
lag.xts(spread, fh) | -0.543*** |
(0.062) | |
Constant | -0.469*** |
(0.087) | |
Observations | 641 |
Log Likelihood | -210.435 |
Akaike Inf. Crit. | 424.869 |
Notes: | ***Significant at the 1 percent level. |
**Significant at the 5 percent level. | |
*Significant at the 10 percent level. |
Plot the fitted values of the model. These represent the probability of recession estimated by our model for each month over the estimation data period.
7 Forecasts
We generate out-of-sample forecasts of the probability of recession using the data covering the period from 2016 to 2023. We did not use this data to estimate the model.
Create the sample of new data (the term spread from 2015 until now) to make our forecasts. We need to add on 6 empty months (rows) to our spread data to hold the forecasts 6 months ahead.
Generate the forecasts.
Plot our out-of-sample recession probability forecasts.
See our most recent recession probability forecasts.
Forecast
May 2024 0.43
Jun 2024 0.53
Jul 2024 0.60
Aug 2024 0.60
Sep 2024 0.54
Oct 2024 0.51
Plot the relationship between the yield spread and the model’s probability of recession, including both our estimates (grey) and forecasts (purple).
Show the code
pmod.fit1 <- merge(pmod.fit, lag.xts(spreadM, fh),
all = TRUE, join = "outer")
pmod.fit1 <- as.data.frame(pmod.fit1)
pmod.for1 <- merge(pmod.for,
lag.xts(newdata[paste(forSTART, "", sep = "/")],fh),
all = TRUE, join = "outer")
pmod.for1 <- as.data.frame(pmod.for1)
plot(pmod.fit1$spread, pmod.fit1$Estimate, col = "gray", pch = 19,
main=paste("Yield curve spread and the probability of recession",
fh, "months later", sep = " "),
ylab="Recession probability",
xlab = "10-year - 3-month yield spread (%)")
points(pmod.for1$spread, pmod.for1$Forecast, col = "purple", pch = 20)
text(pmod.for1$spread[nrow(pmod.for1)],
pmod.for1$Forecast[nrow(pmod.for1)],
labels = rownames(pmod.for1)[nrow(pmod.for1)],
col = "purple", pos = 4)
8 Visualization
The ggplot package allows for very customized data visualization. Here I combine our estimated and forecast recession probabilities with the NBER defined recessions.
Show the code
recession <- urecM[paste(fvSTART, "", sep = "/")]
drecession <- diff(recession)
# In recession at the beginning? Set to 1.
recession.start <- time(drecession[drecession==1])
recession.end <- time(drecession[drecession==-1])
urec.df <- data.frame(recession.start
,recession.end[1:length(recession.end)])
colnames(urec.df) <- c("PEAK","TROUGH")
pmod.out <- merge(pmod.fit, pmod.for, all = TRUE, join = "outer")
pmod.out <- tidy(pmod.out)
theme_set(theme_bw())
mytheme <- theme(plot.title = element_text(color="black",
size=16, face="bold", hjust = 0.5),
axis.title.x = element_text(color="black", size=14),
axis.text.x = element_text(color="black", size=12),
axis.title.y = element_text(color="black", size=14),
axis.text.y = element_text(color="black", size=12),
legend.text=element_text(color="black", size=12),
legend.title=element_text(color="black", size=14),
plot.subtitle=element_text(color="black",
size=12, hjust = 0.5),
text = element_text(size=10, family = "sans"),
plot.background = element_rect(fill = "white"),
panel.background = element_rect(colour = "white"),
panel.border = element_rect(colour = "black",
fill = NA, size=0.75),
panel.grid.major = element_line(colour = "lightgrey"),
panel.grid.minor = element_blank(),
legend.position=c(0.1,0.85), legend.key=element_blank(),
legend.background = element_rect(colour = "white"),
legend.box.background = element_rect(colour = "black",
size=0.50),
plot.margin = unit(c(20,20,20,20), "pt"))
plot1 <- ggplot() + geom_line(data=pmod.out,
aes(x = index, y = value, color=series), size=0.75) +
scale_x_date(labels = date_format("%Y"), breaks = pretty_breaks(n=8)) +
labs(title = "Estimated and forecast U.S. recession probability",
subtitle = "(Shaded areas represent NBER-defined recessions)",
x="", y="",
caption = "Source: FRED data with NBER recessions, our calculations.") +
mytheme + theme(legend.title=element_blank()) +
geom_rect(data=urec.df, aes(xmin=TROUGH, xmax=PEAK, ymin=0,
ymax=max(pmod.fit[,1],na.rm=T)), fill='grey30', alpha=0.25)
plot1
9 Further reading
New York Fed Yield Curve as a Leading indicator
FRBSF Economic Letter - Current Recession Risk According to the Yield Curve
FRBC - Yield Curve and Predicted GDP Growth
RBloggers Predicting future recessions
How to use Quarto with R in RStudio for publishing