# Quantlib ZeroCurve interpolation

I'd like to check how QuantLib does interpolation on rates if I use ZeroCurve constructor. As it was mentioned here, by using curve.nodes() you can get a list of rates, used for interpolation.

So, if I build a curve with spot rates with the following code

import QuantLib as ql
todays_date = ql.Date(12, 3, 2020)
spot_dates = [todays_date + ql.Period(i, ql.Years) for i in [0, 1, 2, 3, 4, 5]]
spot_rates = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06]
spot_curve = ql.ZeroCurve(
spot_dates, spot_rates,
ql.SimpleDayCounter(),
ql.NullCalendar(),
ql.Linear(),
ql.Compounded,
ql.Annual
)


I got back

spot_curve.nodes()

((Date(12,3,2020), 0.009950330853148023),
(Date(12,3,2021), 0.01980262729617973),
(Date(12,3,2022), 0.02955880224154438),
(Date(12,3,2023), 0.03922071315328132),
(Date(12,3,2024), 0.04879016416943205),
(Date(12,3,2025), 0.05826890812397582))


I've realized that the issue is the compounding. By indicating that input rates are Continuously compounded, nodes() matches with the input.

spot_curve = ql.ZeroCurve(
spot_dates, spot_rates,
ql.SimpleDayCounter(),
ql.NullCalendar(),
ql.Linear(), ql.Continuous, ql.Annual
)
spot_curve.nodes()

((Date(12,3,2020), 0.01),
(Date(12,3,2021), 0.02),
(Date(12,3,2022), 0.03),
(Date(12,3,2023), 0.04),
(Date(12,3,2024), 0.05),
(Date(12,3,2025), 0.06))


Based on that discovery, the question is: Does QuantLib always interpolates in continues rates (with zero rates constructor)? Is this a convention?

The data stored in the object is adjusted such that compounding is Continuous and frequency is NoFrequency. The C++ source code is available here: zerocurve.hpp. I think that the reason for this is that a ZeroCurve object then won't have to store compounding and frequency.

We can validate the new rates by using the equation $$e^{r_{cont}t}=(1+r_{comp})^t$$

The calculations below gives zero, which verifies the QuantLib transform of the rates from Compounded to Continuous:

import math
math.exp(0.009950330853148023*1.0)-pow(1.0+0.01,1.0)
math.exp(0.01980262729617973*2.0)-pow(1.0+0.02,2.0)


To obtain the zero rates with the needed compounding and frequency you can use something like

for x in spot_dates:
print(spot_curve.zeroRate(x,
ql.SimpleDayCounter(),
ql.Compounded,
ql.Annual).rate())


I got the same problem. Also, when I call for the ZeroRate method on the reference date of the curve I get a different rate from the one that I created the curve object with it.

For example:

ql.Settings.instance().evaluationDate = ql.Date(8, 12, 2021)

rates = [0.015677430225945563, 0.015677430225945563, 0.011840632376029895]
date = [Date(8,12,2021), Date(3,1,2022), Date(1,2,2022)]
curve = ql.ZeroCurve(dates, rates, ql.Actual360(), ql.NullCalendar(), ql.Linear(), ql.Simple, ql.Annual)

curve.zeroRate(ql.Date(8, 12, 2021), ql.Actual360(), ql.Simple).rate()


I expected the rate 0.015677430225945563, but I got 0.015677094022947813

For the other dates I get the right rate.

But also I have the same problem as the topic creator above. When I call for the curve nodes I get different rates for all dates:

curve.nodes()

((Date(8,12,2021), 0.015677093548145716),
(Date(3,1,2022), 0.01566856146524625),
(Date(1,2,2022), 0.011829935508255464))


Does anyone have a answer as why this is? Thanks.