Skip to content
All library documents

Treasury Bond Par Pricing Depends on Accrued Interest and Day-Count Conventions

Article Quant Q&A · Author: SRqt

Summary

This QuantLib discussion investigates why a newly constructed Treasury bond does not return exactly par when priced at a coupon date using a flat yield. The example is a long-dated, semiannual fixed-rate bond with a 2% coupon and a 1% annual yield. The resulting clean price is slightly above 100, despite the expectation that a bond discounted at its coupon rate should price at par.

The author reports obtaining par after setting the global evaluation date to a coupon payment date and using an Actual/Actual convention tied to the bond’s coupon schedule, both in the bond and discount-curve setup. The example highlights that bond valuation depends on consistent schedules, settlement timing, accrued-interest treatment, and day-count conventions. The discussion provides a diagnostic outcome rather than a general pricing derivation; exact results can vary with the library configuration and instrument conventions.

Key ideas

  • A bond’s clean price can differ slightly from par when timing and day-count conventions are inconsistent.
  • The example uses a semiannual Treasury bond and a flat yield in QuantLib.
  • The reported par result follows setting the evaluation date to a coupon date and using schedule-aware Actual/Actual conventions.
  • Settlement, accrued interest, and coupon schedule details matter when comparing clean price with present value.

Tags

Full text
# QuantLib - Help buiding a simple T-Bond (Mischievous Pricing Conventions)


# QuantLib - Help buiding a simple T-Bond (Mischievous Pricing Conventions)












Im having a problem getting the right price for a simple T-Bond, maybe a Mischievous Pricing Conventions like Luigi says in his book. Im tying to price "912810SZ Govt"

```
def t_bond(iss, mat, coup):
    calendar = ql.UnitedStates()
    busconv = ql.Unadjusted
    sett = 1
    face = 100.
    freq = ql.Period(ql.Semiannual)
    schedule = ql.Schedule(iss, \
                        mat, \
                        freq, calendar, busconv, busconv, \
                        ql.DateGeneration.Backward, True)
    bond = ql.FixedRateBond(sett, face, schedule, [coup/2/100], \
                            ql.ActualActual(ql.ActualActual.Bond), ql.Unadjusted)
    return bond

bond = t_bond(ql.Date(15, 8, 2021), ql.Date(15, 8, 2051), 2.)
rate = ql.InterestRate(0.01, ql.ActualActual(), ql.SimpleThenCompounded, ql.Annual)
ql.BondFunctions.cleanPrice(bond, rate)

>>> 100.00006747141342
```

Tell me if im worg, but it should return 100.0, right?

When I inspect the cashflows it seems correct

```
coupons = [ql.as_coupon(c) for c in bond.cashflows()[:-1]]
dados = [(c.date(), c.rate(), c.accrualPeriod(), c.accruedAmount(c.date())) for c in coupons]
pd.DataFrame(dados, columns=["Date", "Rate", "Acc Period", "AccAmount"], index=range(1, len(coupons)+1))
```

What am I doing wrong? Thanks in advance.

EDIT

I got the right par value of the bond by setting the global evaluation date to a coupom payment date and by passing a Schedule instance with act/act daycount convention in the bond object and on the discount curve object

```
ql.ActualActual(ql.ActualActual.ISMA, schedule)
```

This discussion helped me to arive at the right answer for my problem: Difference arising between Dirty Price and NPV using QuantLib Python Thanks!

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.