Anderson-Sleath yield curves: latest and historical

Charles Coverdale

30 May 2026

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

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:

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.

panel <- boe_curve_panel(
  curve     = "nominal",
  measure   = "spot",
  frequency = "monthly",
  from      = "2000-01-01",
  maturities = c(2, 5, 10, 20)
)
head(panel)
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.

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")])
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.

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)
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.

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.

ois_short  <- boe_curve(curve = "ois", measure = "forward", segment = "short")
latest_day <- ois_short[ois_short$date == max(ois_short$date), ]
head(latest_day)
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