---
title: "Anderson-Sleath yield curves: latest and historical"
author: "Charles Coverdale"
date: "`r format(Sys.Date(), '%d %B %Y')`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Anderson-Sleath yield curves: latest and historical}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
library(boe)
not_on_cran <- identical(Sys.getenv("NOT_CRAN"), "true")
knitr::opts_chunk$set(
  collapse = TRUE,
  comment  = "#>",
  fig.width  = 7,
  fig.height = 4.5,
  eval = not_on_cran
)
op <- options(boe.cache_dir = tempfile("boe_vignette_"))
```

The Bank of England publishes daily fitted yield curves at all maturities
using the Anderson and Sleath (2001) smoothing methodology. Five curves
are produced: nominal gilt, real (index-linked) gilt, implied inflation,
overnight index swap (OIS), and the commercial bank liability curve
(BLC). Each is available in spot and instantaneous-forward form, and in
two segments: the *standard* curve (half-year maturity steps out to 25 or
40 years) and the separately fitted *short end* (monthly steps from one
month to five years), selected with `segment = "short"`.

The default behaviour of `boe_curve()` returns the latest published
month, matching what most analysts need when they reach for "today's
curve". Pass `from`, `to`, or `frequency = "monthly"` and the function
switches to the BoE historical archive, which extends back as far as
1979 for nominal gilts.

## Latest published month

```{r latest}
latest <- boe_curve(curve = "nominal", measure = "spot")
range(latest$date)
range(latest$maturity_years)
```

`boe_curve()` returns a long-format `boe_tbl` with one row per
(date, maturity) pair. Provenance is attached as an attribute:

```{r latest-provenance}
attr(latest, "boe_query")$source
attr(latest, "boe_query")$series_codes
```

## Historical: 10-year nominal spot rate since 2000

For time-series work, `boe_curve_panel()` reshapes the long format into
a wide panel with one column per pillar maturity. End-of-month frequency
is plenty for multi-decade work and keeps the download small.

```{r hist-10y}
panel <- boe_curve_panel(
  curve     = "nominal",
  measure   = "spot",
  frequency = "monthly",
  from      = "2000-01-01",
  maturities = c(2, 5, 10, 20)
)
head(panel)
```

```{r hist-10y-plot, fig.alt = "10-year UK nominal spot rate, 2000 to present"}
if (requireNamespace("ggplot2", quietly = TRUE)) {
  ggplot2::ggplot(panel, ggplot2::aes(date, m10)) +
    ggplot2::geom_line(colour = "#1f77b4") +
    ggplot2::labs(
      title    = "UK 10-year nominal spot rate",
      subtitle = "End of month, Anderson-Sleath fitted",
      x = NULL, y = "Per cent"
    ) +
    ggplot2::theme_minimal()
}
```

## 5y5y forward implied inflation

The 5y5y forward inflation rate (the average implied inflation rate over
the second five-year horizon, five years from now) is a textbook
medium-term inflation expectations measure. It comes straight off the
implied-inflation forward curve.

```{r five-five}
inflation_fwd <- boe_curve_panel(
  curve     = "inflation",
  measure   = "forward",
  frequency = "monthly",
  from      = "2010-01-01",
  maturities = c(5, 10)
)

inflation_fwd$five_y_five_y <- (inflation_fwd$m10 * 10 -
                                inflation_fwd$m5  *  5) / 5
head(inflation_fwd[, c("date", "m5", "m10", "five_y_five_y")])
```

```{r five-five-plot, fig.alt = "UK 5y5y forward implied inflation, 2010 to present"}
if (requireNamespace("ggplot2", quietly = TRUE)) {
  ggplot2::ggplot(inflation_fwd, ggplot2::aes(date, five_y_five_y)) +
    ggplot2::geom_line(colour = "#d62728") +
    ggplot2::geom_hline(yintercept = 2.0, linetype = "dashed",
                        colour = "grey40") +
    ggplot2::annotate("text", x = max(inflation_fwd$date),
                      y = 2.0, label = "2% target", hjust = 1, vjust = -0.5,
                      colour = "grey40", size = 3) +
    ggplot2::labs(
      title    = "UK 5y5y forward implied inflation",
      subtitle = "End of month, derived from the BoE implied-inflation forward curve",
      x = NULL, y = "Per cent per annum"
    ) +
    ggplot2::theme_minimal()
}
```

## OIS curve evolution across the rate cycle

The OIS curve gives a market-implied path for Bank Rate. Comparing OIS
spot pillars at MPC decision dates shows how expectations shifted
through the 2022 to 2024 hiking cycle.

```{r ois-cycle}
ois <- boe_curve_panel(
  curve     = "ois",
  measure   = "spot",
  frequency = "monthly",
  from      = "2020-01-01",
  maturities = c(0.5, 1, 2, 5)
)

