Skip to content
All library documents

Why a Treasury Bond Quote Differs from a Curve Zero Rate

Article Quant Q&A · Author: user2728814

Summary

The document presents a QuantLib example that builds a US Treasury yield curve from four quoted yields using fixed-rate bond helpers, then compares the ten-year input quote with the curve’s ten-year zero rate. The displayed figures differ, prompting a question about why the rates do not match.

The example highlights that a bond yield quote and a zero rate are different rate measures: the curve is inferred from coupon-bearing bonds, while the zero rate describes discounting to a maturity under specified day-count and compounding conventions. The document does not include an answer or establish which convention or construction detail explains the particular discrepancy, so the figures should be read as a question rather than a general QuantLib rule.

Key ideas

  • The example bootstraps a Treasury curve from quoted yields using fixed-rate bond helpers.
  • It compares a ten-year bond quote with the zero rate extracted at the corresponding maturity.
  • Bond yields and zero rates can differ because they describe different cash-flow and rate conventions.
  • The document poses the discrepancy but does not provide a diagnosis or resolution.

Tags

Full text
# Matching the yield on a bond with the zeroRate on a curve in Quantlib


# Matching the yield on a bond with the zeroRate on a curve in Quantlib












I am using QuantLib to generate a US Treasury curve from 1y, 3y, 5y, and 10y yield quotes. However, after building the curve and running `zeroRate` on it, it returns a number that is about 0.012% different to the actual quote (1.972% vs 1.96% quote). What is the difference between these two numbers? Shouldn't they be almost identical?

Thanks in advance!

```
import QuantLib as ql

maturities = [ql.Period('1Y'), ql.Period('3Y'), ql.Period('5Y'), ql.Period('10Y')]
yields = [0.0191, 0.0171, 0.0174, 0.0196]

coupon_frequency = ql.UnitedStates.GovernmentBond
settlement_days = 0
face_amount = 100.0
day_count = ql.ActualActual(ql.ActualActual.Bond)
calendar = ql.UnitedStates()
convention = ql.Unadjusted
generation = ql.DateGeneration.Backward
end_of_month = False

calc_date = ql.Date(5,7,2019)
ql.Settings.instance().evaluationDate = calc_date

bond_helpers = []
for r, m in zip(yields, maturities):
    termination_date = calendar.advance(calc_date, m, convention)
    schedule = ql.Schedule(calc_date,
                           termination_date, 
                           ql.Period(coupon_frequency), 
                           calendar,
                           convention, 
                           convention, 
                           generation,
                           end_of_month,
                          )

    bond_helper = ql.FixedRateBondHelper(ql.QuoteHandle(ql.SimpleQuote(face_amount)),
                                         settlement_days,
                                         face_amount,
                                         schedule,
                                         [r],
                                         day_count,
                                         convention,
                                        )
    bond_helpers.append(bond_helper)

curve = ql.PiecewiseLogCubicDiscount(calc_date, bond_helpers, day_count)

test_maturity = calendar.advance(calc_date, ql.Period('10Y'), convention)

test_maturity, 0.0196, curve.zeroRate(test_maturity, day_count, ql.Compounded, coupon_frequency).rate()
```

```
(Date(5,7,2029), 0.0196, 0.019727996796473413)
```

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.