From 0eff87734e487f4bb672a97bf634c7e4d0004caa Mon Sep 17 00:00:00 2001 From: Peter Caspers Date: Sat, 1 Nov 2025 14:02:31 +0100 Subject: [PATCH 1/3] QPR-13654 move built flag to trade level --- OREData/ored/portfolio/portfolio.cpp | 10 +++++++--- OREData/ored/portfolio/portfolio.hpp | 3 +-- OREData/ored/portfolio/trade.cpp | 2 ++ OREData/ored/portfolio/trade.hpp | 7 +++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/OREData/ored/portfolio/portfolio.cpp b/OREData/ored/portfolio/portfolio.cpp index 22317fbd2f..44529070c5 100644 --- a/OREData/ored/portfolio/portfolio.cpp +++ b/OREData/ored/portfolio/portfolio.cpp @@ -42,7 +42,6 @@ void Portfolio::clear() { } void Portfolio::reset() { - isBuilt_ = false; LOG("Reset portfolio of size " << trades_.size()); for (auto [id, t] : trades_) t->reset(); @@ -175,9 +174,13 @@ void Portfolio::build(const QuantLib::ext::shared_ptr& engineFact .log(); } QL_REQUIRE(trades_.size() > 0, "Portfolio does not contain any built trades, context is '" + context + "'"); - isBuilt_ = true; } +bool Portfolio::isBuilt() const { + return std::all_of(trades_.begin(), trades_.end(), [](const auto& s) { return s.second->isBuilt(); }); +} + + Date Portfolio::maturity() const { QL_REQUIRE(trades_.size() > 0, "Cannot get maturity of an empty portfolio"); Date mat = Date::minDate(); @@ -221,7 +224,6 @@ void Portfolio::add(const QuantLib::ext::shared_ptr& trade) { QL_REQUIRE(!has(trade->id()), "Attempted to add a trade to the portfolio with an id, which already exists."); underlyingIndicesCache_.clear(); trades_[trade->id()] = trade; - isBuilt_ = false; } bool Portfolio::has(const string& id) { return trades_.find(id) != trades_.end(); } @@ -308,6 +310,7 @@ std::pair, bool> buildTrade(QuantLib::ext::shar try { trade->reset(); trade->build(engineFactory); + trade->setBuilt(); TLOG("Required Fixings for trade " << trade->id() << ":"); TLOGGERSTREAM(trade->requiredFixings()); return std::make_pair(nullptr, true); @@ -326,6 +329,7 @@ std::pair, bool> buildTrade(QuantLib::ext::shar failed->setEnvelope(trade->envelope()); failed->build(engineFactory); failed->resetPricingStats(trade->getNumberOfPricings(), trade->getCumulativePricingTime()); + failed->setBuilt(); LOG("Built failed trade with id " << failed->id()); return std::make_pair(failed, false); } else { diff --git a/OREData/ored/portfolio/portfolio.hpp b/OREData/ored/portfolio/portfolio.hpp index e966b13a4d..8630634f5e 100644 --- a/OREData/ored/portfolio/portfolio.hpp +++ b/OREData/ored/portfolio/portfolio.hpp @@ -87,7 +87,7 @@ class Portfolio : public XMLSerializable { const bool emitStructuredError = true); //! if the portfolio has been built - bool isBuilt() const { return isBuilt_; } + bool isBuilt() const; //! Calculates the maturity of the portfolio QuantLib::Date maturity() const; @@ -138,7 +138,6 @@ class Portfolio : public XMLSerializable { bool buildFailedTrades_, ignoreTradeBuildFail_; std::map> trades_; std::map> underlyingIndicesCache_; - bool isBuilt_ = false; }; std::pair, bool> buildTrade( diff --git a/OREData/ored/portfolio/trade.cpp b/OREData/ored/portfolio/trade.cpp index bbb5bf74bf..12c98fb86d 100644 --- a/OREData/ored/portfolio/trade.cpp +++ b/OREData/ored/portfolio/trade.cpp @@ -300,6 +300,8 @@ void Trade::reset() { savedNumberOfPricings_ += instrument_->getNumberOfPricings(); savedCumulativePricingTime_ += instrument_->getCumulativePricingTime(); } + // reset build status + setBuilt(false); // reset members instrument_ = QuantLib::ext::shared_ptr(); legs_.clear(); diff --git a/OREData/ored/portfolio/trade.hpp b/OREData/ored/portfolio/trade.hpp index 429ed3bdf6..06ccce7de4 100644 --- a/OREData/ored/portfolio/trade.hpp +++ b/OREData/ored/portfolio/trade.hpp @@ -246,6 +246,12 @@ class Trade : public XMLSerializable { const std::string& configuration, const bool includePastCashflows) const; + /* set build status, this flag is maintained in buildTrade() and Trade::reset(), i.e. _not_ in Trade::build() */ + void setBuilt(const bool b = true) const { isBuilt_ = b; } + + /* get build status */ + bool isBuilt() const { return isBuilt_; } + protected: string tradeType_; // class name of the derived class QuantLib::ext::shared_ptr instrument_; @@ -294,6 +300,7 @@ class Trade : public XMLSerializable { string id_; Envelope envelope_; TradeActions tradeActions_; + mutable bool isBuilt_ = false; }; template From 1c7fb035ee78e89f7f192a6141f11deffd414e25 Mon Sep 17 00:00:00 2001 From: Peter Caspers Date: Tue, 4 Nov 2025 14:59:22 +0100 Subject: [PATCH 2/3] align submodule --- ORE-SWIG/QuantLib-SWIG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ORE-SWIG/QuantLib-SWIG b/ORE-SWIG/QuantLib-SWIG index 9b1d648856..18203bf0af 160000 --- a/ORE-SWIG/QuantLib-SWIG +++ b/ORE-SWIG/QuantLib-SWIG @@ -1 +1 @@ -Subproject commit 9b1d6488567f1cc84ab55d4c08cfef7ea7d1550b +Subproject commit 18203bf0af4639a51a08c705e7b07bc864d2116b From 13ae7c26c835f05e77348eefbb3a407d1edefb72 Mon Sep 17 00:00:00 2001 From: Xiaofeng Hao Date: Tue, 13 Jan 2026 15:06:59 +0800 Subject: [PATCH 3/3] Update SwaptionVol configuration reference --- OREData/ored/marketdata/marketimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OREData/ored/marketdata/marketimpl.cpp b/OREData/ored/marketdata/marketimpl.cpp index aff87688d9..d64fd2484a 100644 --- a/OREData/ored/marketdata/marketimpl.cpp +++ b/OREData/ored/marketdata/marketimpl.cpp @@ -140,7 +140,7 @@ Handle MarketImpl::swaptionVol(const stri } // check if we have a curve for the ccy in the default config if (configuration != Market::defaultConfiguration) { - require(MarketObject::SwaptionVol, ccy, configuration); + require(MarketObject::SwaptionVol, ccy, Market::defaultConfiguration); auto it4 = swaptionCurves_.find(make_pair(Market::defaultConfiguration, ccy)); if (it4 != swaptionCurves_.end()) return it4->second;