Pricing a Floating Bond in quantlib using Python
Asked Answered
S

1

10

I am trying to price a very basic floating rate bond in python using the Quantlib (v1.2) SWIG wrapper. I modified the example included with the documentation.

My bond has a 4 year maturity. The libor is set to 10% and the spread of the bond is 0. My question is if I am discounting at the rate of 10%, why isn't the PV of the bond 100? I am getting a value of 99.54.

Thanks!

from QuantLib import *

frequency_enum, settle_date = 4, Date(5, 1, 2010)
maturity_date = Date(5, 1, 2014)
face_amount = 100.0
settlement_days = 0
fixing_days = 0

calendar = NullCalendar()
settle_date = calendar.adjust(settle_date)
todays_date = calendar.advance(settle_date, -fixing_days, Days)
Settings.instance().evaluationDate = todays_date

rate = 10.0 / 100.0

flat_forward = FlatForward(settle_date,
                           rate,
                           Thirty360(),
                           Compounded,
                           frequency_enum)

discounting_term_structure = RelinkableYieldTermStructureHandle(flat_forward)
index_term_structure = RelinkableYieldTermStructureHandle(flat_forward)

index = USDLibor(Period(3, Months), index_term_structure)

schedule = Schedule(settle_date,
                    maturity_date, Period(frequency_enum),
                    NullCalendar(),
                    Unadjusted, Unadjusted,
                    DateGeneration.Forward, False)

floating_bond = FloatingRateBond(settlement_days,
                                 face_amount,
                                 schedule,
                                 index,
                                 Thirty360(),
                                 Unadjusted,
                                 fixing_days,
                                 [],   # Gearings
                                 [0],  # Spreads
                                 [],      # Caps
                                 [],      # Floors
                                 False,    # Fixing in arrears
                                 face_amount,
                                 settle_date)

bond_engine = DiscountingBondEngine(discounting_term_structure)
floating_bond.setPricingEngine(bond_engine)

# coupon pricers
pricer = BlackIborCouponPricer()

volatility = 0.0
vol = ConstantOptionletVolatility(settlement_days,
                                  calendar,
                                  Unadjusted,
                                  volatility,
                                  Thirty360())

pricer.setCapletVolatility(OptionletVolatilityStructureHandle(vol))
setCouponPricer(floating_bond.cashflows(), pricer)

print floating_bond.NPV(), floating_bond.cleanPrice(), floating_bond.dirtyPrice()
Silberman answered 7/3, 2013 at 14:30 Comment(0)
M
8

The coupons rates are fixed using the USDLibor day counter (that is, Actual/360) which doesn't match the payment day counter you provided (30/360). You can see it by inspecting the coupons:

cfs = floating_bond.cashflows()
coupons = [ as_coupon(c) for c in cfs[:-1] ] # the last one is the redemption
print [ (c.rate(), c.accrualPeriod()) for c in coupons ]

which gives you T = 0.25 for all coupons, but rates lower than 10%.

To get the price you want, you have to match rate and accrual period. One way is to pass Actual360() as the bond day counter, which gives a price of 100.002 on my machine (I haven't investigated further, but the discrepancy might be due to the end date for the LIBOR fixing, which is determined using the USD calendar and might not match the end of the coupon exactly). Another way is to create a custom LIBOR index with an internal 30/360 day counter; I haven't tried this myself, but you can do it by creating an appropriate instance of the IborIndex class.

Merca answered 8/3, 2013 at 15:54 Comment(1)
Thanks a lot. I created a custom index and I got an exact result of 100.0! Custom index is: index = IborIndex('USD Libor', Period(3, Months), settlement_days, USDCurrency(), NullCalendar(), Unadjusted, False, Thirty360(), index_term_structure)Silberman

© 2022 - 2024 — McMap. All rights reserved.