diff --git a/ql/cashflow.hpp b/ql/cashflow.hpp index 5de9a88d19c..e1e98e5dae5 100644 --- a/ql/cashflow.hpp +++ b/ql/cashflow.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace QuantLib { @@ -36,7 +37,7 @@ namespace QuantLib { /*! This class is purely virtual and acts as a base class for the actual cash flow implementations. */ - class CashFlow : public Event { + class CashFlow : public Event, public LazyObject { public: ~CashFlow() override = default; //! \name Event interface @@ -50,6 +51,10 @@ namespace QuantLib { bool hasOccurred(const Date& refDate = Date(), ext::optional includeRefDate = ext::nullopt) const override; //@} + //! \name LazyObject interface + //@{ + void performCalculations() const override {} + //@} //! \name CashFlow interface //@{ //! returns the amount of the cash flow diff --git a/ql/cashflows/digitalcoupon.hpp b/ql/cashflows/digitalcoupon.hpp index 542594156e0..71ffe68d5c0 100644 --- a/ql/cashflows/digitalcoupon.hpp +++ b/ql/cashflows/digitalcoupon.hpp @@ -90,8 +90,7 @@ namespace QuantLib { Position::Type putPosition = Position::Long, bool isPutITMIncluded = false, Rate putDigitalPayoff = Null(), - const ext::shared_ptr& replication = - ext::shared_ptr(), + const ext::shared_ptr& replication = {}, bool nakedOption = false); //@} diff --git a/ql/cashflows/fixedratecoupon.cpp b/ql/cashflows/fixedratecoupon.cpp index 1ca0c98c3e6..0010f09c4e7 100644 --- a/ql/cashflows/fixedratecoupon.cpp +++ b/ql/cashflows/fixedratecoupon.cpp @@ -60,10 +60,14 @@ namespace QuantLib { rate_(std::move(interestRate)) {} Real FixedRateCoupon::amount() const { - return nominal()*(rate_.compoundFactor(accrualStartDate_, - accrualEndDate_, - refPeriodStart_, - refPeriodEnd_) - 1.0); + calculate(); + return amount_; + } + + void FixedRateCoupon::performCalculations() const { + amount_ = nominal() * (rate_.compoundFactor(accrualStartDate_, accrualEndDate_, + refPeriodStart_, refPeriodEnd_) - + 1.0); } Real FixedRateCoupon::accruedAmount(const Date& d) const { diff --git a/ql/cashflows/fixedratecoupon.hpp b/ql/cashflows/fixedratecoupon.hpp index 87763aa2398..17540e7b834 100644 --- a/ql/cashflows/fixedratecoupon.hpp +++ b/ql/cashflows/fixedratecoupon.hpp @@ -60,6 +60,10 @@ namespace QuantLib { const Date& refPeriodEnd = Date(), const Date& exCouponDate = Date()); //@} + //! \name LazyObject interface + //@{ + void performCalculations() const override; + //@} //! \name CashFlow interface //@{ Real amount() const override; @@ -77,6 +81,7 @@ namespace QuantLib { //@} private: InterestRate rate_; + mutable Real amount_; }; diff --git a/ql/cashflows/floatingratecoupon.hpp b/ql/cashflows/floatingratecoupon.hpp index d1d6ece9015..490d871124c 100644 --- a/ql/cashflows/floatingratecoupon.hpp +++ b/ql/cashflows/floatingratecoupon.hpp @@ -42,7 +42,7 @@ namespace QuantLib { class FloatingRateCouponPricer; //! base floating-rate coupon class - class FloatingRateCoupon : public Coupon, public LazyObject { + class FloatingRateCoupon : public Coupon { public: FloatingRateCoupon(const Date& paymentDate, Real nominal, diff --git a/ql/cashflows/indexedcashflow.cpp b/ql/cashflows/indexedcashflow.cpp index 00ef2a7f056..867727b3cc6 100644 --- a/ql/cashflows/indexedcashflow.cpp +++ b/ql/cashflows/indexedcashflow.cpp @@ -36,13 +36,17 @@ namespace QuantLib { } Real IndexedCashFlow::amount() const { + calculate(); + return amount_; + } + + void IndexedCashFlow::performCalculations() const { Real I0 = baseFixing(); Real I1 = indexFixing(); if (growthOnly_) - return notional_ * (I1 / I0 - 1.0); + amount_ = notional_ * (I1 / I0 - 1.0); else - return notional_ * (I1 / I0); + amount_ = notional_ * (I1 / I0); } - } diff --git a/ql/cashflows/indexedcashflow.hpp b/ql/cashflows/indexedcashflow.hpp index 41d85efe22d..b721e74b5b4 100644 --- a/ql/cashflows/indexedcashflow.hpp +++ b/ql/cashflows/indexedcashflow.hpp @@ -42,8 +42,7 @@ namespace QuantLib { growthOnly = false means i(T)/i(0), which is a bond-type setting. growthOnly = true means i(T)/i(0) - 1, which is a swap-type setting. */ - class IndexedCashFlow : public CashFlow, - public Observer { + class IndexedCashFlow : public CashFlow { public: IndexedCashFlow(Real notional, ext::shared_ptr index, @@ -70,15 +69,16 @@ namespace QuantLib { //@{ void accept(AcyclicVisitor&) override; //@} - //! \name Observer interface + //! \name LazyObject interface //@{ - void update() override { notifyObservers(); } + void performCalculations() const override; //@} private: Real notional_; ext::shared_ptr index_; Date baseDate_, fixingDate_, paymentDate_; bool growthOnly_; + mutable Real amount_; }; diff --git a/ql/cashflows/inflationcoupon.cpp b/ql/cashflows/inflationcoupon.cpp index ace9d7f9268..516e010310e 100644 --- a/ql/cashflows/inflationcoupon.cpp +++ b/ql/cashflows/inflationcoupon.cpp @@ -62,11 +62,16 @@ namespace QuantLib { Rate InflationCoupon::rate() const { + calculate(); + return rate_; + } + + void InflationCoupon::performCalculations() const { QL_REQUIRE(pricer_, "pricer not set"); // we know it is the correct type because checkPricerImpl checks on setting // in general pricer_ will be a derived class, as will *this on calling pricer_->initialize(*this); - return pricer_->swapletRate(); + rate_ = pricer_->swapletRate(); } diff --git a/ql/cashflows/inflationcoupon.hpp b/ql/cashflows/inflationcoupon.hpp index 7f03716eff6..0a1ddc06c44 100644 --- a/ql/cashflows/inflationcoupon.hpp +++ b/ql/cashflows/inflationcoupon.hpp @@ -43,8 +43,7 @@ namespace QuantLib { \note inflation indices do not contain day counters or calendars. */ - class InflationCoupon : public Coupon, - public Observer { + class InflationCoupon : public Coupon { public: InflationCoupon(const Date& paymentDate, Real nominal, @@ -85,9 +84,9 @@ namespace QuantLib { virtual Rate indexFixing() const; //@} - //! \name Observer interface + //! \name LazyObject interface //@{ - void update() override { notifyObservers(); } + void performCalculations() const override; //@} //! \name Visitability @@ -103,6 +102,7 @@ namespace QuantLib { Period observationLag_; DayCounter dayCounter_; Natural fixingDays_; + mutable Real rate_; //! makes sure you were given the correct type of pricer // this can also done in external pricer setter classes via diff --git a/ql/experimental/inflation/yoyoptionlethelpers.cpp b/ql/experimental/inflation/yoyoptionlethelpers.cpp index 89af2924671..a7a74f891a3 100644 --- a/ql/experimental/inflation/yoyoptionlethelpers.cpp +++ b/ql/experimental/inflation/yoyoptionlethelpers.cpp @@ -65,7 +65,7 @@ namespace QuantLib { Real YoYOptionletHelper::impliedQuote() const { - yoyCapFloor_->recalculate(); + yoyCapFloor_->deepUpdate(); return yoyCapFloor_->NPV(); } diff --git a/ql/instruments/bond.cpp b/ql/instruments/bond.cpp index 8fd704807d4..abecef6add6 100644 --- a/ql/instruments/bond.cpp +++ b/ql/instruments/bond.cpp @@ -355,9 +355,7 @@ namespace QuantLib { void Bond::deepUpdate() { for (auto& cashflow : cashflows_) { - if(auto lazy = ext::dynamic_pointer_cast(cashflow)) { - lazy->deepUpdate(); - } + cashflow->deepUpdate(); } update(); } diff --git a/ql/instruments/capfloor.cpp b/ql/instruments/capfloor.cpp index 70298e10906..cd39dde7e09 100644 --- a/ql/instruments/capfloor.cpp +++ b/ql/instruments/capfloor.cpp @@ -270,8 +270,7 @@ namespace QuantLib { void CapFloor::deepUpdate() { for (auto& i : floatingLeg_) { - if(auto lazy = ext::dynamic_pointer_cast(i)) - lazy->deepUpdate(); + i->deepUpdate(); } update(); } diff --git a/ql/instruments/swap.cpp b/ql/instruments/swap.cpp index e9e299f766f..d02852056e5 100644 --- a/ql/instruments/swap.cpp +++ b/ql/instruments/swap.cpp @@ -160,8 +160,7 @@ namespace QuantLib { void Swap::deepUpdate() { for (auto& leg : legs_) { for (auto& k : leg) { - if (auto lazy = ext::dynamic_pointer_cast(k)) - lazy->deepUpdate(); + k->deepUpdate(); } } update(); diff --git a/ql/termstructures/inflation/inflationhelpers.cpp b/ql/termstructures/inflation/inflationhelpers.cpp index 991d2c57040..7965d9aff38 100644 --- a/ql/termstructures/inflation/inflationhelpers.cpp +++ b/ql/termstructures/inflation/inflationhelpers.cpp @@ -74,7 +74,7 @@ namespace QuantLib { Real ZeroCouponInflationSwapHelper::impliedQuote() const { - zciis_->recalculate(); + zciis_->deepUpdate(); return zciis_->fairRate(); } @@ -155,7 +155,7 @@ namespace QuantLib { Real YearOnYearInflationSwapHelper::impliedQuote() const { - yyiis_->recalculate(); + yyiis_->deepUpdate(); return yyiis_->fairRate(); }