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 <- 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:
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()
}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()
}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 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 yearsThe 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.
| 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.
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