From 571caf411eaaf3d8352c89463a55dd22fdaadf45 Mon Sep 17 00:00:00 2001 From: Eugene Toder Date: Tue, 22 Oct 2024 19:18:14 -0400 Subject: [PATCH] Merge DatedOISRateHelper with OISRateHelper Add a second constructor overload to OISRateHelper which works like DatedOISRateHelper. Deprecate DatedOISRateHelper. This removes a lot of code duplication and also adds support for custom pillars to DatedOISRateHelper. --- ql/instruments/makeois.cpp | 3 +- ql/termstructures/bootstraphelper.hpp | 26 +++-- ql/termstructures/yield/oisratehelper.cpp | 136 ++++++++-------------- ql/termstructures/yield/oisratehelper.hpp | 115 +++++++++--------- 4 files changed, 129 insertions(+), 151 deletions(-) diff --git a/ql/instruments/makeois.cpp b/ql/instruments/makeois.cpp index 13701526c55..17efeb7f1ab 100644 --- a/ql/instruments/makeois.cpp +++ b/ql/instruments/makeois.cpp @@ -192,7 +192,8 @@ namespace QuantLib { MakeOIS& MakeOIS::withTerminationDate(const Date& terminationDate) { terminationDate_ = terminationDate; - swapTenor_ = Period(); + if (terminationDate != Date()) + swapTenor_ = Period(); return *this; } diff --git a/ql/termstructures/bootstraphelper.hpp b/ql/termstructures/bootstraphelper.hpp index 66b071b42ce..0d3c62315f6 100644 --- a/ql/termstructures/bootstraphelper.hpp +++ b/ql/termstructures/bootstraphelper.hpp @@ -128,12 +128,15 @@ namespace QuantLib { template class RelativeDateBootstrapHelper : public BootstrapHelper { public: - explicit RelativeDateBootstrapHelper(const Handle& quote); - explicit RelativeDateBootstrapHelper(Real quote); + explicit RelativeDateBootstrapHelper(const Handle& quote, + bool updateDates = true); + explicit RelativeDateBootstrapHelper(Real quote, + bool updateDates = true); //! \name Observer interface //@{ void update() override { - if (evaluationDate_ != Settings::instance().evaluationDate()) { + if (evaluationDate_ != Date() && + evaluationDate_ != Settings::instance().evaluationDate()) { evaluationDate_ = Settings::instance().evaluationDate(); initializeDates(); } @@ -212,17 +215,22 @@ namespace QuantLib { template RelativeDateBootstrapHelper::RelativeDateBootstrapHelper( - const Handle& quote) + const Handle& quote, bool updateDates) : BootstrapHelper(quote) { - this->registerWith(Settings::instance().evaluationDate()); - evaluationDate_ = Settings::instance().evaluationDate(); + if (updateDates) { + this->registerWith(Settings::instance().evaluationDate()); + evaluationDate_ = Settings::instance().evaluationDate(); + } } template - RelativeDateBootstrapHelper::RelativeDateBootstrapHelper(Real quote) + RelativeDateBootstrapHelper::RelativeDateBootstrapHelper( + Real quote, bool updateDates) : BootstrapHelper(quote) { - this->registerWith(Settings::instance().evaluationDate()); - evaluationDate_ = Settings::instance().evaluationDate(); + if (updateDates) { + this->registerWith(Settings::instance().evaluationDate()); + evaluationDate_ = Settings::instance().evaluationDate(); + } } inline std::ostream& operator<<(std::ostream& out, diff --git a/ql/termstructures/yield/oisratehelper.cpp b/ql/termstructures/yield/oisratehelper.cpp index ce211d3eed4..a3877088c01 100644 --- a/ql/termstructures/yield/oisratehelper.cpp +++ b/ql/termstructures/yield/oisratehelper.cpp @@ -50,16 +50,53 @@ namespace QuantLib { Natural lockoutDays, bool applyObservationShift, ext::shared_ptr pricer) - : RelativeDateRateHelper(fixedRate), pillarChoice_(pillar), settlementDays_(settlementDays), tenor_(tenor), + : RelativeDateRateHelper(fixedRate), settlementDays_(settlementDays), tenor_(tenor), discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates), paymentLag_(paymentLag), paymentConvention_(paymentConvention), paymentFrequency_(paymentFrequency), paymentCalendar_(std::move(paymentCalendar)), - forwardStart_(forwardStart), overnightSpread_(overnightSpread), + forwardStart_(forwardStart), overnightSpread_(overnightSpread), pillarChoice_(pillar), averagingMethod_(averagingMethod), endOfMonth_(endOfMonth), fixedPaymentFrequency_(fixedPaymentFrequency), fixedCalendar_(std::move(fixedCalendar)), lookbackDays_(lookbackDays), lockoutDays_(lockoutDays), applyObservationShift_(applyObservationShift), pricer_(std::move(pricer)) { + initialize(overnightIndex, customPillarDate); + } + OISRateHelper::OISRateHelper(const Date& startDate, + const Date& endDate, + const Handle& fixedRate, + const ext::shared_ptr& overnightIndex, + Handle discount, + bool telescopicValueDates, + Integer paymentLag, + BusinessDayConvention paymentConvention, + Frequency paymentFrequency, + Calendar paymentCalendar, + const Spread overnightSpread, + Pillar::Choice pillar, + Date customPillarDate, + RateAveraging::Type averagingMethod, + ext::optional endOfMonth, + ext::optional fixedPaymentFrequency, + Calendar fixedCalendar, + Natural lookbackDays, + Natural lockoutDays, + bool applyObservationShift, + ext::shared_ptr pricer) + : RelativeDateRateHelper(fixedRate, false), startDate_(startDate), endDate_(endDate), + discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates), + paymentLag_(paymentLag), paymentConvention_(paymentConvention), + paymentFrequency_(paymentFrequency), paymentCalendar_(std::move(paymentCalendar)), + overnightSpread_(overnightSpread), pillarChoice_(pillar), + averagingMethod_(averagingMethod), endOfMonth_(endOfMonth), + fixedPaymentFrequency_(fixedPaymentFrequency), fixedCalendar_(std::move(fixedCalendar)), + lookbackDays_(lookbackDays), lockoutDays_(lockoutDays), applyObservationShift_(applyObservationShift), + pricer_(std::move(pricer)) { + initialize(overnightIndex, customPillarDate); + } + + void OISRateHelper::initialize(const ext::shared_ptr& overnightIndex, + Date customPillarDate) { overnightIndex_ = ext::dynamic_pointer_cast(overnightIndex->clone(termStructureHandle_)); // We want to be notified of changes of fixings, but we don't @@ -75,12 +112,13 @@ namespace QuantLib { } void OISRateHelper::initializeDates() { - // input discount curve Handle might be empty now but it could // be assigned a curve later; use a RelinkableHandle here - MakeOIS tmp = MakeOIS(tenor_, overnightIndex_, 0.0, forwardStart_) + auto tmp = MakeOIS(tenor_, overnightIndex_, 0.0, forwardStart_) .withDiscountingTermStructure(discountRelinkableHandle_) - .withSettlementDays(settlementDays_) + .withSettlementDays(settlementDays_) // resets effectiveDate + .withEffectiveDate(startDate_) + .withTerminationDate(endDate_) .withTelescopicValueDates(telescopicValueDates_) .withPaymentLag(paymentLag_) .withPaymentAdjustment(paymentConvention_) @@ -186,56 +224,13 @@ namespace QuantLib { Natural lookbackDays, Natural lockoutDays, bool applyObservationShift, - const ext::shared_ptr& pricer) - : RateHelper(fixedRate), discountHandle_(std::move(discount)), - telescopicValueDates_(telescopicValueDates), averagingMethod_(averagingMethod) { - - auto clonedOvernightIndex = - ext::dynamic_pointer_cast(overnightIndex->clone(termStructureHandle_)); - // We want to be notified of changes of fixings, but we don't - // want notifications from termStructureHandle_ (they would - // interfere with bootstrapping.) - clonedOvernightIndex->unregisterWith(termStructureHandle_); - - registerWith(clonedOvernightIndex); - registerWith(discountHandle_); - - // input discount curve Handle might be empty now but it could - // be assigned a curve later; use a RelinkableHandle here - auto tmp = MakeOIS(Period(), clonedOvernightIndex, 0.0) - .withDiscountingTermStructure(discountRelinkableHandle_) - .withEffectiveDate(startDate) - .withTerminationDate(endDate) - .withTelescopicValueDates(telescopicValueDates_) - .withPaymentLag(paymentLag) - .withPaymentAdjustment(paymentConvention) - .withPaymentFrequency(paymentFrequency) - .withPaymentCalendar(paymentCalendar) - .withOvernightLegSpread(overnightSpread) - .withAveragingMethod(averagingMethod_) - .withLookbackDays(lookbackDays) - .withLockoutDays(lockoutDays) - .withObservationShift(applyObservationShift); - if (endOfMonth) { - tmp.withEndOfMonth(*endOfMonth); - } - if (fixedPaymentFrequency) { - tmp.withFixedLegPaymentFrequency(*fixedPaymentFrequency); - } - if (!fixedCalendar.empty()) { - tmp.withFixedLegCalendar(fixedCalendar); - } - swap_ = tmp; - - if (pricer) - setCouponPricer(swap_->overnightLeg(), pricer); - - earliestDate_ = swap_->startDate(); - maturityDate_ = swap_->maturityDate(); - Date lastPaymentDate = std::max(swap_->overnightLeg().back()->date(), - swap_->fixedLeg().back()->date()); - latestRelevantDate_ = latestDate_ = std::max(maturityDate_, lastPaymentDate); - } + const ext::shared_ptr& pricer, + Pillar::Choice pillar, + Date customPillarDate) + : OISRateHelper(startDate, endDate, fixedRate, overnightIndex, std::move(discount), telescopicValueDates, + paymentLag, paymentConvention, paymentFrequency, paymentCalendar, overnightSpread, + pillar, customPillarDate, averagingMethod, endOfMonth, fixedPaymentFrequency, + fixedCalendar, lookbackDays, lockoutDays, applyObservationShift, pricer) {} DatedOISRateHelper::DatedOISRateHelper(const Date& startDate, const Date& endDate, @@ -257,35 +252,4 @@ namespace QuantLib { averagingMethod, paymentLag, paymentConvention, paymentFrequency, paymentCalendar, overnightSpread, endOfMonth, fixedPaymentFrequency, fixedCalendar) {} - void DatedOISRateHelper::setTermStructure(YieldTermStructure* t) { - // do not set the relinkable handle as an observer - - // force recalculation when needed - bool observer = false; - - ext::shared_ptr temp(t, null_deleter()); - termStructureHandle_.linkTo(temp, observer); - - if (discountHandle_.empty()) - discountRelinkableHandle_.linkTo(temp, observer); - else - discountRelinkableHandle_.linkTo(*discountHandle_, observer); - - RateHelper::setTermStructure(t); - } - - Real DatedOISRateHelper::impliedQuote() const { - QL_REQUIRE(termStructure_ != nullptr, "term structure not set"); - // we didn't register as observers - force calculation - swap_->deepUpdate(); - return swap_->fairRate(); - } - - void DatedOISRateHelper::accept(AcyclicVisitor& v) { - auto* v1 = dynamic_cast*>(&v); - if (v1 != nullptr) - v1->visit(*this); - else - RateHelper::accept(v); - } - } diff --git a/ql/termstructures/yield/oisratehelper.hpp b/ql/termstructures/yield/oisratehelper.hpp index 9135c479ee9..426b676f3c8 100644 --- a/ql/termstructures/yield/oisratehelper.hpp +++ b/ql/termstructures/yield/oisratehelper.hpp @@ -59,6 +59,28 @@ namespace QuantLib { Natural lockoutDays = 0, bool applyObservationShift = false, ext::shared_ptr pricer = {}); + OISRateHelper(const Date& startDate, + const Date& endDate, + const Handle& fixedRate, + const ext::shared_ptr& overnightIndex, + // exogenous discounting curve + Handle discountingCurve = {}, + bool telescopicValueDates = false, + Integer paymentLag = 0, + BusinessDayConvention paymentConvention = Following, + Frequency paymentFrequency = Annual, + Calendar paymentCalendar = Calendar(), + Spread overnightSpread = 0.0, + Pillar::Choice pillar = Pillar::LastRelevantDate, + Date customPillarDate = Date(), + RateAveraging::Type averagingMethod = RateAveraging::Compound, + ext::optional endOfMonth = ext::nullopt, + ext::optional fixedPaymentFrequency = ext::nullopt, + Calendar fixedCalendar = Calendar(), + Natural lookbackDays = Null(), + Natural lockoutDays = 0, + bool applyObservationShift = false, + ext::shared_ptr pricer = {}); //! \name RateHelper interface //@{ Real impliedQuote() const override; @@ -74,38 +96,43 @@ namespace QuantLib { void accept(AcyclicVisitor&) override; //@} protected: - void initializeDates() override; - Pillar::Choice pillarChoice_; - - Natural settlementDays_; - Period tenor_; - ext::shared_ptr overnightIndex_; - - ext::shared_ptr swap_; - RelinkableHandle termStructureHandle_; - - Handle discountHandle_; - bool telescopicValueDates_; - RelinkableHandle discountRelinkableHandle_; - - Integer paymentLag_; - BusinessDayConvention paymentConvention_; - Frequency paymentFrequency_; - Calendar paymentCalendar_; - Period forwardStart_; - Spread overnightSpread_; - RateAveraging::Type averagingMethod_; - ext::optional endOfMonth_; - ext::optional fixedPaymentFrequency_; - Calendar fixedCalendar_; - Natural lookbackDays_; - Natural lockoutDays_; - bool applyObservationShift_; - ext::shared_ptr pricer_; + void initialize(const ext::shared_ptr& overnightIndex, + Date customPillarDate); + void initializeDates() override; + + Natural settlementDays_; + Period tenor_; + Date startDate_, endDate_; + ext::shared_ptr overnightIndex_; + + ext::shared_ptr swap_; + RelinkableHandle termStructureHandle_; + + Handle discountHandle_; + bool telescopicValueDates_; + RelinkableHandle discountRelinkableHandle_; + + Integer paymentLag_; + BusinessDayConvention paymentConvention_; + Frequency paymentFrequency_; + Calendar paymentCalendar_; + Period forwardStart_; + Spread overnightSpread_; + Pillar::Choice pillarChoice_; + RateAveraging::Type averagingMethod_; + ext::optional endOfMonth_; + ext::optional fixedPaymentFrequency_; + Calendar fixedCalendar_; + Natural lookbackDays_; + Natural lockoutDays_; + bool applyObservationShift_; + ext::shared_ptr pricer_; }; - //! Rate helper for bootstrapping over Overnight Indexed Swap rates - class DatedOISRateHelper : public RateHelper { + /*! \deprecated Use OISRateHelper instead. + Deprecated in version 1.37. + */ + class QL_DEPRECATED DatedOISRateHelper : public OISRateHelper { public: DatedOISRateHelper(const Date& startDate, const Date& endDate, @@ -126,7 +153,9 @@ namespace QuantLib { Natural lookbackDays = Null(), Natural lockoutDays = 0, bool applyObservationShift = false, - const ext::shared_ptr& pricer = {}); + const ext::shared_ptr& pricer = {}, + Pillar::Choice pillar = Pillar::LastRelevantDate, + Date customPillarDate = Date()); /*! \deprecated Use the overload without forward start. Deprecated in version 1.35. @@ -149,30 +178,6 @@ namespace QuantLib { ext::optional endOfMonth = ext::nullopt, ext::optional fixedPaymentFrequency = ext::nullopt, const Calendar& fixedCalendar = Calendar()); - - //! \name RateHelper interface - //@{ - Real impliedQuote() const override; - void setTermStructure(YieldTermStructure*) override; - //@} - //! \name inspectors - //@{ - // NOLINTNEXTLINE(cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - ext::shared_ptr swap() const { return swap_; } - //@} - //@} - //! \name Visitability - //@{ - void accept(AcyclicVisitor&) override; - //@} - protected: - ext::shared_ptr swap_; - RelinkableHandle termStructureHandle_; - - Handle discountHandle_; - bool telescopicValueDates_; - RelinkableHandle discountRelinkableHandle_; - RateAveraging::Type averagingMethod_; }; }