fuggers_py.curves

Executive Summary

fuggers_py.curves provides a toolkit for building interest-rate term structures from fixed-income quotes. It can bootstrap exact node curves or fit smooth curves from swap quotes, bond quotes, and repo quotes. The main user object is YieldCurve: callers give it quotes plus a CurveSpec, then query rates, discount factors, and forward rates. The fit also returns one CalibrationReport so users can inspect how closely the curve matched the input quotes.

Use the root package for the first-layer curve API:

from fuggers_py.curves import CurveSpec, YieldCurve

Most users do not need deeper curve imports. YieldCurve.fit(...) accepts plain strings and dictionaries for the common path, including global-fit settings. The deeper calibrators and kernels modules expose small instruction records for code that wants to store, validate, or pass fit configuration as objects.

Curve fitting workflow

Public Surface

fuggers_py.curves exports only the first-layer curve objects and helpers:

Export

What it does

CurveSpec

Names one curve snapshot and fixes its date, currency, day-count rule, curve type, and out-of-range rule.

YieldCurve

Concrete discounting curve. Build it from quotes with YieldCurve.fit(...) or from an already-built internal kernel.

RatesTermStructure

Base type for rate curves.

DiscountingCurve

Base type for curves that can return discount factors.

CalibrationReport

Fit-level report attached to YieldCurve.calibration_report.

CalibrationPoint

One fitted quote row inside a report.

STANDARD_KEY_RATE_TENORS

Built-in key-rate tenor grid.

The root package does not export kernel classes, calibrator classes, old enum controls, or compatibility aliases. Import advanced objects from their submodules when you need them.

Curve class hierarchy

Basic Fit

from fuggers_py import Date
from fuggers_py.curves import CurveSpec, YieldCurve
from fuggers_py.rates import SwapQuote

reference_date = Date.from_ymd(2026, 4, 9)

curve = YieldCurve.fit(
    quotes=[
        SwapQuote("USD-SWAP-1Y", tenor="1Y", rate=0.040, currency="USD", as_of=reference_date),
        SwapQuote("USD-SWAP-2Y", tenor="2Y", rate=0.041, currency="USD", as_of=reference_date),
        SwapQuote("USD-SWAP-5Y", tenor="5Y", rate=0.043, currency="USD", as_of=reference_date),
    ],
    spec=CurveSpec(
        name="USD SOFR",
        reference_date=reference_date,
        day_count="ACT/365F",
        currency="USD",
        type="overnight_discount",
        extrapolation_policy="hold_last_zero_rate",
    ),
)

print(curve.rate_at(2.0))
print(curve.discount_factor_at(5.0))
print(curve.forward_rate_between(1.0, 5.0))

rate_at(...) returns the public zero-rate view of the curve. A zero rate is one rate from the curve date to a future tenor. discount_factor_at(...) turns a future cash flow into today’s value on the curve date.

YieldCurve wrapper

CurveSpec

CurveSpec is the identity record for one curve snapshot.

from fuggers_py import Date
from fuggers_py.curves import CurveSpec

spec = CurveSpec(
    name="USD OIS",
    reference_date=Date.from_ymd(2026, 4, 9),
    day_count="act/365f",
    currency="usd",
    type="overnight_discount",
    reference="SOFR",
    extrapolation_policy="error",
)

Important fields:

Field

Meaning

name

Human-readable curve name. Whitespace is stripped.

reference_date

Curve date. Quote as_of values must match it.

day_count

Day-count label. Strings are normalized.

currency

Curve currency. Strings such as "usd" become Currency.USD.

type

Plain string such as "nominal", "real", "overnight_discount", or "projection".

reference

Optional benchmark or index label.

extrapolation_policy

Plain string controlling tenors above max_t().

Supported extrapolation policies:

Policy

Behavior above max_t()

"error"

Raise TenorOutOfBounds.

"hold_last_zero_rate"

Hold the final public zero rate.

"hold_last_native_rate"

Ask the fitted kernel to hold its own final rate concept.

"hold_last_forward_rate"

Hold the terminal forward rate when the kernel supports that rule.

YieldCurve.fit(...)

YieldCurve.fit(
    quotes,
    *,
    spec,
    kernel="linear_zero",
    method="bootstrap",
    bond_target="dirty_price",
    regressors=(),
    kernel_params=None,
)

Main inputs:

Input

Meaning

quotes

Sequence of SwapQuote, BondQuote, or RepoQuote records.

spec

CurveSpec for the curve being built.

kernel

Curve shape name, such as "linear_zero" or "nelson_siegel".

method

Fit route: "bootstrap" or "global_fit".

bond_target

For global-fit bond price rows, choose "dirty_price" or "clean_price".

regressors

Optional bond regressor names used by global fit.

kernel_params

Optional shape-specific settings, such as spline knots.

The object form is optional. This call:

curve = YieldCurve.fit(
    quotes,
    spec=spec,
    kernel="cubic_spline",
    method="global_fit",
    bond_target="clean_price",
    kernel_params={"knots": (1.0, 2.0, 5.0)},
)

is equivalent to passing KernelSpec and CalibrationSpec objects.

Quote Inputs

Quote objects stay in the package that owns the instrument:

Quote type

Import from

What the fitter reads

SwapQuote

fuggers_py.rates

instrument_id, tenor, rate, currency, and as_of. The current fitter treats the rate as a zero-rate observation.

BondQuote

fuggers_py.bonds

The bond instrument, as_of, optional yield, optional clean or dirty price, optional fit weight, and optional regressors.

RepoQuote

fuggers_py.funding

instrument_id, repo term or dates, rate, currency, and as_of.

