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)), 
                    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)
rateHelpers = depositHelpers + bondHelpers

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

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.

  • $\begingroup$ I am a bit rusty with Quantlib but as far as I remember the zero rates are calculated from valuation date to maturity date. Your quotations start from spot date i.e. 2021-07-02. Therefore when you call zeroRate function it calculates zero rates from 2021-06-30 -> maturity, not the rates from 2021-07-02 -> maturity. If you want all calculations to be performed from spot date, change the following: Change fixing days to 0 (i.e. second parameter in depositHelpers) and in yieldCurve.zeroRate change ql.Compounded to ql.Simple, then you should get the same rates as the one provided. $\endgroup$
    – emot
    Commented Aug 9, 2021 at 9:33
  • $\begingroup$ @emot Yes, the issue arises due to the 2 fixing days that I have added, thanks a lot for your help. $\endgroup$ Commented Aug 9, 2021 at 10:29

1 Answer 1


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)

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%

  • $\begingroup$ Thank you a lot for your help David, that's exactly what I needed! $\endgroup$ Commented Aug 9, 2021 at 11:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.