From 6dc78b2a7d4287b068f431a702c320eeacb484be Mon Sep 17 00:00:00 2001 From: Luigi Ballabio Date: Thu, 28 Sep 2023 14:24:52 +0200 Subject: [PATCH] Detect null time-to-reference --- ql/termstructures/yieldtermstructure.cpp | 5 ++-- test-suite/termstructures.cpp | 30 +++++++++++++++++++----- test-suite/termstructures.hpp | 1 + 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/ql/termstructures/yieldtermstructure.cpp b/ql/termstructures/yieldtermstructure.cpp index 45bd101f288..6220fd4506e 100644 --- a/ql/termstructures/yieldtermstructure.cpp +++ b/ql/termstructures/yieldtermstructure.cpp @@ -100,7 +100,8 @@ namespace QuantLib { Compounding comp, Frequency freq, bool extrapolate) const { - if (d==referenceDate()) { + Time t = timeFromReference(d); + if (t == 0) { Real compound = 1.0/discount(dt, extrapolate); // t has been calculated with a possibly different daycounter // but the difference should not matter for very small times @@ -108,7 +109,7 @@ namespace QuantLib { dayCounter, comp, freq, dt); } - Real compound = 1.0/discount(d, extrapolate); + Real compound = 1.0/discount(t, extrapolate); return InterestRate::impliedRate(compound, dayCounter, comp, freq, referenceDate(), d); diff --git a/test-suite/termstructures.cpp b/test-suite/termstructures.cpp index f654e35858a..c383f7e39e1 100644 --- a/test-suite/termstructures.cpp +++ b/test-suite/termstructures.cpp @@ -416,6 +416,26 @@ void TermStructureTest::testCompositeZeroYieldStructures() { } } + +void TermStructureTest::testNullTimeToReference() { + BOOST_TEST_MESSAGE("Testing zero-rate calculation for null time-to-reference..."); + + Rate rate = 0.02; + auto dayCount = Thirty360(Thirty360::BondBasis); + auto curve = FlatForward(Date(30, August, 2023), rate, dayCount); + + // the time between August 30th and 31st is null for the 30/360 day count convention + Rate expected = rate; + Rate calculated = curve.zeroRate(Date(31, August, 2023), dayCount, Continuous); + Real tolerance = 1.0e-10; + + if (std::fabs(calculated - expected) > tolerance) + BOOST_ERROR("unable to reproduce zero yield rate from curve\n" + << std::fixed << std::setprecision(10) + << " calculated: " << calculated << "\n" + << " expected: " << expected); +} + test_suite* TermStructureTest::suite() { auto* suite = BOOST_TEST_SUITE("Term structure tests"); suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testReferenceChange)); @@ -425,12 +445,10 @@ test_suite* TermStructureTest::suite() { suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testFSpreadedObs)); suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testZSpreaded)); suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testZSpreadedObs)); - suite->add(QUANTLIB_TEST_CASE( - &TermStructureTest::testCreateWithNullUnderlying)); - suite->add(QUANTLIB_TEST_CASE( - &TermStructureTest::testLinkToNullUnderlying)); - suite->add(QUANTLIB_TEST_CASE( - &TermStructureTest::testCompositeZeroYieldStructures)); + suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testCreateWithNullUnderlying)); + suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testLinkToNullUnderlying)); + suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testCompositeZeroYieldStructures)); + suite->add(QUANTLIB_TEST_CASE(&TermStructureTest::testNullTimeToReference)); return suite; } diff --git a/test-suite/termstructures.hpp b/test-suite/termstructures.hpp index 5933153a02c..fc4faf89f96 100644 --- a/test-suite/termstructures.hpp +++ b/test-suite/termstructures.hpp @@ -37,6 +37,7 @@ class TermStructureTest { static void testCreateWithNullUnderlying(); static void testLinkToNullUnderlying(); static void testCompositeZeroYieldStructures(); + static void testNullTimeToReference(); static boost::unit_test_framework::test_suite* suite(); };