I use QuantLib Python to calibrate a curve based on interpolated discount factors (https://github.com/lballabio/QuantLib-SWIG/blob/master/SWIG/discountcurve.i). Using LogLinear interpolation on discount factors results in well-behaved forward rates:
(black line is zero rates, dotted line is 1d-tenor forward curve)
However, using MonotonicLogCubic or SplineCubic, my forward rates are not well behaved - in the end-point, the forwards are 0:
Now I understand that using these interpolation methods, second derivatives in end points are set to zero, however this shouldn't necessarily mean that forwards are zero in the end points. What gives? How to overcome this issue?
These are my input DFs:
February 27th, 2020: 1.0000102501050636
February 28th, 2020: 1.0000205003151919
March 10th, 2020: 1.000135036504439
March 17th, 2020: 1.0002140481753308
April 1st, 2020: 1.0003903064472135
April 30th, 2020: 1.0007383708059454
June 1st, 2020: 1.0011864659905814
July 1st, 2020: 1.001606452340883
July 30th, 2020: 1.0020206702099752
September 1st, 2020: 1.0025224673306345
September 30th, 2020: 1.003007005031276
October 30th, 2020: 1.0034783631568704
December 2nd, 2020: 1.0040034616057292
December 30th, 2020: 1.0045093968882473
February 1st, 2021: 1.0050604130179728
March 3rd, 2021: 1.0055474482943993
September 1st, 2021: 1.0087481016987652
March 2nd, 2022: 1.01191304422858
August 31st, 2022: 1.0148211625629888
March 2nd, 2023: 1.0174479377825414
March 1st, 2024: 1.0215623647797287
March 4th, 2025: 1.023909696966405
March 4th, 2026: 1.0242610376714252
March 3rd, 2027: 1.02262864674708
March 1st, 2028: 1.0191710493588495
March 2nd, 2029: 1.013740853380904
March 4th, 2030: 1.0061949692591952
March 4th, 2031: 0.998108130543049
March 3rd, 2032: 0.9884922702699311
March 2nd, 2035: 0.961448481843742
March 1st, 2040: 0.9138611360550781
March 2nd, 2045: 0.8771539172898629
March 2nd, 2050: 0.8489994312646763
And I construct the instance as such:
ql.NaturalCubicDiscountCurve(dates, discountfactors, ql.Actual365Fixed(),ql.UnitedStates())
where dates and discountfactors are lists based on the above.
To get the forwards, I call forwardRate(date, date+1, ql.Actual360(), ql.Simple()).rate() on the discount curve