MyNixOS website logo
Description

Yield Curve Fitting, Analysis, and Decomposition.

Fits yield curves using Nelson-Siegel (1987) <doi:10.1086/296409>, Svensson (1994) <doi:10.3386/w4871>, and cubic spline methods. Extracts forward rates, discount factors, and par rates from fitted curves. Computes duration and convexity risk measures. Computes Z-spread and key rate durations. Provides principal component decomposition following Litterman and Scheinkman (1991) <doi:10.3905/jfi.1991.692347>, carry and roll-down analysis, and slope measures. All methods are pure computation with no external dependencies beyond base R; works with yield data from any source.

yieldcurves

Lifecycle: stable License: MIT

An R package for working with yield curves: fit smooth curves to bond yields, extract forward rates and discount factors, compute duration and convexity, and decompose curve movements.

Installation

# install.packages("devtools")
devtools::install_github("charlescoverdale/yieldcurves")
library(yieldcurves)

# US Treasury yields: maturities in years, rates as decimals (5% = 0.05)
maturities <- c(0.25, 0.5, 1, 2, 5, 10, 30)
rates <- c(0.052, 0.050, 0.048, 0.045, 0.042, 0.040, 0.043)

fit <- yc_nelson_siegel(maturities, rates)
fit
#> -- Yield Curve (Nelson-Siegel) --
#> * Type: "zero"
#> * Maturities: 7 (0.25Y to 30Y)
#> * Rate range: 4% to 5.2%
#> * RMSE: 8.6 bps
#> * Parameters: beta0=0.04127, beta1=0.01347, beta2=-0.0091, tau=1

plot(fit)

Why yieldcurves?

Government bond yields are published daily at a handful of maturities: 1-month, 3-month, 1-year, 2-year, 5-year, 10-year, 30-year. But most questions in fixed income require yields at maturities that are not published, or require derived quantities (forward rates, discount factors, risk measures) that cannot be read off a table. If you need a discount factor at 7.5 years, or the implied rate for a 5-year loan starting in 5 years, you need a fitted model.

The Nelson-Siegel (1987) and Svensson (1994) models are the standard solution. They fit the entire curve with 4 to 6 parameters that have economic meaning: level (long-run rate), slope (term premium), and curvature (medium-term humps). Over 20 central banks use these models for their official yield curve estimates. Once you have a fitted curve, you can extract forward rates, discount factors, carry and roll-down, duration and convexity, and Z-spreads.

There are two existing R packages in this space. YieldCurve (last updated 2022) fits Nelson-Siegel and Svensson models but requires xts/zoo objects as input, does not compute duration, convexity, Z-spreads, or PCA, and has no carry/roll-down analysis. termstrc was more comprehensive (cubic splines, forward rates) but was archived from CRAN in 2018 due to failing checks and is no longer maintained. Neither package covers the full workflow from curve fitting through to risk measures and portfolio analytics. yieldcurves fills this gap: it works with plain numeric vectors, has no heavy dependencies, and covers fitting, extraction, risk measures, and decomposition in one package.

How does this compare to existing packages?

FeatureyieldcurvesYieldCurvetermstrc
Nelson-Siegel fittingYesYesYes
Svensson fittingYesYesYes
Cubic splineYesNoYes
Weighted fittingYesNoNo
Forward rates (analytical)YesNoYes
Discount factorsYesNoYes
Duration and convexityYesNoNo
Z-spreadYesNoNo
Key rate durationsYesNoNo
Par/zero conversionsYesNoYes
PCA decompositionYesNoNo
Carry and roll-downYesNoNo
Slope measuresYesNoNo
Works with plain vectorsYesNo (needs xts/zoo)No
Last updated202620222015

Examples

Fit a yield curve

The Nelson-Siegel model takes two inputs: maturities (in years) and rates (as decimals, so 5% = 0.05). It returns a fitted curve you can query at any maturity.

library(yieldcurves)

maturities <- c(0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30)
rates <- c(0.052, 0.050, 0.048, 0.045, 0.043, 0.042, 0.041,
           0.040, 0.042, 0.043)

fit <- yc_nelson_siegel(maturities, rates)
fit
#> -- Yield Curve (Nelson-Siegel) --
#> * Type: "zero"
#> * Maturities: 10 (0.25Y to 30Y)
#> * Rate range: 4% to 5.2%
#> * RMSE: 8.6 bps
#> * Parameters: beta0=0.04127, beta1=0.01347, beta2=-0.0091, tau=1

