From c8c0b65b7bbe15e202c105764c6a57b126f61934 Mon Sep 17 00:00:00 2001 From: Zetterberg <119352036+oszette@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:09:53 +0100 Subject: [PATCH 1/2] Add fixingDays parameter to applyStubInterpolation --- OREData/ored/portfolio/legdata.cpp | 2 +- OREData/ored/portfolio/legdata.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/OREData/ored/portfolio/legdata.cpp b/OREData/ored/portfolio/legdata.cpp index 2ead26e77b..ba1fd98956 100644 --- a/OREData/ored/portfolio/legdata.cpp +++ b/OREData/ored/portfolio/legdata.cpp @@ -1231,7 +1231,7 @@ Leg makeZCFixedLeg(const LegData& data, const QuantLib::Date& openEndDateReplace void applyStubInterpolation(Leg::iterator c, const std::string& shortIndexStr, const std::string& longIndexStr, const std::string& roundingTypeStr, const std::string& roundingPrecisionStr, const QuantLib::ext::shared_ptr& engineFactory, - const bool useOriginalIndexCurve, const Size accrualDays) { + const bool useOriginalIndexCurve, const Size accrualDays, const Size fixingDays) { if (shortIndexStr.empty() && longIndexStr.empty()) { return; } diff --git a/OREData/ored/portfolio/legdata.hpp b/OREData/ored/portfolio/legdata.hpp index 1f89a483ea..a3dfcf02dc 100644 --- a/OREData/ored/portfolio/legdata.hpp +++ b/OREData/ored/portfolio/legdata.hpp @@ -1259,7 +1259,8 @@ Leg buildNotionalLeg(const LegData& data, const Leg& leg, RequiredFixings& requi void applyStubInterpolation(Leg::iterator c, const std::string& shortIndexStr, const std::string& longIndexStr, const std::string& roundingTypeStr, const std::string& roundingPrecisionStr, const QuantLib::ext::shared_ptr& engineFactory, - const bool useOriginalIndexCurve, const Size accrualDays = Null()); + const bool useOriginalIndexCurve, const Size accrualDays = Null(), + const Size fixingDays = Null()); } // namespace data } // namespace ore From bd6f40ae3d9ad6c68ccb230d5beba8ac4e3611d1 Mon Sep 17 00:00:00 2001 From: Zetterberg <119352036+oszette@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:16:29 +0100 Subject: [PATCH 2/2] Pass fixingDays from floatData or index IborCoupon can be created without defining fixingDays, which will cause errors. To mitigate this, one solution is to be able to pass in fixingDays into applyStubInterpolation and use it if it is defined, if not you can try and retrieve it from the coupon (which still ofc can fail). --- OREData/ored/portfolio/legdata.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/OREData/ored/portfolio/legdata.cpp b/OREData/ored/portfolio/legdata.cpp index ba1fd98956..7b4a7a44b2 100644 --- a/OREData/ored/portfolio/legdata.cpp +++ b/OREData/ored/portfolio/legdata.cpp @@ -1253,6 +1253,7 @@ void applyStubInterpolation(Leg::iterator c, const std::string& shortIndexStr, c iborCpn = QuantLib::ext::dynamic_pointer_cast(*c); } QL_REQUIRE(iborCpn, "applyStubInterpolation(): unable to unpack coupon to ibor coupon"); + Size fDays = fixingDays == Null() ? iborCpn->fixingDays() : fixingDays; // ... replace it with an interpolated Ibor Coupon ... QuantLib::ext::shared_ptr idx1, idx2; if (!shortIndexStr.empty()) @@ -1269,7 +1270,7 @@ void applyStubInterpolation(Leg::iterator c, const std::string& shortIndexStr, c // actually no interpolation, only one index is given effectively, so we can use an Ibor Coupon tmp = QuantLib::ext::make_shared( iborCpn->date(), iborCpn->nominal(), iborCpn->accrualStartDate(), iborCpn->accrualEndDate(), - iborCpn->fixingDays(), + fDays, useOriginalIndexCurve ? idx1->clone(iborCpn->iborIndex()->forwardingTermStructure()) : idx1, iborCpn->gearing(), iborCpn->spread(), iborCpn->referencePeriodStart(), iborCpn->referencePeriodEnd(), iborCpn->dayCounter(), iborCpn->isInArrears(), iborCpn->exCouponDate()); @@ -1287,7 +1288,7 @@ void applyStubInterpolation(Leg::iterator c, const std::string& shortIndexStr, c useOriginalIndexCurve ? iborCpn->iborIndex()->forwardingTermStructure() : Handle()); tmp = QuantLib::ext::make_shared( iborCpn->date(), iborCpn->nominal(), iborCpn->accrualStartDate(), iborCpn->accrualEndDate(), - iborCpn->fixingDays(), interpolatedIndex, iborCpn->gearing(), iborCpn->spread(), + fDays, interpolatedIndex, iborCpn->gearing(), iborCpn->spread(), iborCpn->referencePeriodStart(), iborCpn->referencePeriodEnd(), iborCpn->dayCounter(), iborCpn->isInArrears(), iborCpn->exCouponDate(), iborCpn->iborIndex()); DLOG("created InterpolatedIborIndex for accrual period " @@ -1465,7 +1466,7 @@ Leg makeIborLeg(const LegData& data, const QuantLib::ext::shared_ptr& // front / back stub interpolation applyStubInterpolation(leg.begin(), floatData->frontStubShortIndex(), floatData->frontStubLongIndex(), floatData->frontStubRoundingType(), floatData->frontStubRoundingPrecision(), engineFactory, - floatData->stubUseOriginalCurve()); + floatData->stubUseOriginalCurve(), Null(), fixingDays); if (leg.size() == 1 && !floatData->frontStubShortIndex().empty() && !floatData->frontStubLongIndex().empty() && !floatData->backStubShortIndex().empty() && !floatData->backStubLongIndex().empty()) { @@ -1474,7 +1475,7 @@ Leg makeIborLeg(const LegData& data, const QuantLib::ext::shared_ptr& } else { applyStubInterpolation(leg.end() - 1, floatData->backStubShortIndex(), floatData->backStubLongIndex(), floatData->backStubRoundingType(), floatData->backStubRoundingPrecision(), engineFactory, - floatData->stubUseOriginalCurve()); + floatData->stubUseOriginalCurve(), Null(), fixingDays); } return leg; } @@ -1588,7 +1589,7 @@ Leg makeIborLeg(const LegData& data, const QuantLib::ext::shared_ptr& // front / back stub interpolation applyStubInterpolation(tmpLeg.begin(), floatData->frontStubShortIndex(), floatData->frontStubLongIndex(), floatData->frontStubRoundingType(), floatData->frontStubRoundingPrecision(), engineFactory, - floatData->stubUseOriginalCurve()); + floatData->stubUseOriginalCurve(), Null(), fixingDays); if (tmpLeg.size() == 1 && !floatData->frontStubShortIndex().empty() && !floatData->frontStubLongIndex().empty() && !floatData->backStubShortIndex().empty() && !floatData->backStubLongIndex().empty()) { @@ -1597,7 +1598,7 @@ Leg makeIborLeg(const LegData& data, const QuantLib::ext::shared_ptr& } else { applyStubInterpolation(tmpLeg.end() - 1, floatData->backStubShortIndex(), floatData->backStubLongIndex(), floatData->backStubRoundingType(), floatData->backStubRoundingPrecision(), engineFactory, - floatData->stubUseOriginalCurve()); + floatData->stubUseOriginalCurve(), Null(), fixingDays); } // return the leg