book_irds3 icon indicating copy to clipboard operation
book_irds3 copied to clipboard

Erratum: 22.10.4 Impact of IRS risk rather than zero coupon deposits

Open attack68 opened this issue 1 month ago • 0 comments

The formula:

$$ 1 + r_i^Z \approx \left(1 + \frac{R_i}{n} \right )^n $$

is incorrect and should be correctly written, assuming n is number of years and R is an annual swap rate as:

$$ 1 + n r_i^Z \approx \left(1 + R_i \right ) ^n $$

which implies that the following line should read:

$$ \beta_i \approx \left ( 1 + R_i \right ) ^{1-n} $$

Extension

For additional information, if f is a swap frequency (e.g 2=semiannual) not equal to annual, this could be re-expressed as:

$$ 1 + n r_i^Z \approx \left ( 1 + \frac{R_i}{f} \right ) ^{fn} $$

leading to:

$$ \beta_i \approx \left ( 1 + \frac{R_i}{f} \right ) ^{1-fn} $$

Numerical Validation

It is possible to validate these calculations using rateslib

from rateslib import *  # v 2.1.1

curve = Curve(
    nodes={dt(2000, 1, 1): 1.0, dt(2005, 1, 1): 1.0, dt(2010, 1, 1): 1.0, dt(2020, 1, 1): 1.0},
    calendar="ldn",
    convention="act365f",
    id="sonia",
)

# The IRS are semi-annual in frequency with tenors of 5Y, 5Y and 10Y respectively 
solver_irs=Solver(
    curves=[curve],
    instruments=[
        IRS(dt(2000, 1, 1), "5y", spec="gbp_irs", frequency="S", curves=curve),
        IRS(dt(2005, 1, 1), "5y", spec="gbp_irs", frequency="S", curves=curve),
        IRS(dt(2010, 1, 1), "10y", spec="gbp_irs", frequency="S", curves=curve),
    ],
    s=[2.5, 2.8, 2.7],
)

# The Zero coupon deposit rates have matching dates.
instruments=[
    IRS(dt(2000, 1, 1), "5y", spec="gbp_irs", frequency="Z", curves=curve),
    IRS(dt(2005, 1, 1), "5y", spec="gbp_irs", frequency="Z", curves=curve),
    IRS(dt(2010, 1, 1), "10y", spec="gbp_irs", frequency="Z", curves=curve),
]
solver_zero_deposits=Solver(
    curves=[curve],
    instruments=instruments,
    s=[float(inst.rate(curves=curve)) for inst in instruments],
)
Image
(1 + 0.025 / 2) ** (1 - 10) = 0.8942206877308926
(1 + 0.028 / 2) ** (1 - 10) = 0.8823855856918761
(1 + 0.027 / 2) ** (1 - 20) = 0.7750838582503535

Comment

These are approximations. Deviations from assumptions, like using splines curves with global risk sensitivity may create larger errors. Adding interpolation="spline" to the Curve configuration and re-running these calculations will demonstrate the errors:

Image

attack68 avatar Nov 28 '25 11:11 attack68