plot(fit)

Extract forward rates and discount factors

Forward rates tell you what the market implies about future interest rates. Discount factors tell you what a future cash flow is worth today.

# Forward rates at 1, 5, and 10 years
yc_forward(fit, maturities = c(1, 5, 10))
#>   maturity forward_rate
#> 1        1       0.0468
#> 2        5       0.0393
#> 3       10       0.0413

# Discount factors
yc_discount(fit, maturities = c(1, 5, 10, 30))
#>   maturity discount_factor
#> 1        1          0.9530
#> 2        5          0.8103
#> 3       10          0.6619
#> 4       30          0.2817   # $1 in 30 years is worth $0.28 today

Compute carry and roll-down

How much do you earn from holding a bond, assuming the curve does not move? Carry is the yield income minus the funding cost. Roll-down is the capital gain as the bond's remaining maturity shortens and it slides to a lower-rate part of the curve.

yc_carry(fit, maturities = c(2, 5, 10, 30))
#>   maturity     carry   rolldown      total
#> 1        2  0.000170  0.005143  0.005313   # 53 bps total on the 2Y
#> 2        5  0.000013  0.004478  0.004491   # 45 bps on the 5Y
#> 3       10 -0.000059  0.003260  0.003201   # 32 bps on the 10Y
#> 4       30  0.000033 -0.001507 -0.001474   # Negative on the 30Y

Compute duration and convexity for a coupon bond

Duration measures how sensitive a bond's price is to rate changes. A modified duration of 7.87 means a 1% rate rise causes roughly a 7.87% price drop.

# 10-year bond with 5% coupon at 4.5% yield, semi-annual coupons
yc_bond_duration(face = 100, coupon_rate = 0.05, maturity = 10,
                 yield = 0.045, frequency = 2)
#> $macaulay_duration
#> [1] 8.05
#>
#> $modified_duration
#> [1] 7.87
#>
#> $convexity
#> [1] 73.7
#>
#> $price
#> [1] 104.01

Compute the Z-spread on a bond

The Z-spread is the constant spread over the benchmark zero curve that reprices a bond to its market price. A positive Z-spread means the bond yields more than the benchmark.

# Benchmark zero curve
curve <- yc_curve(c(0.5, 1, 2, 5, 10), c(0.03, 0.035, 0.04, 0.042, 0.045))

# Bond trading below par
result <- yc_zspread(price = 95, coupon_rate = 0.04, maturity = 5,
                     curve = curve, frequency = 2)
result$zspread
#> [1] 0.0148   # 148 bps over the benchmark curve

Decompose yield curve movements with PCA

Principal component analysis decomposes a time series of yield curves into orthogonal factors. Litterman and Scheinkman (1991) showed that three factors (level, slope, curvature) explain over 95% of yield curve movements.

# Simulate a time series of yield curves (200 days, 5 tenors)
set.seed(42)
n_days <- 200
tenors <- c(1, 2, 5, 10, 30)
base <- c(0.045, 0.043, 0.042, 0.040, 0.043)
level <- cumsum(rnorm(n_days, 0, 0.001))
curves <- matrix(NA, n_days, length(tenors))
for (i in seq_len(n_days)) curves[i, ] <- base + level[i]
colnames(curves) <- paste0(tenors, "Y")

pca <- yc_pca(curves)
pca
#> -- Yield Curve PCA --
#> * Components: 3
#> * PC1 (Level): 97.2% variance
#> * PC2 (Slope): 1.2% variance
#> * PC3 (Curvature): 0.8% variance

plot(pca)

Key terms

  • Zero rates (spot rates): yields on zero-coupon bonds. These are the building blocks of the yield curve.
  • Par rates: the coupon rate at which a bond prices at par (100). This is what the news means by "the 10-year yield."
  • Forward rates: rates implied by the curve for a future period. The "5y5y forward" is the rate the market implies for a 5-year loan starting in 5 years.
  • Basis points (bps): 1 bp = 0.01%. All rates in this package are decimals: 5% = 0.05, 50 bps = 0.005.

What data do I need?

You supply two numeric vectors: maturities (in years) and rates (as decimals, so 5% = 0.05). You can type them in directly or pull them from a data source.

