Yield Curve inversion

📅️ Published:

🔄 Updated:

🕔 4 min read ∙ 791 words

The yield curve is appearing more important these days since the Fed is discussing its tapering policy.

Every so often, we hear warnings from commentators on the “inverted yield curve” and its predictive power with respect to recessions. An explainer what a inverted yield curve is can be found here. If you’d rather listen to something, here is a great podcast from NPR on yield curve indicators

In addition, many articles and commentators think that, e.g., Yield curve inversion is viewed as a harbinger of recession. One can always doubt whether inversions are truly a harbinger of recessions, and use the attached parable on yield curve inversions.

Get the data

In our case we will look at US data and use the FRED database to download historical yield curve rates, and plot the yield curves since 1999 to see when the yield curves flatten. There’s further information from an article that explains the yield curve is and its inversion can be found here.

First, we will load the yield curve data file that contains data on the yield curve since 1960-01-01

yield_curve <- read_csv(here::here("data_project", "yield_curve.csv"))
glimpse(yield_curve)
## Rows: 6,884
## Columns: 5
## $ date      <date> 1960-01-01, 1960-02-01, 1960-03-01, 1960-04-01, 1960-05-01,~
## $ series_id <chr> "TB3MS", "TB3MS", "TB3MS", "TB3MS", "TB3MS", "TB3MS", "TB3MS~
## $ value     <dbl> 4.35, 3.96, 3.31, 3.23, 3.29, 2.46, 2.30, 2.30, 2.48, 2.30, ~
## $ maturity  <chr> "3m", "3m", "3m", "3m", "3m", "3m", "3m", "3m", "3m", "3m", ~
## $ duration  <chr> "3-Month Treasury Bill", "3-Month Treasury Bill", "3-Month T~

Our dataframe yield_curve has five columns (variables):

  • date: already a date object
  • series_id: the FRED database ticker symbol
  • value: the actual yield on that date
  • maturity: a short hand for the maturity of the bond
  • duration: the duration, written out in all its glory!

According to Wikipedia’s list of recession in the United States, since 1999 there have been two recession in the US: between Mar 2001–Nov 2001 and between Dec 2007–June 2009. The yield curve seems to flatten before these recessions. Usually the flattening yield curve is an economic indicator of recessions. Since 1999, short-term (3 months) yield has been higher than the long term (10 years) debt for three time: Early 2001(2001 Recession), late 2006 to 2007(housing bubble crisis, subprime lending crisis) and late 2019(covid pandemic).

spread (10year - 3months)

To create our final plot, we do the following steps:

  • Calculate the spread (10year - 3months)
  • Plot the spread between 10 years and 3 months as a blue/red ribbon, blue for positive and red for negative
  • Superimpose recessions as the grey areas in our plot
  • Plot the rugs on x-axis

We get the recession data first.

# get US recession dates after 1946 from Wikipedia 
# https://en.wikipedia.org/wiki/List_of_recessions_in_the_United_States

recessions <- tibble(
  from = c("1948-11-01", "1953-07-01", "1957-08-01", "1960-04-01", "1969-12-01", "1973-11-01", "1980-01-01","1981-07-01", "1990-07-01", "2001-03-01", "2007-12-01","2020-02-01"),  
  to = c("1949-10-01", "1954-05-01", "1958-04-01", "1961-02-01", "1970-11-01", "1975-03-01", "1980-07-01", "1982-11-01", "1991-03-01", "2001-11-01", "2009-06-01", "2020-04-30") 
  )  %>% 
  mutate(From = ymd(from), 
         To=ymd(to),
         duration_days = To-From)

recessions
## # A tibble: 12 x 5
##    from       to         From       To         duration_days
##    <chr>      <chr>      <date>     <date>     <drtn>       
##  1 1948-11-01 1949-10-01 1948-11-01 1949-10-01 334 days     
##  2 1953-07-01 1954-05-01 1953-07-01 1954-05-01 304 days     
##  3 1957-08-01 1958-04-01 1957-08-01 1958-04-01 243 days     
##  4 1960-04-01 1961-02-01 1960-04-01 1961-02-01 306 days     
##  5 1969-12-01 1970-11-01 1969-12-01 1970-11-01 335 days     
##  6 1973-11-01 1975-03-01 1973-11-01 1975-03-01 485 days     
##  7 1980-01-01 1980-07-01 1980-01-01 1980-07-01 182 days     
##  8 1981-07-01 1982-11-01 1981-07-01 1982-11-01 488 days     
##  9 1990-07-01 1991-03-01 1990-07-01 1991-03-01 243 days     
## 10 2001-03-01 2001-11-01 2001-03-01 2001-11-01 245 days     
## 11 2007-12-01 2009-06-01 2007-12-01 2009-06-01 548 days     
## 12 2020-02-01 2020-04-30 2020-02-01 2020-04-30  89 days

We manipulate the data to calculate the up-and-down spreads.

yield_curve_recession <- yield_curve %>%
  filter(maturity=="3m"|maturity=="10y") %>%
  group_by(date)%>%
  pivot_wider(id_col=1, names_from = duration, values_from=value) %>%
  clean_names() %>%
  mutate(spread = x10_year_treasury_rate - x3_month_treasury_bill,
         up = ifelse(spread>0, spread, 0), #up gives the diffrence between 10y and 3m when 10y>3m
         down = ifelse(spread<0, spread, 0)) #down gives the diffrence between 10y and 3m when 10y<3m
yield_curve_recession %>%
  ggplot()+
  #plot rectangles for recessions
  geom_rect(data=recessions %>% filter(From>="1960-01-01"),
            aes(xmin=From,xmax=To,ymin=-Inf,ymax=Inf),colour="grey",alpha=0.2)+ 
  scale_x_date(date_breaks = "2 years", date_labels = "%Y")+
  #plot rug for x asis
  geom_rug(aes(x=date,colour=ifelse(x10_year_treasury_rate>=x3_month_treasury_bill,">=0","<0")),sides="b")+ 
  scale_colour_manual(values=c("#EC7063","#2874A6"),name="Actual vs Expected ", guide=FALSE)+
  geom_line(aes(x=date,y=spread,fill="black"))+
  #plot the areas in blue using up when 10y>3m
  geom_ribbon(aes(x=date,ymin=0,
                  ymax=up),alpha=0.4,fill="#2874A6")+ 
  #plot the areas in red using down when 10y<3m
  geom_ribbon(aes(x=date,ymin=down,
                  ymax=0),alpha=0.4,fill="#EC7063")+ 
  theme_bw()  +
  theme(legend.position = "none",
        plot.title =element_text(size=16, face='bold',hjust = 0,margin = margin(10,0,10,0)),
        plot.subtitle =element_text(size=16, hjust = 0), 
        axis.text.x = element_text(size=10),
        axis.text.y = element_text(size=12),
        axis.ticks.x = element_line(),
        axis.ticks.y=element_line(),
        axis.title.x = element_text(size=16,face='bold'),
        axis.title.y = element_text(size=16,face='bold'),
        ) +
  labs(title = "Yield Curve Inversion: 10-year minus 3-month U.S. Treasury rates", 
       subtitle = "Difference in % points, monthly averages,
Grey areas representing recessions", 
       caption= "Source: St. Louis Federal Reserve Economic Database (FRED)",
       x="", y="Yield Spread (10year - 3months)") 


Wrong content? Edit on Github.


💬 Comment: