Menu

#88 Bootstrapping for bonds: Inconsistency in the clean price

None
closed-out-of-date
nobody
None
5
2017-12-06
2009-03-18
Karl Riedel
No

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

Discussion

  • Luigi Ballabio

    Luigi Ballabio - 2009-03-18

    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

     
  • Karl Riedel

    Karl Riedel - 2009-03-19

    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

     
  • Karl Riedel

    Karl Riedel - 2009-03-19

    Example Code

     
  • Luigi Ballabio

    Luigi Ballabio - 2017-12-06

    Clean and dirty prices should be accounted for correctly now.

     
  • Luigi Ballabio

    Luigi Ballabio - 2017-12-06
    • status: open --> closed-out-of-date
    • Group: -->
     

Log in to post a comment.