Skip to content
All library documents

Handling Irregular First Coupon Dates in Bond Schedules

Article Quant Q&A · Author: Nick von T

Summary

The document explains how an irregular first coupon period can cause a programmatically generated bond schedule to disagree with vendor calculations of accrued interest, clean and dirty prices, or duration. A schedule built backward from maturity may insert a coupon date shortly after accrual begins, even when the bond’s actual first coupon comes later. In the example, matching data after the first regular coupon suggests the discrepancy is tied to the initial stub period.

The recommended method is to obtain the first coupon date from the bond’s prospectus or reliable instrument reference data, then pass that date explicitly to the QuantLib schedule constructor. The answer cautions against inferring the date from a generic rule: an initial period may be unusually short or long, and an automated guess can be wrong. Some bonds have bespoke schedules that require supplying all dates directly. Vendor data can also contain mistakes, especially for recently issued bonds, so checking the prospectus and validating indicative data remain important. The example motivates the guidance but does not give a full pricing implementation.

Key ideas

  • A generated schedule can misstate the initial coupon period when the first coupon date is irregular.
  • Use the instrument’s documented first coupon date as an explicit schedule input.
  • Do not infer an odd first coupon period from a general programmatic guess.
  • For bespoke bonds, supply the full schedule as custom dates.
  • Reference data can contain errors, so verify important schedule dates against source documentation.

Tags

Full text
# Coupon schedule issue with initial coupon date


# Coupon schedule issue with initial coupon date












I am trying to match the accrued interest, clean price, dirty price, and duration from the iBoxx underlying data. I've come close to perfectly matching their measurements but have run into an edge case where I'm not sure how best to approach it.

I have a bond issued on 2017-11-09 with an interest accrual start date on 2017-11-14 and maturity date of 2024-11-15. When I create the Schedule object as below:

```
# Create schedule
    Schedule = ql.Schedule(StartDate, 
                            MaturityDate,
                            ql.Period(CouponFrequency),
                            Calendar,
                            ql.Unadjusted, 
                            ql.ModifiedFollowing,
                            ql.DateGeneration.Backward, 
                            False)
```

I get the following output when I call

```
list(Schedule)
```

I get

```
[Date(14,11,2017), Date(15,11,2017), Date(15,5,2018), Date(15,11,2018), Date(15,5,2019), Date(15,11,2019), Date(15,5,2020), Date(15,11,2020), Date(15,5,2021), Date(15,11,2021), Date(15,5,2022), Date(15,11,2022), Date(15,5,2023), Date(15,11,2023), Date(15,5,2024), Date(15,11,2024)]
```

As you can see from the first two entries, we have the start date of interest accrual and then a coupon date the day after (on the semi-annual date associated with the maturity date).

My question is: should the interest accrual reset on 2017-11-15? For reference the cusip is 911312BL9. I found the following information through FactSet that the initial coupon date is in fact 2018-05-15. Therefore, it seems like the way I've constructed my Schedule is incorrect. However, I'm not sure how to adjust my Python code. The difference between my output and iBoxx disappears after 2018-05-15 indicating that they are properly accounting for the fact that interest accrual does not reset on 2017-11-15.

## Answer by Dimitri Vulis (score 2, accepted)

https://quant.stackexchange.com/a/80268

Sometimes an odd coupon period is long and sometimes it is short. In your example, it's possible, but unlikely, that the first coupon period is only 5 days long. It's more likely, but not certain, that the first coupon period is 5 days longer than a regular period. It is an extremely bad and dangerous practice to try to guess programmatically which one it is, because sometimes your guess will be wrong. Instead you should obtain the first coupon date as part of your instrument's indicative data and pass it to the scheduler constructor. In Python Quantlib, the first coupon date is the next positional argument to ql.Schedule after EndOfMonth=False

The dates should be in the bond's prospectus. If you get the bond indicative data from a data vendor like Bloomberg, there should be a field for it, but you should check - data vendors sometimes drop the ball.

Your comment mentions Mergent Fixed Income Securities Database (FISD) from FTSE Russel Mergent https://www.mergentonline.com/ . I've never used it myself. The database description reads:

> The database, designed for academia, contains issue details on over 140,000 corporate, corporate MTN (medium-term note), supranational, U.S. Agency, and U.S. Treasury debt securities and includes more than 550 data items. Mergent FISD provides details on debt issues and the issuers, as well as transactions by insurance companies.

Sometimes the entire schedule is so bespoke that it cannot be recreated using a programmatic scheduler, and then you have to pass the entire list of dates as a custom schedule. This example doesn't sound so bad as to need that. US911312BL96 looks like a pretty vanilla corporate bond from United Parcel Service.

My typical experience with more exotic and emerging markets bonds and Bloomberg indicative data has been:

- a bond gets issued

- Bloomberg's analysts in a low-cost location extract the indicative data and retype into their databases, often with mistakes on the first try

- lots of Bloomberg customers look at the indicative data on Bloomberg, find errors, and usually tell Bloomberg support (F1 F1) when they do

- Bloomberg eventually corrects their indicative data

As the result, Bloomberg is effectively crowdsourced, and therefore usually correct, although for recently issues bonds you should watch out for data errors.

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.