Using a Null Calendar to Preserve QuantLib Coupon Dates
Summary
The document concerns a QuantLib schedule intended to place bond coupon payments on fixed January and July dates. The schedule is built backward from maturity with semiannual periods, unadjusted business-day conventions, and a specified calendar. The author observes that generated dates differ from the intended pattern in some years and provides a CPI-linked bond example, but the displayed output and detailed diagnosis are absent.
The answer reports that replacing the chosen business calendar with QuantLib’s NullCalendar produced dates matching Bloomberg’s calculations. This points to calendar adjustment as the source of the discrepancy: a NullCalendar does not adjust dates for weekends or holidays. The answer is brief and reports a match for this particular convention; it does not explain the underlying schedule-generation rules, identify which dates changed, or establish that NullCalendar is appropriate for other instruments. Users would need to confirm the required market convention before applying the approach elsewhere.
Key ideas
- A QuantLib schedule can shift intended coupon dates when its calendar applies business-day rules.
- The reported fix for this example was to use a NullCalendar.
- The answer says this matched Bloomberg’s calculations for the schedule in question.
- A NullCalendar does not make weekend or holiday adjustments, so its suitability depends on the instrument convention.
Tags
Full text
# Generate QuantLib schedule with same dates as payment
# Generate QuantLib schedule with same dates as payment
I am trying to generate a schedule in QuantLib that has all the coupon payments on january 15th and july 15th. It seems that this is done, but every four years the schedule seems to generate different dates. I don't want this to occur, as I'm trying to follow a very particular convention.
```
from QuantLib import *
# make cpi index
base_date = Date(1,5,2025)
valuation_date = Date.todaysDate()
end_date = base_date + Period(100, Years)
rates=[0.0,0.0]
zero_inflation = ZeroInflationCurve(valuation_date, [base_date, end_date], rates, Monthly, ActualActual(ActualActual.ISDA))
zero_inflation_ts_handle = ZeroInflationTermStructureHandle(zero_inflation)
cpi_index = USCPI(zero_inflation_ts_handle)
# add historical CPI fixings
# for march, april, may
cpi_vals = [319.799, 320.795, 321.465]
for i in range(3,6):
cpi_index.addFixing(Date(1,i,2025), cpi_vals[i-3])
issue_date = Date(31, 1, 2025)
maturity_date = Date(15, 1, 2035)
tenor = Period(Semiannual)
calendar = UnitedStates(UnitedStates.NYSE)
first_coupon = Date(15, 7, 2025)
next_to_last = Date(15, 1, 2035)
calendar = UnitedKingdom()
business_convention = Unadjusted
date_generation = DateGeneration.Backward
month_end = False
schedule = Schedule (issue_date, maturity_date, tenor,
calendar, business_convention,
business_convention, date_generation,
month_end)
coupon_rate = .02125
coupons = [coupon_rate]
settlement_days = 1
face_value = 1000000
base_cpi = 315.58677
cpi_bond = CPIBond(settlement_days, face_value, False, base_cpi, Period(3, Months), cpi_index,
CPI.Linear, schedule, coupons, Thirty360(Thirty360.USA))
bond_yield = cpi_bond.bondYield(100,Thirty360(Thirty360.USA),CompoundedThenSimple,Monthly,Date.todaysDate(),1.0e-9, 100000)
#cleanPrice, dayCounter, compounding, frequency, settlementDate=Date, accuracy=1.0e-8, maxEvaluations=100
print(bond_yield)
for cf in cpi_bond.cashflows():
print(cf.date().ISO(), cf.amount())
```
This is generating the following schedule:
## Answer by Thomas David (score 0)
https://quant.stackexchange.com/a/83778
I had to make the calendar NullCalendar - this matches the schedule that Bloomberg uses in its calculations.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.