29#include <ql/cashflows/fixedratecoupon.hpp>
30#include <ql/cashflows/simplecashflow.hpp>
31#include <ql/time/calendars/weekendsonly.hpp>
32#include <ql/time/daycounters/one.hpp>
50 bool excludePeriodStart,
bool includePeriodEnd,
51 const QuantLib::ext::shared_ptr<CommodityFutureConvention>& conv,
52 const QuantLib::ext::shared_ptr<FutureExpiryCalculator>& calc, Natural hoursPerDay,
bool useBusinessDays,
53 const std::string& daylightSavingLocation,
const string& commName,
bool unrealisedQuantity,
54 const boost::optional<pair<Calendar, Real>>& offPeakPowerData) {
56 QL_REQUIRE(leg.size() == schedule.size() - 1,
"The number of schedule periods (" << (schedule.size() - 1) <<
57 ") was expected to equal the number of leg cashflows (" << leg.size() <<
") when updating quantities" <<
58 " for commodity " << commName <<
".");
61 if (cqf == CQF::PerCalculationPeriod) {
63 if (unrealisedQuantity) {
64 if (!isAveragingFuture) {
65 DLOG(
"The future " << commName <<
" is not averaging, unrealisedQuantity does not make sense" <<
66 " so the PerCalculationPeriod quantities have not been altered.");
67 }
else if (conv->contractFrequency() == Daily) {
68 DLOG(
"The future " << commName <<
" is averaging but has a daily frequency " <<
69 " so the PerCalculationPeriod quantities have not been altered.");
72 QL_REQUIRE(calc,
"Updating commodity quantities due to unrealisedQuantity = true, expected a" <<
73 " valid future expiry calculator, commodity is " << commName <<
".");
74 Size numberCashflows = leg.size();
75 for (Size i = 0; i < numberCashflows; ++i) {
77 auto ccf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(leg[i]);
78 QL_REQUIRE(ccf, io::ordinal(i + 1) <<
" quantity for commodity " << commName <<
79 ", expected a valid CommodityIndexedCashFlow.");
80 Date pricingDate = ccf->pricingDate();
81 Date aveEnd = calc->priorExpiry(
true, pricingDate);
82 Date aveStart = calc->priorExpiry(
false, aveEnd);
83 Date today = Settings::instance().evaluationDate();
85 if (aveStart <= today && today < aveEnd) {
87 QL_REQUIRE(conv,
"Need a valid convention for " << commName <<
88 " while updating quantities due to unrealisedQuantity = true.");
89 auto pds =
pricingDates(aveStart, aveEnd, conv->calendar(),
true,
true, useBusinessDays);
91 DLOG(
"UnrealisedQuantity is true so updating the quantity:");
92 DLOG(
"today: " << io::iso_date(today));
93 DLOG(
"pricing date: " << io::iso_date(pricingDate));
94 DLOG(
"period start: " << io::iso_date(aveStart));
95 DLOG(
"period end: " << io::iso_date(aveEnd));
97 Real unrealisedFraction = 0.0;
98 if (offPeakPowerData) {
100 Calendar peakCalendar = offPeakPowerData->first;
101 Real offPeakHours = offPeakPowerData->second;
104 for (
const auto& pd : pds) {
105 Real numHours = peakCalendar.isHoliday(pd) ? 24.0 : offPeakHours;
108 unrealised += numHours;
110 DLOG(
"total hours: " << total);
111 DLOG(
"unrealised hours: " << unrealised);
112 unrealisedFraction = unrealised / total;
116 auto unrealised = count_if(pds.begin(), pds.end(),
117 [&today](
const Date& pd) { return pd > today; });
118 DLOG(
"total pricing dates: " << pds.size());
119 DLOG(
"unrealised pricing dates: " << unrealised);
120 unrealisedFraction =
static_cast<Real
>(unrealised) / pds.size();
124 if (unrealisedFraction > 0) {
125 Real oldQuantity = ccf->quantity();
126 Real newQuantity = oldQuantity / unrealisedFraction;
127 DLOG(
"old quantity: " << oldQuantity);
128 DLOG(
"new quantity: " << newQuantity);
129 ccf->setPeriodQuantity(newQuantity);
131 DLOG(
"UnrealisedQuantity is true but cannot update the quantity because" <<
132 " value of unrealised is 0.");
141 DLOG(
"updateQuantities: quantity is PerCalculationPeriod and unrealisedQuantity is" <<
142 " false so nothing to update.");
145 }
else if (cqf == CQF::PerCalendarDay) {
147 QL_REQUIRE(conv,
"Need a valid convention for " << commName <<
148 " while updating quantities (PerCalendarDay).");
150 DLOG(
"updateQuantities: updating quantities based on PerCalendarDay.");
152 Size numberCashflows = leg.size();
153 for (Size i = 0; i < numberCashflows; ++i) {
154 Date start = schedule.date(i);
155 Date end = schedule.date(i + 1);
156 bool excludeStart = i == 0 ? false : excludePeriodStart;
157 bool includeEnd = i == numberCashflows - 1 ? true : includePeriodEnd;
158 auto ccf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(leg[i]);
159 QL_REQUIRE(ccf,
"Updating " << io::ordinal(i + 1) <<
" quantity for commodity " << commName <<
160 ", expected a valid CommodityIndexedCashFlow.");
161 Real newQuantity = ccf->quantity() * ((end - start - 1.0) +
162 (!excludeStart ? 1.0 : 0.0) + (includeEnd ? 1.0 : 0.0));
163 ccf->setPeriodQuantity(newQuantity);
164 DLOG(
"updateQuantities: updating quantity for pricing date " << ccf->pricingDate() <<
" from " <<
165 ccf->quantity() <<
" to " << newQuantity);
171 QL_REQUIRE(cqf == CQF::PerPricingDay || cqf == CQF::PerHour || cqf == CQF::PerHourAndCalendarDay,
172 "Did not cover commodity"
173 <<
" quantity frequency type " << cqf <<
" while updating quantities for " << commName <<
".");
176 Size numberCashflows = leg.size();
177 vector<Real> quantities(numberCashflows, 0.0);
178 vector<QuantLib::ext::shared_ptr<CommodityIndexedCashFlow>> ccfs(numberCashflows);
179 for (Size i = 0; i < numberCashflows; ++i) {
180 auto ccf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(leg[i]);
181 QL_REQUIRE(ccf,
"Updating " << io::ordinal(i + 1) <<
" quantity for commodity " << commName <<
182 ", expected a valid CommodityIndexedCashFlow.");
184 quantities[i] = ccf->quantity();
187 if (!isAveragingFuture) {
189 if (cqf == CQF::PerPricingDay) {
190 DLOG(
"The future " << commName <<
" is not averaging so a commodity quantity frequency equal to" <<
191 " PerPricingDay does not make sense. Quantities have not been altered. Commodity is " <<
194 DLOG(
"updateQuantities: the future " << commName <<
" is not averaging and quantity frequency is" <<
195 " PerHour so updating quantities with daily quantities.");
196 if (offPeakPowerData) {
197 QL_REQUIRE(cqf == CQF::PerHour,
"PerHourAndCalendarDay not allowed for "
198 "off-peak power contracts, expected PerHour");
199 Calendar peakCalendar = offPeakPowerData->first;
200 Real offPeakHours = offPeakPowerData->second;
201 for (Size i = 0; i < numberCashflows; ++i) {
202 Real numHours = peakCalendar.isHoliday(ccfs[i]->pricingDate()) ? 24.0 : offPeakHours;
203 ccfs[i]->setPeriodQuantity(quantities[i] * numHours);
204 DLOG(
"updateQuantities: updating quantity for pricing date " << ccfs[i]->pricingDate() <<
205 " from " << quantities[i] <<
" to " << (quantities[i] * numHours));
208 QL_REQUIRE(hoursPerDay != Null<Natural>(),
209 "Need HoursPerDay when commodity quantity frequency"
210 <<
" is PerHour or PerHourAndCalendarDay. Updating quantities failed, commodity is "
212 for (Size i = 0; i < numberCashflows; ++i) {
213 Real newQuantity = 0.0;
214 if (cqf == CQF::PerHour) {
215 newQuantity = quantities[i] * hoursPerDay;
216 }
else if (cqf == CQF::PerHourAndCalendarDay) {
217 Date start = schedule.date(i);
218 Date end = schedule.date(i + 1);
219 bool excludeStart = i == 0 ? false : excludePeriodStart;
220 bool includeEnd = i == numberCashflows - 1 ? true : includePeriodEnd;
221 int numberOfDays = ((end - start - 1) + (!excludeStart ? 1 : 0) + (includeEnd ? 1 : 0));
223 quantities[i] *
static_cast<Real
>(hoursPerDay) *
static_cast<Real
>(numberOfDays) +
226 ccfs[i]->setPeriodQuantity(newQuantity);
227 DLOG(
"updateQuantities: updating quantity for pricing date "
228 << ccfs[i]->pricingDate() <<
" from " << quantities[i] <<
" to "
229 << (quantities[i] * hoursPerDay));
236 QL_REQUIRE(conv,
"Need a valid convention for " << commName <<
237 " while updating quantities for averaging future (PerPricingDay/PerHour).");
241 if (conv->contractFrequency() == Daily) {
242 DLOG(
"The future " << commName <<
" is averaging but has a daily frequency " <<
243 " so the quantities have not been altered.");
250 QL_REQUIRE(calc,
"Updating commodity quantities expected a valid future expiry calculator" <<
251 ", commodity is " << commName <<
".");
252 DLOG(
"The future " << commName <<
" is averaging and does not have a daily frequency.");
253 for (Size i = 0; i < numberCashflows; ++i) {
254 Date pricingDate = ccfs[i]->pricingDate();
255 Date aveEnd = calc->priorExpiry(
true, pricingDate);
256 Date aveStart = calc->priorExpiry(
false, aveEnd);
257 auto pds =
pricingDates(aveStart, aveEnd, conv->calendar(),
true,
true, useBusinessDays);
258 if (cqf == CQF::PerHour || cqf == CQF::PerHourAndCalendarDay) {
259 if (offPeakPowerData) {
260 QL_REQUIRE(cqf == CQF::PerHour,
"PerHourAndCalendarDay not allowed for "
261 "off-peak power contracts, expected PerHour");
262 Calendar peakCalendar = offPeakPowerData->first;
263 Real offPeakHours = offPeakPowerData->second;
264 Real newQuantity = 0.0;
265 for (
const auto& pd : pds) {
266 newQuantity += quantities[i] * (peakCalendar.isHoliday(pd) ? 24.0 : offPeakHours);
268 ccfs[i]->setPeriodQuantity(newQuantity);
269 DLOG(
"updateQuantities: updating quantity for pricing date " << ccfs[i]->pricingDate() <<
270 " from " << quantities[i] <<
" to " << newQuantity);
272 QL_REQUIRE(hoursPerDay != Null<Natural>(),
273 "Need HoursPerDay when commodity"
274 <<
" quantity frequency is PerHour or PerHourAndCalendarDay. Commodity is "
276 Real newQuantity = 0.0;
277 if(cqf == CQF::PerHour) {
278 newQuantity = quantities[i] * hoursPerDay * pds.size();
279 }
else if (cqf == CQF::PerHourAndCalendarDay) {
280 Date start = schedule.date(i);
281 Date end = schedule.date(i + 1);
282 bool excludeStart = i == 0 ? false : excludePeriodStart;
283 bool includeEnd = i == numberCashflows - 1 ? true : includePeriodEnd;
285 ((end - start - 1) + (!excludeStart ? 1 : 0) + (includeEnd ? 1 : 0));
288 (
static_cast<Real
>(hoursPerDay) *
static_cast<Real
>(numberOfDays) +
291 ccfs[i]->setPeriodQuantity(newQuantity);
292 DLOG(
"updateQuantities: updating quantity for pricing date " << ccfs[i]->pricingDate() <<
293 " from " << quantities[i] <<
" to " << newQuantity);
296 ccfs[i]->setPeriodQuantity(quantities[i] * pds.size());
297 DLOG(
"updateQuantities: updating quantity for pricing date " << ccfs[i]->pricingDate() <<
298 " from " << quantities[i] <<
" to " << (quantities[i] * pds.size()));
313 const QuantLib::Date& openEndDateReplacement,
const bool useXbsCurves)
const {
316 auto fixedLegData = QuantLib::ext::dynamic_pointer_cast<CommodityFixedLegData>(
data.concreteLegData());
317 QL_REQUIRE(fixedLegData,
"Wrong LegType, expected CommodityFixed, got " <<
data.legType());
321 vector<Real> prices =
buildScheduledVector(fixedLegData->prices(), fixedLegData->priceDates(), schedule);
322 vector<Real> quantities =
buildScheduledVector(fixedLegData->quantities(), fixedLegData->quantityDates(), schedule);
327 Leg fixedRateLeg = FixedRateLeg(schedule)
328 .withNotionals(quantities)
329 .withCouponRates(prices, dc)
330 .withPaymentAdjustment(Unadjusted)
332 .withPaymentCalendar(NullCalendar());
335 vector<Date> paymentDates;
336 if (!
data.paymentDates().empty()) {
337 paymentDates = parseVectorOfValues<Date>(
data.paymentDates(), &
parseDate);
339 QL_REQUIRE(paymentDates.size() == fixedRateLeg.size(),
340 "Expected the number of payment dates derived from float leg with tag '"
341 << fixedLegData->tag() <<
"' (" << paymentDates.size()
342 <<
") to equal the number of fixed price periods (" << fixedRateLeg.size()
343 <<
"). Are the leg schedules consistent? Should CommodityPayRelativeTo = FutureExpiryDate "
346 QL_REQUIRE(paymentDates.size() == fixedRateLeg.size(),
347 "Expected the number of explicit payment dates ("
348 << paymentDates.size() <<
") to equal the number of fixed price periods ("
349 << fixedRateLeg.size() <<
")");
354 Leg commodityFixedLeg;
355 for (Size i = 0; i < fixedRateLeg.size(); i++) {
357 auto cp = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixedRateLeg[i]);
361 if (!paymentDates.empty()) {
363 Calendar paymentCalendar =
366 Period paymentLagPeriod = boost::apply_visitor(
PaymentLagPeriod(), paymentLag);
367 BusinessDayConvention paymentConvention =
369 pmtDate = paymentCalendar.advance(paymentDates[i], paymentLagPeriod, paymentConvention);
372 BusinessDayConvention bdc =
375 Calendar paymentCalendar =
383 pmtDate = cp->accrualEndDate();
385 pmtDate = cp->accrualStartDate();
387 pmtDate = fixedRateLeg.back()->date();
389 QL_FAIL(
"Internal error: commodity fixed leg builder can not determine payment date relative to future "
390 "expiry date, this has to be handled in the instrument builder.");
392 QL_FAIL(
"Unexpected value " << fixedLegData->commodityPayRelativeTo() <<
" for CommodityPayRelativeTo");
396 pmtDate = paymentCalendar.advance(pmtDate, paymentLag, bdc);
400 commodityFixedLeg.push_back(QuantLib::ext::make_shared<SimpleCashFlow>(cp->amount(), pmtDate));
403 applyIndexing(commodityFixedLeg,
data, engineFactory, requiredFixings, openEndDateReplacement, useXbsCurves);
404 addToRequiredFixings(commodityFixedLeg, QuantLib::ext::make_shared<FixingDateGetter>(requiredFixings));
406 addToRequiredFixings(commodityFixedLeg, QuantLib::ext::make_shared<ore::data::FixingDateGetter>(requiredFixings));
408 return commodityFixedLeg;
413 const QuantLib::Date& openEndDateReplacement,
const bool useXbsCurves)
const {
419 auto floatingLegData = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegData>(
data.concreteLegData());
420 QL_REQUIRE(floatingLegData,
"Wrong LegType: expected CommodityFloating but got " <<
data.legType());
424 string commName = floatingLegData->name();
425 Calendar commCal = WeekendsOnly();
426 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
427 QuantLib::ext::shared_ptr<CommodityFutureConvention> commFutureConv;
428 boost::optional<pair<Calendar, Real>> offPeakPowerData;
429 bool balanceOfTheMonth =
false;
430 if (conventions->has(commName)) {
431 QuantLib::ext::shared_ptr<Convention> commConv = conventions->get(commName);
434 if (
auto c = QuantLib::ext::dynamic_pointer_cast<CommodityForwardConvention>(commConv)) {
435 if (c->advanceCalendar() != NullCalendar()) {
436 commCal = c->advanceCalendar();
441 commFutureConv = QuantLib::ext::dynamic_pointer_cast<CommodityFutureConvention>(commConv);
442 if (commFutureConv) {
443 balanceOfTheMonth = commFutureConv->balanceOfTheMonth();
444 commCal = commFutureConv->calendar();
445 if (
const auto& oppid = commFutureConv->offPeakPowerIndexData()) {
446 offPeakPowerData = make_pair(oppid->peakCalendar(), oppid->offPeakHours());
455 QuantLib::ext::shared_ptr<FutureExpiryCalculator> feCalc;
459 QL_REQUIRE(commFutureConv,
"Expected to have a commodity future convention for commodity " << commName);
461 feCalc = QuantLib::ext::make_shared<ConventionsBasedFutureExpiry>(*commFutureConv);
465 if (commFutureConv->isAveraging()) {
466 QL_REQUIRE(floatingLegData->isAveraged(),
467 "The future, " << commName <<
", is averaging but the leg is not.");
473 Handle<PriceTermStructure> priceCurve = engineFactory->market()->commodityPriceCurve(commName, configuration);
479 vector<Real> quantities =
480 buildScheduledVector(floatingLegData->quantities(), floatingLegData->quantityDates(), schedule);
483 vector<Real> spreads =
buildScheduledVector(floatingLegData->spreads(), floatingLegData->spreadDates(), schedule);
484 vector<Real> gearings =
489 if (!floatingLegData->pricingDates().empty()) {
495 BusinessDayConvention paymentConvention =
497 Calendar paymentCalendar =
499 Calendar pricingCalendar;
502 if (floatingLegData->pricingCalendar().empty() && floatingLegData->isAveraged() && balanceOfTheMonth &&
504 pricingCalendar = commFutureConv->balanceOfTheMonthPricingCalendar();
505 }
else if (floatingLegData->pricingCalendar().empty()) {
506 pricingCalendar = commCal;
508 pricingCalendar =
parseCalendar(floatingLegData->pricingCalendar());
512 vector<Date> paymentDates;
515 Schedule paymentSchedule =
makeSchedule(
data.paymentSchedule(), openEndDateReplacement);
517 if (!paymentSchedule.empty()) {
518 paymentDates = paymentSchedule.dates();
519 }
else if (!
data.paymentDates().empty()) {
520 BusinessDayConvention paymentDatesConvention =
522 Calendar paymentDatesCalendar =
524 paymentDates = parseVectorOfValues<Date>(
data.paymentDates(), &
parseDate);
525 for (Size i = 0; i < paymentDates.size(); i++)
526 paymentDates[i] = paymentDatesCalendar.adjust(paymentDates[i], paymentDatesConvention);
530 auto hoursPerDay = floatingLegData->hoursPerDay();
531 if ((floatingLegData->commodityQuantityFrequency() == CommodityQuantityFrequency::PerHour ||
532 floatingLegData->commodityQuantityFrequency() == CommodityQuantityFrequency::PerHourAndCalendarDay) &&
533 hoursPerDay == Null<Natural>()) {
534 QL_REQUIRE(commFutureConv,
535 "Commodity floating leg commodity frequency set to PerHour / PerHourAndCalendarDay but"
536 <<
" no HoursPerDay provided in floating leg data and no commodity future convention for "
538 hoursPerDay = commFutureConv->hoursPerDay();
539 QL_REQUIRE(commFutureConv,
540 "Commodity floating leg commodity frequency set to PerHour / PerHourAndCalendarDay but"
541 <<
" no HoursPerDay provided in floating leg data and commodity future convention for "
542 << commName <<
" does not provide it.");
546 std::string daylightSavingLocation;
547 if (floatingLegData->commodityQuantityFrequency() == CommodityQuantityFrequency::PerHourAndCalendarDay) {
550 "Commodity floating leg commodity frequency set to PerHourAndCalendarDay, need commodity convention for "
552 daylightSavingLocation = commFutureConv->savingsTime();
554 QuantLib::ext::shared_ptr<FxIndex> fxIndex;
558 bool isCashFlowAveraged =
559 floatingLegData->isAveraged() && !
allAveraging_ && floatingLegData->lastNDays() == Null<Natural>();
562 auto dailyExpOffset = floatingLegData->dailyExpiryOffset();
563 if (dailyExpOffset != Null<Natural>() && dailyExpOffset > 0) {
564 QL_REQUIRE(commFutureConv,
"A positive DailyExpiryOffset has been provided but no commodity"
565 <<
" future convention given for " << commName);
566 QL_REQUIRE(commFutureConv->contractFrequency() == Daily,
567 "A positive DailyExpiryOffset has been"
568 <<
" provided but the commodity contract frequency is not Daily ("
569 << commFutureConv->contractFrequency() <<
")");
572 if (!floatingLegData->fxIndex().empty()) {
573 auto underlyingCcy = priceCurve->currency().code();
574 auto npvCurrency =
data.currency();
575 if (underlyingCcy != npvCurrency)
576 fxIndex =
buildFxIndex(floatingLegData->fxIndex(), npvCurrency, underlyingCcy, engineFactory->market(),
580 if (isCashFlowAveraged) {
582 CommodityIndexedAverageCashFlow::PaymentTiming::InArrears;
584 paymentTiming = CommodityIndexedAverageCashFlow::PaymentTiming::InAdvance;
586 paymentTiming = CommodityIndexedAverageCashFlow::PaymentTiming::InArrears;
588 QL_FAIL(
"CommodityLegBuilder: CommodityPayRelativeTo 'FutureExpiryDate' not allowed for average cashflow.");
590 QL_FAIL(
"CommodityLegBuilder: CommodityPayRelativeTo " << floatingLegData->commodityPayRelativeTo()
591 <<
" not handled. This is an internal error.");
622 paymentTiming = CommodityIndexedCashFlow::PaymentTiming::InAdvance;
624 paymentTiming = CommodityIndexedCashFlow::PaymentTiming::InArrears;
626 paymentTiming = CommodityIndexedCashFlow::PaymentTiming::RelativeToExpiry;
628 QL_FAIL(
"CommodityLegBuilder: CommodityPayRelativeTo " << floatingLegData->commodityPayRelativeTo()
629 <<
" not handled. This is an internal error.");
642 .
inArrears(floatingLegData->isInArrears())
658 updateQuantities(leg,
allAveraging_, floatingLegData->commodityQuantityFrequency(), schedule,
659 floatingLegData->excludePeriodStart(), floatingLegData->includePeriodEnd(), commFutureConv,
660 feCalc, hoursPerDay, floatingLegData->useBusinessDays(), daylightSavingLocation, commName,
661 floatingLegData->unrealisedQuantity(), offPeakPowerData);
664 auto lastNDays = floatingLegData->lastNDays();
665 if (lastNDays != Null<Natural>() && lastNDays > 1) {
666 if (commFutureConv) {
667 if (lastNDays > 31) {
668 WLOG(
"LastNDays (" << lastNDays <<
") should not be greater than 31. " <<
669 "Proceed as if it is not set.");
670 }
else if (commFutureConv->isAveraging()) {
671 WLOG(
"Commodity future convention for " << commName <<
" is averaging so LastNDays (" <<
672 lastNDays <<
") is ignored. Proceed as if it is not set.");
674 DLOG(
"Amending cashflows to account for LastNDays (" << lastNDays <<
").");
675 const auto& cal = commFutureConv->calendar();
676 for (
auto& cf : leg) {
677 auto ccf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(cf);
678 const Date& endDate = ccf->pricingDate();
679 Date startDate = cal.advance(endDate, -
static_cast<Integer
>(lastNDays) + 1, Days, Preceding);
680 TLOG(
"Creating cashflow averaging over period [" << io::iso_date(startDate) <<
681 "," << io::iso_date(endDate) <<
"]");
682 cf = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(ccf->periodQuantity(), startDate,
683 endDate, ccf->date(), ccf->index(), cal, ccf->spread(), ccf->gearing(),
684 ccf->useFuturePrice(), 0, 0, feCalc,
true,
false);
688 WLOG(
"Need a commodity future convention for " << commName <<
" when LastNDays (" << lastNDays <<
689 ") is set and greater than 1. Proceed as if it is not set.");
696 for (
auto cf : leg) {
697 auto cacf = QuantLib::ext::dynamic_pointer_cast<CommodityCashFlow>(cf);
698 QL_REQUIRE(cacf,
"Commodity Indexed averaged cashflow is required to compute daily converted average.");
699 for (
auto kv : cacf->indices()) {
700 if (!fxIndex->fixingCalendar().isBusinessDay(
704 Date adjustedFixingDate = fxIndex->fixingCalendar().adjust(kv.first, Preceding);
705 requiredFixings.
addFixingDate(adjustedFixingDate, floatingLegData->fxIndex());
707 requiredFixings.
addFixingDate(kv.first, floatingLegData->fxIndex());
712 applyIndexing(leg,
data, engineFactory, requiredFixings, openEndDateReplacement, useXbsCurves);
Engine builder for commodity swaps.
CommodityIndexedAverageLeg & useFuturePrice(bool flag=false)
CommodityIndexedAverageLeg & withPaymentLag(QuantLib::Natural paymentLag)
CommodityIndexedAverageLeg & includeEndDate(bool flag=true)
CommodityIndexedAverageLeg & excludeStartDate(bool flag=true)
CommodityIndexedAverageLeg & withFutureMonthOffset(QuantLib::Natural futureMonthOffset)
CommodityIndexedAverageLeg & withGearings(QuantLib::Real gearing)
CommodityIndexedAverageLeg & paymentTiming(CommodityIndexedAverageCashFlow::PaymentTiming paymentTiming)
CommodityIndexedAverageLeg & withDeliveryDateRoll(QuantLib::Natural deliveryDateRoll)
CommodityIndexedAverageLeg & withQuantityFrequency(CommodityQuantityFrequency quantityFrequency)
CommodityIndexedAverageLeg & withPaymentConvention(QuantLib::BusinessDayConvention paymentConvention)
CommodityIndexedAverageLeg & withPaymentDates(const std::vector< QuantLib::Date > &paymentDates)
CommodityIndexedAverageLeg & withDailyExpiryOffset(QuantLib::Natural dailyExpiryOffset)
CommodityIndexedAverageLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedAverageLeg & withPaymentCalendar(const QuantLib::Calendar &paymentCalendar)
CommodityIndexedAverageLeg & withHoursPerDay(QuantLib::Natural hoursPerDay)
CommodityIndexedAverageLeg & useBusinessDays(bool flag=true)
CommodityIndexedAverageLeg & withFutureExpiryCalculator(const ext::shared_ptr< FutureExpiryCalculator > &calc=nullptr)
CommodityIndexedAverageLeg & withPricingCalendar(const QuantLib::Calendar &pricingCalendar)
CommodityIndexedAverageLeg & withSpreads(QuantLib::Real spread)
CommodityIndexedAverageLeg & unrealisedQuantity(bool flag=false)
CommodityIndexedAverageLeg & withOffPeakPowerData(const boost::optional< std::pair< QuantLib::Calendar, QuantLib::Real > > &offPeakPowerData)
CommodityIndexedAverageLeg & withFxIndex(const ext::shared_ptr< FxIndex > &fxIndex)
CommodityIndexedAverageLeg & payAtMaturity(bool flag=false)
CommodityIndexedLeg & excludeStartDate(bool flag=true)
CommodityIndexedLeg & withPricingLagCalendar(const QuantLib::Calendar &pricingLagCalendar)
CommodityIndexedLeg & paymentTiming(CommodityIndexedCashFlow::PaymentTiming paymentTiming)
CommodityIndexedLeg & payAtMaturity(bool flag=false)
CommodityIndexedLeg & withIsAveraging(const bool isAveraging)
CommodityIndexedLeg & includeEndDate(bool flag=true)
CommodityIndexedLeg & withFutureMonthOffset(QuantLib::Natural futureMonthOffset)
CommodityIndexedLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedLeg & withPaymentDates(const std::vector< QuantLib::Date > &paymentDates)
CommodityIndexedLeg & withFxIndex(const ext::shared_ptr< FxIndex > &fxIndex)
CommodityIndexedLeg & withFutureExpiryCalculator(const ext::shared_ptr< FutureExpiryCalculator > &calc=nullptr)
CommodityIndexedLeg & withPaymentLag(QuantLib::Natural paymentLag)
CommodityIndexedLeg & inArrears(bool flag=true)
CommodityIndexedLeg & withGearings(QuantLib::Real gearing)
CommodityIndexedLeg & withDailyExpiryOffset(QuantLib::Natural dailyExpiryOffset)
CommodityIndexedLeg & withPaymentCalendar(const QuantLib::Calendar &paymentCalendar)
CommodityIndexedLeg & withPricingDates(const std::vector< QuantLib::Date > &pricingDates)
CommodityIndexedLeg & withSpreads(QuantLib::Real spread)
CommodityIndexedLeg & useFuturePrice(bool flag=false)
CommodityIndexedLeg & withPricingCalendar(const QuantLib::Calendar &pricingCalendar)
CommodityIndexedLeg & withPaymentConvention(QuantLib::BusinessDayConvention paymentConvention)
CommodityIndexedLeg & withPricingLag(QuantLib::Natural pricingLag)
CommodityIndexedLeg & useFutureExpiryDate(bool flag=true)
QuantLib::Leg buildLeg(const ore::data::LegData &data, const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory, RequiredFixings &requiredFixings, const std::string &configuration, const QuantLib::Date &openEndDateReplacement=Null< Date >(), const bool useXbsCurves=false) const override
QuantLib::Leg buildLeg(const ore::data::LegData &data, const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory, RequiredFixings &requiredFixings, const std::string &configuration, const QuantLib::Date &openEndDateReplacement=Null< Date >(), const bool useXbsCurves=false) const override
Serializable object holding leg data.
void addFixingDate(const QuantLib::Date &fixingDate, const std::string &indexName, const QuantLib::Date &payDate=Date::maxDate(), const bool alwaysAddIfPaysOnSettlement=false, const bool mandatoryFixing=true)
Commodity fixed and floating leg builders.
leg data for commodity leg types
Base class for classes that perform date calculations for future contracts.
Logic for calculating required fixing dates on legs.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
PaymentLag parsePaymentLag(const string &s)
Convert text to PaymentLag.
Map text representations to QuantLib/QuantExt types.
leg data model and serialization
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
#define TLOG(text)
Logging Macro (Level = Data)
market data related utilties
CommodityQuantityFrequency
QuantLib::Integer daylightSavingCorrection(const std::string &location, const QuantLib::Date &start, const QuantLib::Date &end)
set< Date > pricingDates(const Date &s, const Date &e, const Calendar &pricingCalendar, bool excludeStart, bool includeEnd, bool useBusinessDays)
@ CalculationPeriodStartDate
@ CalculationPeriodEndDate
void applyIndexing(Leg &leg, const LegData &data, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, RequiredFixings &requiredFixings, const QuantLib::Date &openEndDateReplacement, const bool useXbsCurves)
void addToRequiredFixings(const QuantLib::Leg &leg, const QuantLib::ext::shared_ptr< FixingDateGetter > &fixingDateGetter)
vector< T > buildScheduledVector(const vector< T > &values, const vector< string > &dates, const Schedule &schedule, const bool checkAllValuesAppearInResult=false)
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
boost::variant< QuantLib::Period, QuantLib::Natural > PaymentLag
QuantLib::ext::shared_ptr< QuantExt::FxIndex > buildFxIndex(const string &fxIndex, const string &domestic, const string &foreign, const QuantLib::ext::shared_ptr< Market > &market, const string &configuration, bool useXbsCurves)
Schedule makeSchedule(const ScheduleDates &data)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.