Interest Rate Swap Valuation and Applications › The Swap Curve
Quantitative FinanceAll chapters Interest Rate Swap Valuation and Applications › The Swap CurveOne section · Sections in this chapter6 / 17 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
A par swap curve shows fixed rates for zero-initial-value swaps across maturities under specified contract conventions. Swap quotes are used to calibrate projection and discount curves for valuing interest-rate products. The resulting curves are valuation inputs; par quotes are not zero-coupon discount factors and do not by themselves specify every derivative's risks.
Why the Swap Curve Matters
Government bond yields can be affected by supply-demand imbalances, tax considerations, and liquidity preferences. Swap rates also contain more than expectations: their interpretation depends on the projection and discount curves, risk premia, and contract terms. For example, investor demand or central-bank purchases can make particular government bonds trade rich or cheap relative to comparable maturities; above-par or below-par price alone does not establish that effect. The swap curve is particularly important because:
- It provides swap-rate quotes across maturities, often out to 30 years or more; a fitted curve connects those quotes without uniquely identifying expected future short-term rates.
- Swap quotes are inputs to curve calibration. The resulting discount factors, together with appropriate floating-rate projection curves and risk-model inputs, support derivative valuation. A par swap quote is not itself a zero-coupon discount factor, and option valuation also needs assumptions about future rate variability.
- Historically, unsecured IBOR-based swap curves reflected an interbank funding benchmark, including bank credit and liquidity components. RFR-based overnight index swap (OIS) curves instead reference overnight near-risk-free rates and do not generally measure banks' unsecured term borrowing costs (BIS, Beyond LIBOR).
- Liquidity and quote freshness vary by market and tenor. A fitted curve may use interpolation or indicative inputs, so a displayed curve point is not necessarily a fresh executable quote.
Bootstrapping the Swap Curve
Bootstrapping is the process of extracting discount factors from market swap rates. The term "bootstrapping" refers to the iterative nature of the procedure: we use information derived from shorter maturities to solve for discount factors at longer maturities. The technique works iteratively, starting from the shortest maturity and working outward.
For a par swap with maturity and swap rate , the no-arbitrage condition requires that the value of the fixed leg equals the value of the floating leg. In the matching-reset single-curve model, the corresponding floating-rate bond including hypothetical principal is worth 1 per unit notional. A par swap therefore has a corresponding fixed-rate bond worth 1 as well:
where:
- : par swap rate for maturity
- : number of payment periods up to maturity
- : day count fraction for period
- : discount factor at coupon date . For the explicit last-factor solve, factors with must already be known or fixed by a stated interpolation rule; is the new endpoint.
- : discount factor for the final maturity (the unknown variable)
On a coupon-complete grid, earlier coupon-date discount factors are available from previous steps. Sparse quotes leave unquoted coupon dates: a 5-year annual-pay swap still pays at year 4 even if no 4-year swap is quoted. We therefore specify an interpolation rule and include those dates in the calibration. If their discounts depend on the new endpoint, we solve the full coupon equation for that endpoint.
We can rearrange the no-arbitrage condition to solve explicitly for the unknown discount factor by separating the final term and isolating :
where:
- : discount factor for maturity
- : par swap rate for maturity
- : number of payment periods
- : day count fraction for period
- : known discount factor for time
- : day count fraction for the final period
- : remaining value to be covered by the final payment
- : final coupon plus hypothetical principal per unit notional, the coefficient multiplying the final discount factor
The explicit quotient requires and a positive solved discount factor. It applies when the earlier coupon factors are fixed inputs. For this sparse-quote example, we instead interpolate continuously compounded zero rates linearly between quoted nodes, keep the first zero rate flat before the first node, and solve each full coupon equation with the trial endpoint included. Integer payment indices generate every regular coupon date. The resulting curve must reprice every input quote using those same conventions. This specifies a model curve; finite quotes do not uniquely determine its values at all other dates.
def bootstrap_swap_curve(swap_rates, maturities, payment_freq=0.5):
"""Calibrate a regular-coupon single curve to hypothetical par quotes.
payment_freq is the accrual interval in years, not payments per year.
Maturities must be positive increasing multiples of that interval.
Continuous zero rates are linear between quoted nodes and flat before
the first node. Each trial includes the current endpoint when valuing
every contractual coupon, including unquoted intermediate dates.
This teaching example does not support stubs or multiple curves.
"""
from scipy.optimize import brentq
swap_rates = np.asarray(swap_rates, dtype=float)
maturities = np.asarray(maturities, dtype=float)
delta = float(payment_freq)
if (
swap_rates.ndim != 1
or maturities.ndim != 1
or len(swap_rates) != len(maturities)
or not len(maturities)
or not np.all(np.isfinite(swap_rates))
or not np.all(np.isfinite(maturities))
or not np.isfinite(delta)
or delta <= 0
or np.any(maturities <= 0)
or np.any(np.diff(maturities) <= 0)
):
raise ValueError(
"Use finite aligned quotes and positive increasing maturities."
)
period_counts = np.rint(maturities / delta).astype(int)
if (
np.any(period_counts < 1)
or not np.allclose(period_counts * delta, maturities, rtol=0, atol=1e-10)
or np.any(1 + swap_rates * delta <= 0)
):
raise ValueError(
"Use regular whole-period maturities and admissible coupon rates."
)
zero_rates = np.empty(len(maturities))
for i, (rate, maturity, periods) in enumerate(
zip(swap_rates, maturities, period_counts)
):
times = delta * np.arange(1, periods + 1)
nodes = maturities[: i + 1]
def par_residual(trial_zero):
trial_rates = np.append(zero_rates[:i], trial_zero)
discounts = np.exp(-np.interp(times, nodes, trial_rates) * times)
return rate * delta * np.sum(discounts) + discounts[-1] - 1
# Explicit finite bracket for this educational rate range; reject
# inconsistent/unbracketed quotes rather than return a false curve.
lower, upper = -0.5, 1.0
if par_residual(lower) * par_residual(upper) > 0:
raise ValueError(
"Quote has no root in the stated illustrative zero-rate bracket."
)
zero_rates[i] = brentq(par_residual, lower, upper, xtol=1e-14)
discount_factors = np.exp(-zero_rates * maturities)
return discount_factors, zero_rates
# Hypothetical par swap quotes; single-curve regular-coupon exercise
market_maturities = np.array([1, 2, 3, 5, 7, 10])
market_swap_rates = np.array([0.047, 0.050, 0.052, 0.055, 0.057, 0.058])# Simplified bootstrap for illustration
def simple_bootstrap(swap_rates, maturities):
"""Annual-payment specialization of the full-coupon calibration above."""
return bootstrap_swap_curve(swap_rates, maturities, payment_freq=1.0)
# Bootstrap the curve
boot_disc_factors, boot_zero_rates = simple_bootstrap(
market_swap_rates, market_maturities
)Bootstrapped Swap Curve
=================================================================
Maturity Swap Rate Discount Factor Zero Rate
-----------------------------------------------------------------
1 yr 4.700% 0.955110 4.5929%
2 yr 5.000% 0.906900 4.8862%
3 yr 5.200% 0.858532 5.0844%
5 yr 5.500% 0.763759 5.3901%
7 yr 5.700% 0.675665 5.6008%
10 yr 5.800% 0.565404 5.7021%
This figure compares annual-pay par quotes with continuously compounded zero rates. For the stated hypothetical data, the calibrated zeros increase from 4.5929% at one year to 5.7021% at ten years. They are not interchangeable with par coupons: the latter price a full coupon schedule, whereas each zero rate describes a single payment.
