1
$\begingroup$

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?

$\endgroup$

2 Answers 2

2
$\begingroup$

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())
$\endgroup$
0
$\begingroup$

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.

$\endgroup$

Your Answer

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

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