Shared quote rules:

  • as_of is required and must equal CurveSpec.reference_date.

  • If quote currency is supplied, it must equal CurveSpec.currency.

  • Bootstrap requires strictly increasing tenors after sorting.

  • Global fit allows duplicate tenors but all rows must fit one target type: rates, discount factors, or bond prices.

Fit Methods And Kernels

Bootstrap builds local curve nodes one by one. It is the exact-fit path.

Kernel

Meaning

"linear_zero"

Zero-rate nodes with linear interpolation.

"log_linear_discount"

Discount-factor nodes with log-linear interpolation.

"piecewise_constant"

Zero rates stay flat until the next node.

"piecewise_flat_forward"

Short forward rates stay flat between nodes.

"monotone_convex"

Smooth zero-rate curve built from positive tenor nodes.

Global fit estimates all parameters together. It is used when the curve shape has fewer parameters than quote rows, or when bond regressors are included.

Kernel

Required settings

"cubic_spline"

kernel_params={"knots": (...)} with at least three knots.

"nelson_siegel"

Optional initial_parameters and max_t. Needs at least four quotes.

"svensson"

Optional initial_parameters and max_t. Needs at least six quotes.

"exponential_spline"

decay_factors is required. Optional initial parameters and max_t.

Fit Reports

YieldCurve.fit(...) attaches a CalibrationReport to the returned curve.

Calibration report and calibration point model

Common report fields:

Field

Meaning

converged

Whether the solver reported success. Bootstrap reports True after a successful build.

method

"bootstrap" or "global_fit".

objective

"exact_fit" or "weighted_l2".

iterations

Solver iteration count.

max_abs_residual

Largest absolute fitted-minus-observed difference.

points

Tuple of CalibrationPoint rows.

solver

Solver name.

regressors

Regressor names used in global fit.

regressor_coefficients

Fitted coefficients in the same order as regressors.

kernel

Fitted kernel name for global fit.

kernel_parameters

Raw fitted kernel parameters for global fit.

objective_value

Final weighted objective value for global fit.

Each CalibrationPoint contains the quote id, tenor, observed value, fitted value, residual, observed kind, weight, and solver iterations. Global-fit rows also carry the curve-only value and optional bond price or yield diagnostics.

Curve Moves

DiscountingCurve.shifted(...) and DiscountingCurve.bumped(...) return a new DiscountingCurve. Use shifted(...) when the whole zero-rate curve should move by one amount. Use bumped(...) when one or more tenor points should move and the move should be interpolated across a tenor grid.

Curve move methods
from fuggers_py.curves import STANDARD_KEY_RATE_TENORS

shifted = curve.shifted(shift=0.0001)

bumped = curve.bumped(
    tenor_grid=STANDARD_KEY_RATE_TENORS,
    bumps={
        2.0: 0.0001,
        5.0: 0.0002,
    },
)

print(shifted.zero_rate_at(2.0))
print(bumped.zero_rate_at(2.0))

The returned object keeps the discounting methods, but it is a wrapper rather than a fitted YieldCurve.

Advanced Submodules

The root package is enough for normal curve work: fit a curve, move it, and query rates or discount factors.

The table below is not a dump of every class inside src/fuggers_py/curves. It lists the deeper imports that are meant to be usable from user code today. Other classes in these folders are implementation details used by YieldCurve.fit(...).

Import

Public names

Use it when

fuggers_py.curves.calibrators

CalibrationSpec

You want one object that stores the fit route, objective, bond target, and regressor order.

fuggers_py.curves.kernels

KernelSpec

You want one object that stores the kernel family and its parameters.

fuggers_py.curves.conversion

ValueConverter

You need rate, discount-factor, or forward-rate conversions without building a curve.

Example: keep a reusable global-fit setup in one object.

from fuggers_py.curves.calibrators import CalibrationSpec
from fuggers_py.curves.kernels import KernelSpec

fit_method = CalibrationSpec(
    method="global_fit",
    bond_target="clean_price",
    regressors=("liquidity", "specialness"),
)

fit_shape = KernelSpec(
    kind="cubic_spline",
    parameters={"knots": (1.0, 2.0, 5.0, 10.0)},
)

curve = YieldCurve.fit(
    quotes,
    spec=spec,
    method=fit_method,
    kernel=fit_shape,
)

Example: use conversion helpers without building a curve.

from fuggers_py.curves.conversion import ValueConverter

discount_factor = ValueConverter.zero_to_df(0.0425, 5.0)
zero_rate = ValueConverter.df_to_zero(discount_factor, 5.0)

Concrete kernel and calibrator classes live in implementation modules under fuggers_py.curves.kernels and fuggers_py.curves.calibrators. They are not the public fitting interface. Most users should not instantiate them directly; YieldCurve.fit(...) builds them and returns a YieldCurve.

At the moment, the public fitting workflows do not require deeper imports. The main reasons to use them are configuration reuse, checking fit instructions before a run, or writing lower-level extension code.

Work In Progress

Some curve code exists, but is not yet a complete user-facing workflow.

Area

What exists today

What is not complete yet

fuggers_py.curves.multicurve

CurrencyPair and RateIndex identifiers for describing FX pairs and rate indexes.

A public workflow for fitting and solving linked curves together.

Concrete kernel classes

Internal classes that YieldCurve.fit(...) uses to represent fitted shapes.

A stable direct-construction API for users.

Concrete calibrator classes

Internal classes that turn quotes and specs into fitted kernels.

A stable direct-calibrator API for users.

Use these areas for internal or research code only. The supported user path is still YieldCurve.fit(...), which returns one YieldCurve and one CalibrationReport.