0
$\begingroup$

When we price a fixed rate bond using Quantlib, we generally take below approach -

import QuantLib as ql
import pandas as pd

todaysDate = ql.Date(31, 8, 2019)
ql.Settings.instance().evaluationDate = todaysDate

spotDates = [ql.Date(1,9,2019), ql.Date(5,9,2019), ql.Date(7,9,2019)]
spotRates = [0.066682, 0.067199, 0.067502]

dayCount = ql.Actual365Fixed()
calendar = ql.SouthAfrica()
interpolation = ql.Linear()
compounding = ql.Compounded
compoundingFrequency = ql.Semiannual

spotCurve = ql.ZeroCurve(spotDates, spotRates, dayCount, calendar, interpolation, compounding, compoundingFrequency)
spotCurveHandle = ql.YieldTermStructureHandle(spotCurve)

issueDate = ql.Date(20, 4, 2017)
maturityDate = ql.Date(20, 4, 2019)
tenor = ql.Period(ql.Semiannual)
calendar = ql.SouthAfrica()
bussinessConvention = ql.Following
dateGeneration = ql.DateGeneration.Backward
monthEnd = False

schedule = ql.Schedule(issueDate, maturityDate, tenor, calendar, bussinessConvention, bussinessConvention, dateGeneration, monthEnd)

dayCount = ql.Actual365Fixed()
couponRate = 0.0925
coupons = [couponRate]

settlementDays = 3
faceValue = 100
fixedRateBond = ql.FixedRateBond(settlementDays, faceValue, schedule, coupons, dayCount)

bondEngine = ql.DiscountingBondEngine(spotCurveHandle)
fixedRateBond.setPricingEngine(bondEngine)

fixedRateBond.NPV()

However my question is - instead of a typical bond if I need to price the Annuity (i.e. there is no Principal payment at the maturity), how can I modify above codebase?

Any pointer will be highly appreciated.

$\endgroup$
1
$\begingroup$

The bond engine uses the CashFlows::npv() method internally, so you can do the same after stripping the principal payment from the bond cashflows:

cashflows = fixedRateBond.cashflows()
coupons = cashflows[:-1] # all except the last

includeSettlementDateFlows = False

annuity = CashFlows.npv(
    coupons,
    spotCurveHandle,
    False,
    spotCurveHandle.referenceDate()
)

This will be consistent to fixedRateBond.NPV() (and you can verify it by not stripping the last coupon, i.e., setting coupons = cashflows: you'll get the same result).

However, note that this (and fixedRateBond.NPV()) discounts to the reference date of the spot curve, i.e., to the first of the spotDates. If you want to discount to the settlement date of the bond, you should use instead

annuity = CashFlows.npv(
    coupons,
    spotCurveHandle,
    False,
    bond.settlementDate()
)

and you should also use fixedRateBond.dirtyPrice() instead of fixedRateBond.NPV().

$\endgroup$
5
  • 2
    $\begingroup$ To add to Luigi's answer, you could also use the FixedRateLeg class and get just the coupons: ql.FixedRateLeg(schedule, dayCount, [faceValue], [couponRate] ) $\endgroup$ – David Duarte Aug 14 '20 at 13:02
  • 1
    $\begingroup$ Thanks. What is the purpose of "includeSettlementDateFlows = False" $\endgroup$ – Bogaso Aug 14 '20 at 16:48
  • $\begingroup$ Additionally, I am getting error "Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'npv'" $\endgroup$ – Bogaso Aug 14 '20 at 17:06
  • $\begingroup$ About the error, careful not to confuse CashFlows (the class) with cashflows (the variable) in the above. Capitalization matters. $\endgroup$ – Luigi Ballabio Aug 14 '20 at 17:20
  • $\begingroup$ With includeSettlementDateFlows set to False (the default), if a coupon pays today it's not included in the NPV. If set to True, the coupon is included. $\endgroup$ – Luigi Ballabio Aug 14 '20 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.