Skip to content
All library documents

Matching Deposit Maturities and Conventions in QuantLib Zero Curves

Article Quant Q&A · Author: ql.user2511

Summary

The document explains why deposit quotes used to build a QuantLib yield curve may not match zero rates queried from that curve. In the example, the curve is built with deposit and bond helpers, then zero rates are read at curve dates using a compounded convention. The accepted answer traces the small differences to a mismatch between the curve’s reference date and the instruments’ maturity dates: the queried zero rates effectively span two extra days relative to the deposits.

The proposed adjustment constructs the curve from a settlement-day offset and calendar, then queries each deposit at its helper maturity using simple compounding. In the displayed example, the queried rates match the deposit quotes. This is a practical illustration of date and compounding conventions in curve construction, not a general prescription for every market. Correct results still depend on matching the instrument conventions, settlement rules, day-count basis, and curve interpolation to the intended market setup.

Key ideas

  • Deposit quotes and zero rates can differ when their date spans or conventions do not match.
  • A curve reference date based on settlement days can align with deposit instrument dates.
  • Query zero rates at the deposit helpers’ maturity dates when comparing them with deposit quotes.
  • Compounding conventions affect the rate reported by a zero-curve query.

Tags

Full text
# Zero Rates for Deposits using Quantlib Python


# Zero Rates for Deposits using Quantlib Python












I have used QuantLib Python to construct a zero curve from deposits and bonds.

Below are my codes:

```
import QuantLib as ql

valuationDate = ql.Date(30, 6, 2021)
ql.Settings.instance().evaluationDate = valuationDate
calendar = ql.NullCalendar()
dayConvention = ql.Actual360()
businessConvention = ql.Following
couponFrequency = ql.Semiannual

depositRates = [1.03, 1.13, 1.43]
depositMaturities = ['91D', '182D', '364D']
depositHelpers = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(r/100.0)), 
                    ql.Period(m), 
                    2,
                    calendar, 
                    businessConvention,
                    True,
                    dayConvention) for r, m in zip(depositRates, depositMaturities)]

bondPrices = [98.452, 99.955, 100.68, 94.251, 89.1395]
bondMaturities = ['3Y', '5Y', '10Y', '15Y', '20Y']
bondCoupons = [1.85, 3.10, 4.45, 4.17, 4.17]
bondHelpers = []
for r, m, z in zip(bondPrices, bondMaturities, bondCoupons):
                    terminationDate = valuationDate + ql.Period(m)
                    schedule = ql.Schedule(valuationDate, terminationDate, ql.Period(couponFrequency), calendar, businessConvention, businessConvention, ql.DateGeneration.Forward, True)
                    bondHelper = ql.FixedRateBondHelper(ql.QuoteHandle(ql.SimpleQuote(r)), 2, 100, schedule, [z/100], dayConvention, businessConvention)
                    bondHelpers.append(bondHelper)
                
rateHelpers = depositHelpers + bondHelpers

yieldCurve = ql.PiecewiseLogCubicDiscount(valuationDate, rateHelpers, dayConvention)
yieldCurve.enableExtrapolation()

dates = [date for date in yieldCurve.dates()]
zeroRates = []

for d in dates[1:]:
    years = dayConvention.yearFraction(valuationDate, d)
    zeroRate = yieldCurve.zeroRate(d, dayConvention, ql.Compounded, couponFrequency).rate()
    zeroRates.append(zeroRate * 100)
```

However, for the deposits, since these are already zero-coupon, I would expect the zero rates to be exactly equal to the par rates inserted in the `depositHelpers` list.

Unfortunately, this is not the case, as can be seen below:

```
for i in range(0, 3, 1):
    print('Par rate:', depositRates[i], '; Zero rate:', zeroRates[i])
```

The results are as follows:

```
Par rate: 1.03 ; Zero rate: 1.0305594755884773
Par rate: 1.13 ; Zero rate: 1.1285118046763465
Par rate: 1.43 ; Zero rate: 1.4224679299821297
```

Can someone please explain what I'm doing wrong? Thanks a lot.

## Answer by David Duarte (score 3, accepted)

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

I just changed the last part of your code and removed the bonds as they don't affect the first rates.

The problem is that your zero rates have 2 extra days in relation to your deposits. You can change the curve reference date to match your instruments by changing the inputs from a fixed date to a relative date based on a calendar (it will be based on the evaluationDate).

```
rateHelpers = depositHelpers #+ bondHelpers

yieldCurve = ql.PiecewiseLinearZero(2, calendar, rateHelpers, dayConvention)
yieldCurve.enableExtrapolation()

for helper in depositHelpers:
    dt = helper.maturityDate()
    zeroRate = yieldCurve.zeroRate(dt, dayConvention, ql.Simple).rate()
    print(f"{dt.ISO()}, {zeroRate:.6%}, {helper.quote().value():.6%}")
```

2021-10-01, 1.030000%, 1.030000% 2021-12-31, 1.130000%, 1.130000% 2022-07-01, 1.430000%, 1.430000%

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.