Class IsdaRateCurve
Plain idea. The quoted swaps are priced at par one at a time,
shortest first. For each new maturity we search for the one zero rate
that makes that swap worth zero, keeping the zero rates already found for
the shorter swaps. The result is an IsdaCurve, so it plugs
straight into IsdaCdsModel.
Formal statement. With trade date T (the curve base
date) and spot S = T + 2 business days, a swap of tenor m
months matures at M = MF(S + m months) (modified following). Its
fixed leg pays annually on MF(S + 12k months), the last payment on
M; a tenor below one year has a single payment. Accrual fractions
are ACT/360. The zero rate r_i at t_i = (M - T)/365 solves
P(M) + c * sum_k tau_k P(d_k) - P(S) = 0, where P is the
IsdaCurve with knots (t_1..t_i, r_1..r_i), linear in
r t between knots and flat outside them. The root is found by 200
bisection steps on [-0.5, 1.0], far more than needed to reach
double precision.
Worked example. Trade Monday 2021-04-26 on a weekends-only
calendar, so spot is 2021-04-28. A 6M swap at 2% matures 2021-10-28 and
pays once, 183/360 of the coupon. Its knot sits at 185/365 years, and the
zero rate solves P(185/365) (1 + 0.02 * 183/360) = P(2/365); with
the flat extrapolation of IsdaCurve both discount factors use the
same rate, giving r = ln(1 + 0.02 * 183/360) / (183/365), about
2.0175% (own test, IsdaRateCurveTest).
Evidence. Used with the official ISDA CDS Standard Model RFR
grids (cdsmodel.com, USD SOFR 2021-04-26 and 2022-06-21, 7164 rows each),
the curve reproduces cash settlement within 1e-6 USD on 10mm notional and
clean upfront within 1e-13 (published reference, checked by
IsdaGridVerificationTest when QFL_ISDA_GRID_DIR is set).
Money-market deposits are not supported: the RFR grids quote swaps only.
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionstatic IsdaCurvebootstrapSwaps(LocalDate tradeDate, List<IsdaRateCurve.Swap> swaps, BusinessCalendar calendar) Bootstraps the swap-only zero curve.static doubleparSwapValue(IsdaCurve curve, LocalDate tradeDate, IsdaRateCurve.Swap swap, BusinessCalendar calendar) Value per unit notional of a receive-fixed swap oncurveunder the conventions above, including the notional exchange: zero for a quote the curve was bootstrapped from.
-
Method Details
-
bootstrapSwaps
public static IsdaCurve bootstrapSwaps(LocalDate tradeDate, List<IsdaRateCurve.Swap> swaps, BusinessCalendar calendar) Bootstraps the swap-only zero curve.- Parameters:
tradeDate- curve base dateswaps- par swaps in strictly increasing maturity ordercalendar- business calendar for spot, rolls and payment dates- Returns:
- zero curve with one knot per swap maturity (ACT/365F from trade date)
-
parSwapValue
public static double parSwapValue(IsdaCurve curve, LocalDate tradeDate, IsdaRateCurve.Swap swap, BusinessCalendar calendar) Value per unit notional of a receive-fixed swap oncurveunder the conventions above, including the notional exchange: zero for a quote the curve was bootstrapped from.- Parameters:
curve- discount curve with base datetradeDatetradeDate- curve base dateswap- the swapcalendar- business calendar- Returns:
P(M) + c * sum tau_k P(d_k) - P(S)
-