From 0eff87734e487f4bb672a97bf634c7e4d0004caa Mon Sep 17 00:00:00 2001 From: Peter Caspers Date: Sat, 1 Nov 2025 14:02:31 +0100 Subject: [PATCH 1/5] 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/5] 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 585a2c3a8b672d16fbc4993cdfbbbffc485a8e4f Mon Sep 17 00:00:00 2001 From: farahkhashman Date: Wed, 21 Jan 2026 11:33:25 +0000 Subject: [PATCH 3/5] merge conflict fix v1.8.14.1 --- QuantLib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuantLib b/QuantLib index ee9cf1dde5..a6ef3224df 160000 --- a/QuantLib +++ b/QuantLib @@ -1 +1 @@ -Subproject commit ee9cf1dde56965141be6fa87ddfce9fa42034580 +Subproject commit a6ef3224dfe0024debde0a14ca6e0af6d8a00ee1 From 9b3150d9b7c57efc26fda1b834afcad4f1832172 Mon Sep 17 00:00:00 2001 From: farahkhashman Date: Wed, 21 Jan 2026 13:30:57 +0000 Subject: [PATCH 4/5] align submodules --- ORE-SWIG/QuantLib-SWIG | 2 +- QuantLib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ORE-SWIG/QuantLib-SWIG b/ORE-SWIG/QuantLib-SWIG index 18203bf0af..b1184e42d4 160000 --- a/ORE-SWIG/QuantLib-SWIG +++ b/ORE-SWIG/QuantLib-SWIG @@ -1 +1 @@ -Subproject commit 18203bf0af4639a51a08c705e7b07bc864d2116b +Subproject commit b1184e42d4a544bd46f260b825d4fe7e31442450 diff --git a/QuantLib b/QuantLib index a6ef3224df..2937e4bc8f 160000 --- a/QuantLib +++ b/QuantLib @@ -1 +1 @@ -Subproject commit a6ef3224dfe0024debde0a14ca6e0af6d8a00ee1 +Subproject commit 2937e4bc8f3e44c16ea1149cfcbe12a8eed1ea29 From e823041cb3adf5dfce7780466d37b7466eedecb0 Mon Sep 17 00:00:00 2001 From: Cornelius motlhala Date: Fri, 10 Apr 2026 17:13:14 +0200 Subject: [PATCH 5/5] Update README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 23dba84d67..d4c8bc397d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ORE The [Open Source Risk](http://opensourcerisk.org) project aims at -establishing a transparent peer-reviewed framework for pricing and risk +establishing a transparent peer-previewed framework for pricing and risk analysis that can serve as * a benchmarking, validation, training, teaching reference * an extensible foundation for tailored risk solutions @@ -68,5 +68,15 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# Contribution by Cornelius Motlhala +# Implementation of Potential Future Exposure (PFE) for 50-Year Horizons +import numpy as np +def calculate_bis_pfe(mtm, vol, time, conf=0.95): + # z-score for 95th percentile (BIS Reporting Standard) + z = 1.645 + addon = mtm * vol * np.sqrt(time) * z + return max(0, mtm + addon) + +print(f"PFE Result: {calculate_bis_pfe(10000000,