Skip to content

Commit e2dc667

Browse files
mgronckijenkins
authored andcommitted
QPR-12108 QPR-10957 QPR-12107: bugfix FixingDateGetter for offpeakpowerindexes
1 parent f29e4e7 commit e2dc667

3 files changed

Lines changed: 58 additions & 11 deletions

File tree

OREAnalytics/orea/app/marketdataloader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ void MarketDataLoader::populateFixings(
197197
// apply all fixings now
198198
applyFixings(loader_->loadFixings());
199199

200-
// check and warn any missing fixings - only warn for portfolio fixings
200+
// check and warn any missing fixings - only warn for mandatory fixings
201201
for (const auto& [indexName, fixingDates] : fixings_) {
202202
for (const auto& [d, mandatory] :fixingDates) {
203203
if (mandatory && !loader_->hasFixing(indexName, d)) {

OREData/ored/portfolio/fixingdates.cpp

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,30 @@ void RequiredFixings::unsetPayDates() {
208208
yoyInflationFixingDates_ = newYoYInflationFixingDates;
209209
}
210210

211+
RequiredFixings RequiredFixings::makeCopyWithMandatoryOverride(bool mandatory) {
212+
RequiredFixings result(*this);
213+
// we can't modify the elements of a set directly, need to make a copy and reassign
214+
std::set<FixingEntry> newFixingDates;
215+
std::set<ZeroInflationFixingEntry> newZeroInflationFixingDates;
216+
std::set<InflationFixingEntry> newYoYInflationFixingDates;
217+
for (auto f : result.fixingDates_) {
218+
f.mandatory = mandatory;
219+
newFixingDates.insert(f);
220+
}
221+
for (auto f : result.zeroInflationFixingDates_) {
222+
f.mandatory = mandatory;
223+
newZeroInflationFixingDates.insert(f);
224+
}
225+
for (auto f : yoyInflationFixingDates_) {
226+
f.mandatory = mandatory;
227+
newYoYInflationFixingDates.insert(f);
228+
}
229+
result.fixingDates_ = newFixingDates;
230+
result.zeroInflationFixingDates_ = newZeroInflationFixingDates;
231+
result.yoyInflationFixingDates_ = newYoYInflationFixingDates;
232+
return result;
233+
}
234+
211235
RequiredFixings RequiredFixings::filteredFixingDates(const Date& settlementDate) {
212236
RequiredFixings rf;
213237
// If settlement date is an empty date, update to evaluation date.
@@ -656,17 +680,35 @@ void FixingDateGetter::visit(EquityMarginCoupon& c) {
656680

657681
void FixingDateGetter::visit(CommodityCashFlow& c) {
658682
auto indices = c.indices();
659-
for (const auto& kv : indices) {
683+
for (const auto& [pricingDate, index] : indices) {
660684
// todays fixing is not mandatory, we will fallback to estimate it if its not there.
661-
bool isTodaysFixing = Settings::instance().evaluationDate() == kv.first;
662-
// see above, the ql and ORE index names are identical
663-
requiredFixings_.addFixingDate(kv.first, kv.second->name(), c.date(), false, !isTodaysFixing);
664-
// if the pricing date is > future expiry, add the future expiry itself as well
665-
if (auto d = kv.second->expiryDate(); d != Date() && d < kv.first) {
666-
requiredFixings_.addFixingDate(d, kv.second->name(), d);
667-
}
668-
if (auto baseFutureIndex = boost::dynamic_pointer_cast<CommodityBasisFutureIndex>(kv.second)) {
669-
baseFutureIndex->baseCashflow(c.date())->accept(*this);
685+
bool isTodaysFixing = Settings::instance().evaluationDate() == pricingDate;
686+
if (auto powerIndex = boost::dynamic_pointer_cast<OffPeakPowerIndex>(index)) {
687+
// see above, the ql and ORE index names are identical
688+
requiredFixings_.addFixingDate(pricingDate, powerIndex->offPeakIndex()->name(), c.date(), false,
689+
!isTodaysFixing);
690+
bool isOffPeakDay = powerIndex->peakCalendar().isHoliday(pricingDate);
691+
requiredFixings_.addFixingDate(pricingDate, powerIndex->peakIndex()->name(), c.date(), false,
692+
isOffPeakDay && !isTodaysFixing);
693+
// if the pricing date is > future expiry, add the future expiry itself as well
694+
if (auto d = index->expiryDate(); d != Date() && d < pricingDate) {
695+
requiredFixings_.addFixingDate(d, powerIndex->offPeakIndex()->name(), c.date(), false, !isTodaysFixing);
696+
requiredFixings_.addFixingDate(d, powerIndex->peakIndex()->name(), c.date(), false,
697+
isOffPeakDay && !isTodaysFixing);
698+
}
699+
} else {
700+
requiredFixings_.addFixingDate(pricingDate, index->name(), c.date(), false, !isTodaysFixing);
701+
// if the pricing date is > future expiry, add the future expiry itself as well
702+
if (auto d = index->expiryDate(); d != Date() && d < pricingDate) {
703+
requiredFixings_.addFixingDate(d, index->name(), c.date(), false, !isTodaysFixing);
704+
}
705+
}
706+
if (auto baseFutureIndex = boost::dynamic_pointer_cast<CommodityBasisFutureIndex>(index)) {
707+
RequiredFixings tmpFixings;
708+
FixingDateGetter baseCashflowGetter(tmpFixings);
709+
baseFutureIndex->baseCashflow(c.date())->accept(baseCashflowGetter);
710+
auto optionalFixings = tmpFixings.makeCopyWithMandatoryOverride(false);
711+
requiredFixings_.addData(optionalFixings);
670712
}
671713
}
672714
}

OREData/ored/portfolio/fixingdates.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class RequiredFixings {
160160
QuantLib::Frequency couponFrequency;
161161
friend bool operator<(const ZeroInflationFixingEntry& lhs, const ZeroInflationFixingEntry& rhs);
162162
};
163+
163164
/*! Gives back the dates for which fixings will be required to price the trade assuming a given \p settlementDate.
164165
If the \p settlementDate is not provided or is set equal to \c QuantLib::Date(), the settlement date in the
165166
implementation is assumed to be the \c Settings::instance().evaluationDate().
@@ -229,6 +230,10 @@ class RequiredFixings {
229230
past payment date can still be relevant for the payment of the current return period. */
230231
void unsetPayDates();
231232

233+
234+
/*! Create a copy and set mandatory flag to mandatory for all fixing entries */
235+
RequiredFixings makeCopyWithMandatoryOverride(bool mandatory);
236+
232237
RequiredFixings filteredFixingDates(const QuantLib::Date& settlementDate = QuantLib::Date());
233238

234239
private:

0 commit comments

Comments
 (0)