Skip to content

Commit

Permalink
Merge DatedOISRateHelper with OISRateHelper
Browse files Browse the repository at this point in the history
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
pillar dates to DatedOISRateHelper's equivalent.
  • Loading branch information
eltoder committed Oct 24, 2024
1 parent 5ee8f89 commit 912c944
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ int main(int, char* []) {
auto startDate = q.first.first;
auto endDate = q.first.second;
auto quote = q.second;
auto helper = ext::make_shared<DatedOISRateHelper>(
auto helper = ext::make_shared<OISRateHelper>(
startDate, endDate, Handle<Quote>(quote), eonia);
eoniaInstruments.push_back(helper);
}
Expand Down
3 changes: 2 additions & 1 deletion ql/instruments/makeois.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ namespace QuantLib {

MakeOIS& MakeOIS::withTerminationDate(const Date& terminationDate) {
terminationDate_ = terminationDate;
swapTenor_ = Period();
if (terminationDate != Date())
swapTenor_ = Period();
return *this;
}

Expand Down
26 changes: 17 additions & 9 deletions ql/termstructures/bootstraphelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,15 @@ namespace QuantLib {
template <class TS>
class RelativeDateBootstrapHelper : public BootstrapHelper<TS> {
public:
explicit RelativeDateBootstrapHelper(const Handle<Quote>& quote);
explicit RelativeDateBootstrapHelper(Real quote);
explicit RelativeDateBootstrapHelper(const Handle<Quote>& 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();
}
Expand Down Expand Up @@ -212,17 +215,22 @@ namespace QuantLib {

template <class TS>
RelativeDateBootstrapHelper<TS>::RelativeDateBootstrapHelper(
const Handle<Quote>& quote)
const Handle<Quote>& quote, bool updateDates)
: BootstrapHelper<TS>(quote) {
this->registerWith(Settings::instance().evaluationDate());
evaluationDate_ = Settings::instance().evaluationDate();
if (updateDates) {
this->registerWith(Settings::instance().evaluationDate());
evaluationDate_ = Settings::instance().evaluationDate();
}
}

template <class TS>
RelativeDateBootstrapHelper<TS>::RelativeDateBootstrapHelper(Real quote)
RelativeDateBootstrapHelper<TS>::RelativeDateBootstrapHelper(
Real quote, bool updateDates)
: BootstrapHelper<TS>(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,
Expand Down
132 changes: 47 additions & 85 deletions ql/termstructures/yield/oisratehelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,53 @@ namespace QuantLib {
Natural lockoutDays,
bool applyObservationShift,
ext::shared_ptr<FloatingRateCouponPricer> 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<Quote>& fixedRate,
const ext::shared_ptr<OvernightIndex>& overnightIndex,
Handle<YieldTermStructure> discount,
bool telescopicValueDates,
Integer paymentLag,
BusinessDayConvention paymentConvention,
Frequency paymentFrequency,
Calendar paymentCalendar,
const Spread overnightSpread,
Pillar::Choice pillar,
Date customPillarDate,
RateAveraging::Type averagingMethod,
ext::optional<bool> endOfMonth,
ext::optional<Frequency> fixedPaymentFrequency,
Calendar fixedCalendar,
Natural lookbackDays,
Natural lockoutDays,
bool applyObservationShift,
ext::shared_ptr<FloatingRateCouponPricer> 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>& overnightIndex,
Date customPillarDate) {
overnightIndex_ =
ext::dynamic_pointer_cast<OvernightIndex>(overnightIndex->clone(termStructureHandle_));
// We want to be notified of changes of fixings, but we don't
Expand All @@ -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_)
Expand Down Expand Up @@ -187,55 +225,10 @@ namespace QuantLib {
Natural lockoutDays,
bool applyObservationShift,
const ext::shared_ptr<FloatingRateCouponPricer>& pricer)
: RateHelper(fixedRate), discountHandle_(std::move(discount)),
telescopicValueDates_(telescopicValueDates), averagingMethod_(averagingMethod) {

auto clonedOvernightIndex =
ext::dynamic_pointer_cast<OvernightIndex>(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);
}
: OISRateHelper(startDate, endDate, fixedRate, overnightIndex, std::move(discount), telescopicValueDates,
paymentLag, paymentConvention, paymentFrequency, paymentCalendar, overnightSpread,
Pillar::LastRelevantDate, Date(), averagingMethod, endOfMonth, fixedPaymentFrequency,
fixedCalendar, lookbackDays, lockoutDays, applyObservationShift, pricer) {}

DatedOISRateHelper::DatedOISRateHelper(const Date& startDate,
const Date& endDate,
Expand All @@ -257,35 +250,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<YieldTermStructure> 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<Visitor<DatedOISRateHelper>*>(&v);
if (v1 != nullptr)
v1->visit(*this);
else
RateHelper::accept(v);
}

}
113 changes: 58 additions & 55 deletions ql/termstructures/yield/oisratehelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ namespace QuantLib {
Natural lockoutDays = 0,
bool applyObservationShift = false,
ext::shared_ptr<FloatingRateCouponPricer> pricer = {});
OISRateHelper(const Date& startDate,
const Date& endDate,
const Handle<Quote>& fixedRate,
const ext::shared_ptr<OvernightIndex>& overnightIndex,
// exogenous discounting curve
Handle<YieldTermStructure> 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<bool> endOfMonth = ext::nullopt,
ext::optional<Frequency> fixedPaymentFrequency = ext::nullopt,
Calendar fixedCalendar = Calendar(),
Natural lookbackDays = Null<Natural>(),
Natural lockoutDays = 0,
bool applyObservationShift = false,
ext::shared_ptr<FloatingRateCouponPricer> pricer = {});
//! \name RateHelper interface
//@{
Real impliedQuote() const override;
Expand All @@ -73,39 +95,44 @@ namespace QuantLib {
//@{
void accept(AcyclicVisitor&) override;
//@}
protected:
void initializeDates() override;
Pillar::Choice pillarChoice_;

Natural settlementDays_;
Period tenor_;
ext::shared_ptr<OvernightIndex> overnightIndex_;

ext::shared_ptr<OvernightIndexedSwap> swap_;
RelinkableHandle<YieldTermStructure> termStructureHandle_;

Handle<YieldTermStructure> discountHandle_;
bool telescopicValueDates_;
RelinkableHandle<YieldTermStructure> discountRelinkableHandle_;

Integer paymentLag_;
BusinessDayConvention paymentConvention_;
Frequency paymentFrequency_;
Calendar paymentCalendar_;
Period forwardStart_;
Spread overnightSpread_;
RateAveraging::Type averagingMethod_;
ext::optional<bool> endOfMonth_;
ext::optional<Frequency> fixedPaymentFrequency_;
Calendar fixedCalendar_;
Natural lookbackDays_;
Natural lockoutDays_;
bool applyObservationShift_;
ext::shared_ptr<FloatingRateCouponPricer> pricer_;
protected:
void initialize(const ext::shared_ptr<OvernightIndex>& overnightIndex,
Date customPillarDate);
void initializeDates() override;

Natural settlementDays_;
Period tenor_;
Date startDate_, endDate_;
ext::shared_ptr<OvernightIndex> overnightIndex_;

ext::shared_ptr<OvernightIndexedSwap> swap_;
RelinkableHandle<YieldTermStructure> termStructureHandle_;

Handle<YieldTermStructure> discountHandle_;
bool telescopicValueDates_;
RelinkableHandle<YieldTermStructure> discountRelinkableHandle_;

Integer paymentLag_;
BusinessDayConvention paymentConvention_;
Frequency paymentFrequency_;
Calendar paymentCalendar_;
Period forwardStart_;
Spread overnightSpread_;
Pillar::Choice pillarChoice_;
RateAveraging::Type averagingMethod_;
ext::optional<bool> endOfMonth_;
ext::optional<Frequency> fixedPaymentFrequency_;
Calendar fixedCalendar_;
Natural lookbackDays_;
Natural lockoutDays_;
bool applyObservationShift_;
ext::shared_ptr<FloatingRateCouponPricer> 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,
Expand Down Expand Up @@ -149,30 +176,6 @@ namespace QuantLib {
ext::optional<bool> endOfMonth = ext::nullopt,
ext::optional<Frequency> 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<OvernightIndexedSwap> swap() const { return swap_; }
//@}
//@}
//! \name Visitability
//@{
void accept(AcyclicVisitor&) override;
//@}
protected:
ext::shared_ptr<OvernightIndexedSwap> swap_;
RelinkableHandle<YieldTermStructure> termStructureHandle_;

Handle<YieldTermStructure> discountHandle_;
bool telescopicValueDates_;
RelinkableHandle<YieldTermStructure> discountRelinkableHandle_;
RateAveraging::Type averagingMethod_;
};

}
Expand Down
4 changes: 2 additions & 2 deletions test-suite/overnightindexedswap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,8 @@ BOOST_AUTO_TEST_CASE(test131BootstrapRegression) {
auto estr = ext::make_shared<Estr>();

std::vector<ext::shared_ptr<RateHelper>> helpers;
helpers.push_back(ext::make_shared<OISRateHelper>(2, 1 * Weeks, Handle<Quote>(ext::make_shared<SimpleQuote>(0.070/100)), estr));
helpers.push_back(ext::make_shared<DatedOISRateHelper>(Date(16, January, 2013), Date(13, February, 2013), Handle<Quote>(ext::make_shared<SimpleQuote>(0.046/100)), estr));
helpers.push_back(ext::make_shared<OISRateHelper>(2, 1 * Weeks, makeQuoteHandle(0.070/100), estr));
helpers.push_back(ext::make_shared<OISRateHelper>(Date(16, January, 2013), Date(13, February, 2013), makeQuoteHandle(0.046/100), estr));

auto curve = PiecewiseYieldCurve<ForwardRate,BackwardFlat>(0, TARGET(), helpers, Actual365Fixed());
BOOST_CHECK_NO_THROW(curve.nodes());
Expand Down

0 comments on commit 912c944

Please sign in to comment.