Dear ladies and gentlemen,
when considering the bootstrapping of a coupon bond according to the example "FittedBondCurve.cpp" I found an inconsistency in the results of the bootstrapper according to
boost::shared_ptr<YieldTermStructure> ts0 (
new PiecewiseYieldCurve<Discount,LogLinear>(curveSettlementDays,
calendar,
instrumentsB,
bondDayCount));
This inconsistency was as follows: For simplicity I considered a coupon bond with only one remaining payment date t_1, at which the coupon c and the redemption 1 will be paid. Let t_0 be the last coupon date and today t is within the interval [t_0,t_1]. For this situation the discount factor df(t,t_1) was calculated according to
Clean Price = df(t,t_1) * [ 1 + c*(t_1-t) ]. (1)
This formula refers to a Clean Price which is theoretically correct, i.e. the accrued amount is discounted.
On the other hand, what has actually to be paid (marked standard) for a bond is the Clean price + the accrued amount according to the simple formula c*(t-t_0) which does not take into account discounting the accrued amount. The net present value of future payments must equal the spot price:
Clean Price + c * (t-t_0) = df(t,t_1) * [1+c]. (2)
In the middle of a payment period the resulting discount factors df(t,t_1) of (1) and (2) differ most. In my example this lead to a difference in the zero rate of around 10 BIPs.
Best regards,
Karl Riedel
Karl,
may you point out the places in the code where the calculations (1) and (2) are performed?
Also, do you have some code to reproduce the error?
Luigi
Hello Luigi,
unfortunately I did not have the time to search the relevant position(s) in the code. I just compared the results of Quantlib bootstrapping to formula (1) and (2) considering an easy example. The bootstrapper calculates results according to formula (1) while formula (2) describes the correct net present value.
Please find the example code attached. The produced output is as follows:
Today's date: January 2nd, 2009
Bootstrapping 1 bond with 0.5 years tenor and 4% coupon ...
According to
Clean Price = df(t,t_1) * [ 1 + c*(t_1-t) ]. (1)
df = 1 / (1+0.5*c) = 1 / 1.02 = 0.980392156863
ts0->discount(maturity) = 0.980392156863
r = -log(df)/0.5 = 0.0396052545924
ts0->zeroRate(... = 0.0396052545924
According to correct net present value
Clean Price + c * (t-t_0) = df(t,t_1) * [1+c]. (2)
df = (1+0.5*c)/(1+c) = 1.02/1.04 = 0.980769230769
r = -log(df)/0.5 = 0.0388361717142
Drücken Sie eine beliebige Taste . . .
Karl
File Added: CleanpriceInconsistencyExample.txt
Example Code
Clean and dirty prices should be accounted for correctly now.