mpc <- boe_mpc_decisions(from = "2020-01-01")
mpc <- data.frame(date = mpc$date, bank_rate = mpc$new_rate_pct)

merged <- merge(ois, mpc, by = "date", all.x = TRUE)
merged$bank_rate <- as.numeric(merged$bank_rate)

# carry the bank rate forward between MPC dates
for (i in seq_along(merged$bank_rate)) {
  if (i > 1 && is.na(merged$bank_rate[i])) {
    merged$bank_rate[i] <- merged$bank_rate[i - 1]
  }
}
tail(merged)
```

```{r ois-cycle-plot, fig.alt = "UK OIS spot pillars and Bank Rate, 2020 to present"}
if (requireNamespace("ggplot2", quietly = TRUE)) {
  long <- data.frame(
    date  = rep(merged$date, 5),
    pillar = rep(c("Bank Rate", "6m OIS", "1y OIS", "2y OIS", "5y OIS"),
                 each = nrow(merged)),
    rate  = c(merged$bank_rate, merged$m0.5, merged$m1, merged$m2, merged$m5)
  )
  long$pillar <- factor(long$pillar,
                        levels = c("Bank Rate", "6m OIS", "1y OIS",
                                   "2y OIS", "5y OIS"))

  ggplot2::ggplot(long, ggplot2::aes(date, rate, colour = pillar)) +
    ggplot2::geom_line() +
    ggplot2::labs(
      title    = "UK OIS spot pillars and Bank Rate, 2020 to present",
      subtitle = "Tightening cycle visible across all pillars",
      x = NULL, y = "Per cent", colour = NULL
    ) +
    ggplot2::theme_minimal() +
    ggplot2::theme(legend.position = "bottom")
}
```

## The short end of the curve

The standard curves step in half-years from 0.5 years out. For near-term
policy and money-market work the Bank fits a separate *short end* at
monthly maturities, from one month to five years. Pass
`segment = "short"` to `boe_curve()` or `boe_curve_panel()` to reach it.

```{r short-end}
short <- boe_curve(curve = "nominal", measure = "spot", segment = "short")
range(short$maturity_years)   # monthly grid, ~1/12 to 5 years
```

The short end of the OIS *forward* curve is the cleanest market-implied
path for Bank Rate: the instantaneous forward rate at each horizon, at
monthly resolution. Here it is on the most recent published date.

```{r short-ois}
ois_short  <- boe_curve(curve = "ois", measure = "forward", segment = "short")
latest_day <- ois_short[ois_short$date == max(ois_short$date), ]
head(latest_day)
```

```{r short-ois-plot, fig.alt = "UK OIS short-end forward curve on the latest published date"}
if (requireNamespace("ggplot2", quietly = TRUE)) {
  ggplot2::ggplot(latest_day, ggplot2::aes(maturity_years, rate_pct)) +
    ggplot2::geom_line(colour = "#1f77b4") +
    ggplot2::geom_point(size = 0.8, colour = "#1f77b4") +
    ggplot2::labs(
      title    = "UK OIS instantaneous forward curve, short end",
      subtitle = paste("Market-implied Bank Rate path on",
                       format(max(ois_short$date), "%d %B %Y")),
      x = "Horizon (years)", y = "Per cent"
    ) +
    ggplot2::theme_minimal()
}
```

Short-end history goes back as far as the Bank published it: to 1979 for
nominal gilts, and from 2016 for OIS. Where a period has no short-end
sheet (early OIS, for instance), those dates are simply absent from the
result rather than causing an error.

## When to reach for the archive

| Question | Argument set |
|---|---|
| Today's curve | none (default) |
| Last few years, daily | `from = "2020-01-01"` |
| Multi-decade panel for econometrics | `frequency = "monthly", from = "1990-01-01"` |
| Near-term policy-rate path, monthly detail | `segment = "short"` |
| Commercial bank liability curve | `curve = "blc"` (always uses archive) |

Archive zips cache for 30 days by default; the latest-month zip caches
for 24 hours. Override with `cache_ttl_h` if you need to force a fresh
pull.

## References

Anderson, N. and Sleath, J. (2001). *New estimates of the UK real and
nominal yield curves.* Bank of England Working Paper No. 126.
[https://www.bankofengland.co.uk/working-paper/2001/new-estimates-of-the-uk-real-and-nominal-yield-curves](https://www.bankofengland.co.uk/working-paper/2001/new-estimates-of-the-uk-real-and-nominal-yield-curves)

```{r teardown, include = FALSE}
options(op)
```
