Skip to main content

yield_curves/
lib.rs

1//! Yield curve interpolation and parametric fitting for fixed income.
2//!
3//! Zero-dependency library. All curves accept `(t_years, rate)` pairs and
4//! expose a uniform interface via [`YieldCurveInterpolator`].
5//!
6//! # Methods
7//!
8//! - [`LinearCurve`] — piecewise linear, transparent baseline.
9//! - [`CubicSplineCurve`] — natural cubic spline (C² continuous), Thomas
10//!   algorithm, no linear-algebra dependencies.
11//! - [`PchipCurve`] — Fritsch-Carlson monotone cubic Hermite (C¹). Use when
12//!   cubic spline produces overshoots or when monotonicity must be preserved.
13//! - [`NelsonSiegelCurve`] — Nelson-Siegel (1987) 4-parameter parametric fit.
14//! - [`SvenssonCurve`] — Nelson-Siegel-Svensson (1994) 6-parameter parametric
15//!   fit (BCB/ANBIMA/ECB standard for sovereign yield curves).
16//!
17//! # Discount factors and forward rates
18//!
19//! See the [`compounding`] module for free-standing helpers that turn
20//! interpolated rates into discount factors and implied forward rates under
21//! any of: continuous, periodic, or simple compounding.
22//!
23//! # Bond pricing
24//!
25//! See the [`bond`] module for price, Macaulay/modified duration, convexity
26//! and par yield computed from a cash-flow schedule plus a YTM.
27//!
28//! # Dates, day counts, calendars, and schedules
29//!
30//! The [`date`], [`daycount`], [`calendar`], and [`schedule`] modules form a
31//! zero-dependency date toolkit for building a curve's time axis: a proleptic
32//! Gregorian [`Date`], ISDA day-count conventions ([`DayCount`]), holiday
33//! calendars ([`Calendar`], [`Brazil`], [`Target2`]) with business-day
34//! adjustment and the BUS/252 year fraction, and coupon/pillar
35//! [`Schedule`] generation.
36//!
37//! # Conventions
38//!
39//! The x-axis is **time in years**. Convert from calendar/business days at
40//! the call site with the appropriate day count convention:
41//!
42//! - Brazil (business-day 252): `days / 252.0`
43//! - US Treasury (actual/365): `days / 365.0`
44//! - ISDA actual/365.25: `days / 365.25`
45//!
46//! Rates are in the same unit as the input (typically percent). The library
47//! performs no unit conversion.
48//!
49//! # Extrapolation
50//!
51//! All curves extrapolate **flat** outside the observed range — the rate of
52//! the nearest observed anchor is returned. Parametric methods (NS, Svensson)
53//! in particular diverge quickly outside the fitted range, so flat extrapolation
54//! is a sane default for financial use.
55//!
56//! # Example
57//!
58//! ```
59//! use yield_curves::{CubicSplineCurve, YieldCurveInterpolator};
60//!
61//! // Brazilian nominal yield curve from LTNs/NTN-Fs (t in years, rate in %).
62//! let points = [
63//!     (1.0, 13.98),
64//!     (2.5, 13.51),
65//!     (4.0, 13.45),
66//!     (7.0, 13.57),
67//!     (10.0, 13.80),
68//! ];
69//!
70//! let curve = CubicSplineCurve::fit(&points).unwrap();
71//! let rate_5y = curve.rate_at(5.0);
72//! assert!((13.4..=13.6).contains(&rate_5y));
73//! ```
74
75pub mod bond;
76pub mod calendar;
77pub mod compounding;
78pub mod date;
79pub mod daycount;
80pub mod linear;
81pub mod nelson_siegel;
82pub mod pchip;
83pub mod schedule;
84pub mod spline;
85pub mod svensson;
86
87mod error;
88mod nelder_mead;
89mod validate;
90
91pub use calendar::{
92    easter, Brazil, BusinessDayConvention, Calendar, JoinCalendar, JoinRule, Target2, WeekendsOnly,
93};
94pub use compounding::{discount_factor, forward_rate, Compounding};
95pub use date::{Date, DateError, Period, Unit, Weekday};
96pub use daycount::DayCount;
97pub use error::YieldCurveError;
98pub use linear::LinearCurve;
99pub use nelson_siegel::NelsonSiegelCurve;
100pub use pchip::PchipCurve;
101pub use schedule::{third_wednesday, DateGeneration, Schedule, ScheduleError, StubConvention};
102pub use spline::CubicSplineCurve;
103pub use svensson::SvenssonCurve;
104
105/// Common interface for all yield curve methods.
106///
107/// Time is in years. Implementations clamp `t_years` to the observed range
108/// before evaluating (flat extrapolation).
109pub trait YieldCurveInterpolator {
110    /// Interpolated rate at `t_years`. Returns the boundary rate if `t_years`
111    /// falls outside the observed range.
112    fn rate_at(&self, t_years: f64) -> f64;
113
114    /// Stable identifier for the method (e.g. `"linear"`, `"cubic_spline"`,
115    /// `"nelson_siegel"`, `"svensson"`). Useful for tagging response payloads.
116    fn method_name(&self) -> &'static str;
117
118    /// The `(min, max)` t_years range observed in the fitted data. Callers
119    /// can use this to mark whether a requested vertex is an interpolation
120    /// or an extrapolation.
121    fn observed_range(&self) -> (f64, f64);
122}