Yield Conventions for Bonds with Long First Coupon Periods
Summary
This note examines a fixed-rate bond with a five-year first coupon period followed by semiannual coupons. In the described QuantLib setup, the calculated yield is below the coupon rate even though the bond is issued at par; the author reports that Bloomberg gives a yield equal to the coupon rate. The stated cause is the yield function's fixed payment-frequency assumption, which does not reflect the unusually long initial period, and the note asks how to obtain the desired yield and price behavior.
The author clarifies that the target is a tax-basis convention rather than conventional yield to maturity. Under the proposed convention, each actual coupon amount determines its own accrual factor in sequential discounting, so a long first coupon period does not compound as multiple regular coupons would. The desired clean-price path is par throughout the bond's life. The post explains the motivation and formula, but does not provide a working QuantLib solution or establish that this convention is appropriate beyond the author's tax-basis use case.
Key ideas
- A long first coupon period can make a fixed-frequency yield calculation diverge from the coupon rate at par.
- The example bond has a five-year initial period followed by semiannual payments.
- The author seeks a tax-basis yield convention based on actual coupon amounts and accrual periods.
- The proposed sequential discounting rule is intended to keep the clean price at par in this example.
- The note does not provide an implemented QuantLib fix and distinguishes its desired convention from standard yield to maturity.
Tags
Full text
# Setting up QuantLib to get correct yield for bond with long first payment period
# Setting up QuantLib to get correct yield for bond with long first payment period
I am dealing with fixed rate bonds. There is one particular bond, 34659UAC0, that caught my eye. This bond has a first coupon period of a whopping 5 years, followed by regular periods of 6 months. My current setup seems unable to deal with this properly. Here is minimal code to replicate this case, on QuantLib 1.32:
```
import QuantLib as ql
import pdb
import pandas as pd
import numpy as np
import os
# 34659UAC0
daycount = ql.Thirty360(ql.Thirty360.ISMA)
schedule = ql.Schedule(
ql.Date(1,7,2014), # effectiveDate
ql.Date(1,1,2043), # terminationDate
ql.Period(ql.Semiannual), # tenor
ql.UnitedStates(ql.UnitedStates.GovernmentBond), # calendar
ql.Unadjusted, # convention
ql.Unadjusted, # terminationDateConvention
ql.DateGeneration.Forward, # rule
False, # endOfMonth
ql.Date(1,7,2019) # firstDate
)
bond = ql.FixedRateBond(
0, # settlementDays
100.0, # faceAmount,
schedule, # schedule
[0.12], # coupons
daycount, # accrualDayCounter
ql.Unadjusted # paymentConvention
)
yield_ = bond.bondYield(
100.0, # clean_price
daycount, # dayCounter
ql.Compounded, # compounding
ql.Semiannual, # frequency
ql.Date(1,7,2014) # settlementDate
)
print(f"yield is {yield_:.3f}")
import matplotlib.pyplot as plt
# plot daily clean price from start to end
prices = pd.Series(dtype=float)
t = ql.Date(1,7,2014)
while True:
cp = bond.cleanPrice(
yield_, # yield
daycount, # dayCount
ql.Compounded, # compounding
ql.Semiannual, # frequency
t # settlementDate
)
prices[t] = cp
t += 1
if t == ql.Date(1,1,2043):
break
fig, axs = plt.subplots(1, 1, figsize=(8, 6))
x_ticks = np.arange(len(prices))
TICK_FREQ = 365 * 2
axs.plot(x_ticks, prices.to_numpy(), label="clean price")
axs.legend()
axs.set_xticks(x_ticks[::TICK_FREQ])
axs.set_xticklabels(prices.index[::TICK_FREQ], rotation=45, fontsize=6)
axs.set_title(f"clean prices")
fig.tight_layout()
fig.savefig(os.path.join(r"C:\data\my_data\tax", f"34659UAC0_cleanprice.png"), dpi=200)
plt.clf()
pdb.set_trace()
```
This code outputs the yield to be 10.8%, then proceeds to plot clean price on each day from start (the interest accrual date) to end (maturity date). However, one can notice that the bond is issued at par, so the YTM from start date should just be the coupon rate, 12%. Indeed, Bloomberg YAS page gives the correct YTM of 12%. How can I set up QuantLib to give the correct YTM and clean prices (they should just be always 100)?
Bond information:
Interest accrual date 2014-07-01
Maturity date: 2043-01-01
First coupon date: 2019-07-01
coupon rate: 12%, paid semiannualy
Update: The problem is with the frequency parameter in bondYield. It forces a constant frequency, and we need to find a way to specify it to be consistent with coupon payment days.
Update2: To clarify the problem, the behavior I want is different from conventional YTM. An example DimitriVulis has raised in the comments below is that for a bond with annual coupon rate of $c$ but only pays until maturity, what do we expect the YTM to be. If we are using annual compounding, then we formula is $1 = \frac{1 + cn}{(1 + ytm)^n}$. However, I need it to be $1 = \frac{1 + cn}{1 + ytm * n}$. The motivation for this can be demonstrated by the clean price graph for my original problem. Since I am dealing with bond taxation, I need a pull-to-par as the tax basis for the bond, and this curve must be monotonically increasing / decreasing. For a method called "constant yield method", the tax basis is equal to clean price on coupon dates, and equal to a linear interpolation in between coupon dates. Therefore, I need my clean price to be monotonic, and thus my yield to be consistent with coupon payment dates.
Mathematically, the YTM I want should be implied from the following formula: $\frac{issue price}{par price} = \frac{c_1}{1 + ytm * c_1 / c} + \frac{c_2}{(1 + ytm * c_1 / c)(1 + ytm * c_2 / c)} + ... + \frac{1 + c_n}{(1 + ytm * c_1 / c)...(1 + ytm * c_n / c)}$, where $c_1...c_n$ are actual coupon payments (taking into account the time after the previous payment) per unit value, and $c$ is annual coupon rate. Note that if the coupon payments are all $c/2$, then this is equivalent to a standard semiannually-compounded YTM.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.