diff --git a/ql/cashflows/iborcoupon.cpp b/ql/cashflows/iborcoupon.cpp index c07100752c7..3e414d263fb 100644 --- a/ql/cashflows/iborcoupon.cpp +++ b/ql/cashflows/iborcoupon.cpp @@ -88,8 +88,24 @@ namespace QuantLib { return fixingDate_; } - Rate IborCoupon::indexFixing() const { + bool IborCoupon::hasFixed() const { + Date today = QuantLib::Settings::instance().evaluationDate(); + + if (fixingDate_ > today) { + return false; + } else if (fixingDate_ < today) { + return true; + } else { + // fixingDate_ == today + if (QuantLib::Settings::instance().enforcesTodaysHistoricFixings()) { + return true; + } else { + return index_->hasHistoricalFixing(fixingDate_); + } + } + } + Rate IborCoupon::indexFixing() const { initializeCachedData(); /* instead of just returning index_->fixing(fixingValueDate_) @@ -98,34 +114,15 @@ namespace QuantLib { 1) allows to save date/time recalculations, and 2) takes into account par coupon needs */ - Date today = QuantLib::Settings::instance().evaluationDate(); - - if (fixingDate_>today) - return iborIndex_->forecastFixing(fixingValueDate_, - fixingEndDate_, - spanningTime_); - if (fixingDate_pastFixing(fixingDate_); QL_REQUIRE(result != Null(), "Missing " << index_->name() << " fixing for " << fixingDate_); return result; + } else { + return iborIndex_->forecastFixing(fixingValueDate_, fixingEndDate_, spanningTime_); } - - try { - Rate result = index_->pastFixing(fixingDate_); - if (result!=Null()) - return result; - else - ; // fall through and forecast - } catch (Error&) { - ; // fall through and forecast - } - return iborIndex_->forecastFixing(fixingValueDate_, - fixingEndDate_, - spanningTime_); } void IborCoupon::setPricer(const ext::shared_ptr& pricer) { diff --git a/ql/cashflows/iborcoupon.hpp b/ql/cashflows/iborcoupon.hpp index d4f645b6937..cbc32c10af3 100644 --- a/ql/cashflows/iborcoupon.hpp +++ b/ql/cashflows/iborcoupon.hpp @@ -56,6 +56,7 @@ namespace QuantLib { //! \name Inspectors //@{ const ext::shared_ptr& iborIndex() const { return iborIndex_; } + bool hasFixed() const; //@} //! \name FloatingRateCoupon interface //@{ diff --git a/test-suite/cashflows.cpp b/test-suite/cashflows.cpp index dd9d736992d..c66a7d5d715 100644 --- a/test-suite/cashflows.cpp +++ b/test-suite/cashflows.cpp @@ -563,6 +563,61 @@ BOOST_AUTO_TEST_CASE(testFixedIborCouponWithoutForecastCurve) { } } +IborCoupon iborCouponForFixingDate(const ext::shared_ptr& index, Date fixingDate) { + Date startDate = index->valueDate(fixingDate); + Date endDate = index->maturityDate(fixingDate); + + IborCoupon coupon(endDate, 100.0, startDate, endDate, index->fixingDays(), index); + coupon.setPricer(ext::make_shared()); + + return coupon; +} + +BOOST_AUTO_TEST_CASE(testIborCouponKnowsWhenitHasFixed) { + BOOST_TEST_MESSAGE("Testing that ibor coupon knows when it has fixed..."); + + Date today = Settings::instance().evaluationDate(); + + auto index = ext::make_shared(); + auto calendar = index->fixingCalendar(); + + { + IborCoupon coupon = iborCouponForFixingDate(index, calendar.advance(today, -1, Days)); + index->clearFixings(); + // this should not throw an exception if the fixing is missing + BOOST_CHECK_EQUAL(coupon.hasFixed(), true); + // but this should + BOOST_CHECK_THROW(coupon.rate(), Error); + } + + { + IborCoupon coupon = iborCouponForFixingDate(index, today); + QuantLib::Settings::instance().enforcesTodaysHistoricFixings() = false; + index->clearFixings(); + BOOST_CHECK_EQUAL(coupon.hasFixed(), false); + } + + { + IborCoupon coupon = iborCouponForFixingDate(index, today); + QuantLib::Settings::instance().enforcesTodaysHistoricFixings() = false; + index->addFixing(coupon.fixingDate(), 0.01); + BOOST_CHECK_EQUAL(coupon.hasFixed(), true); + } + + { + IborCoupon coupon = iborCouponForFixingDate(index, today); + QuantLib::Settings::instance().enforcesTodaysHistoricFixings() = true; + index->clearFixings(); + BOOST_CHECK_EQUAL(coupon.hasFixed(), true); + BOOST_CHECK_THROW(coupon.rate(), Error); + } + + { + IborCoupon coupon = iborCouponForFixingDate(index, calendar.advance(today, 1, Days)); + BOOST_CHECK_EQUAL(coupon.hasFixed(), false); + } +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()