Option 1: Type rates in directly

library(yieldcurves)

maturities <- c(0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30)
rates <- c(0.052, 0.050, 0.048, 0.045, 0.043, 0.042, 0.041,
           0.040, 0.042, 0.043)

fit <- yc_nelson_siegel(maturities, rates)
plot(fit)

Option 2: Pull US Treasury yields from FRED

# 1. Install the fred package (one time)
install.packages("fred")

# 2. Get a free API key from https://fred.stlouisfed.org/docs/api/api_key.html
fred::fred_set_key("your_api_key_here")

# 3. Download Treasury constant maturity rates
library(fred)
treasury <- fred_series(c("DGS1", "DGS2", "DGS5", "DGS10", "DGS30"))

# 4. Extract the most recent observation
latest <- treasury[nrow(treasury), ]
maturities <- c(1, 2, 5, 10, 30)
rates <- as.numeric(latest[, -1]) / 100  # FRED reports percent, convert to decimal

# 5. Fit a yield curve
library(yieldcurves)
fit <- yc_nelson_siegel(maturities, rates)
plot(fit)

Where to find yield data

CountrySourceR packageSeries / function
USUS Treasury / FREDfredDGS1MO, DGS3MO, DGS1, DGS2, DGS5, DGS10, DGS30
UKBank of Englandboeboe_yield_curve()
Euro areaEuropean Central Bankreadecbecb_yield_curve()
JapanMinistry of FinanceDownload CSVmof.go.jp
AustraliaRBADownload CSVrba.gov.au
CanadaBank of CanadafredDGS series on FRED

Functions

Curve construction and fitting

FunctionDescription
yc_curve()Create a yield curve object from maturity-rate pairs
yc_nelson_siegel()Fit a Nelson-Siegel (1987) model
yc_svensson()Fit a Svensson (1994) model
yc_cubic_spline()Fit a cubic spline
yc_fit()Unified fitting interface (dispatches to the above)

Evaluation and extraction

FunctionDescription
yc_predict()Evaluate a fitted curve at new maturities
yc_forward()Extract instantaneous or forward-forward rates
yc_discount()Compute discount factors (continuous, annual, or semi-annual)
yc_interpolate()Interpolate between observed rates (linear, log-linear, or cubic)

Rate conversions

FunctionDescription
yc_par_to_zero()Convert par rates to zero rates via bootstrap stripping
yc_zero_to_par()Convert zero rates to par rates

Risk measures

FunctionDescription
yc_duration()Macaulay/modified duration and convexity for zero-coupon bonds
yc_bond_duration()Duration and convexity for coupon-bearing bonds
yc_zspread()Z-spread (zero-volatility spread) computation
yc_key_rate_duration()Key rate durations with triangular bump profiles

Analysis and decomposition

FunctionDescription
yc_carry()Carry and roll-down decomposition
yc_pca()Principal component analysis of yield curve time series
yc_slope()Spread measures (2s10s, 2s30s, butterfly, etc.)
yc_level_slope_curvature()Level, slope, and curvature factor extraction

All yc_curve and yc_pca objects have print(), summary(), and plot() methods.

Academic references

  • Nelson, C.R. and Siegel, A.F. (1987). Parsimonious Modeling of Yield Curves. The Journal of Business, 60(4), 473-489. doi:10.1086/296409
  • Svensson, L.E.O. (1994). Estimating and Interpreting Forward Interest Rates: Sweden 1992-1994. NBER Working Paper, 4871. doi:10.3386/w4871
  • Litterman, R. and Scheinkman, J. (1991). Common Factors Affecting Bond Returns. The Journal of Fixed Income, 1(1), 54-61. doi:10.3905/jfi.1991.692347

Related packages

PackageDescription
boeBank of England data (includes official yield curves)
fredFederal Reserve Economic Data (includes Treasury rates)
readecbEuropean Central Bank data (includes euro area yield curves)
debtkitDebt sustainability analysis and fiscal projections

Issues

Found a bug or have a feature request? Open an issue at github.com/charlescoverdale/yieldcurves/issues.

Keywords

r, r-package, yield-curve, fixed-income, nelson-siegel, svensson, term-structure, interest-rates, bond-math, finance, duration, convexity, z-spread.

Metadata

Version

0.1.0

License

Unknown

Platforms (80)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arc-linux
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • sh4-linux
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows