19#include <ql/utilities/vectors.hpp>
28 const ext::shared_ptr<CommodityIndex>& index, Real spread,
29 Real gearing,
bool useFuturePrice,
const Date& contractDate,
30 const ext::shared_ptr<FutureExpiryCalculator>& calc,
31 QuantLib::Natural dailyExpiryOffset,
const ext::shared_ptr<FxIndex>& fxIndex)
32 : CommodityCashFlow(quantity, spread, gearing, useFuturePrice, index, fxIndex), pricingDate_(pricingDate),
33 paymentDate_(paymentDate), futureMonthOffset_(0), periodQuantity_(quantity), dailyExpiryOffset_(dailyExpiryOffset),
36 QL_REQUIRE(paymentDate != Date(),
"CommodityIndexedCashFlow: payment date is null");
37 init(calc, contractDate);
40CommodityIndexedCashFlow::CommodityIndexedCashFlow(
41 Real quantity,
const Date& startDate,
const Date& endDate,
const ext::shared_ptr<CommodityIndex>& index,
42 Natural paymentLag,
const Calendar& paymentCalendar, BusinessDayConvention paymentConvention, Natural pricingLag,
43 const Calendar& pricingLagCalendar, Real spread, Real gearing, PaymentTiming paymentTiming,
bool isInArrears,
44 bool useFuturePrice,
bool useFutureExpiryDate, Natural futureMonthOffset,
45 const ext::shared_ptr<FutureExpiryCalculator>& calc,
const QuantLib::Date& paymentDateOverride,
46 const QuantLib::Date& pricingDateOverride, QuantLib::Natural dailyExpiryOffset,
47 const ext::shared_ptr<FxIndex>& fxIndex,
const bool isAveragingWithBalanceMonth,
48 const QuantLib::Calendar& pricingCalendar,
bool includeEndDate,
bool excludeStartDate)
49 : CommodityCashFlow(quantity, spread, gearing, useFuturePrice, index, fxIndex), pricingDate_(pricingDateOverride),
50 paymentDate_(paymentDateOverride), useFutureExpiryDate_(useFutureExpiryDate),
51 futureMonthOffset_(futureMonthOffset), periodQuantity_(quantity), dailyExpiryOffset_(dailyExpiryOffset),
52 isAveraging_(isAveragingWithBalanceMonth) {
55 if (pricingDate_ == Date()) {
56 pricingDate_ = isInArrears ? endDate : startDate;
57 if (!useFuturePrice_ || !useFutureExpiryDate_) {
59 pricingDate_ = pricingLagCalendar.advance(pricingDate_, -
static_cast<Integer
>(pricingLag), Days, Preceding);
62 QL_REQUIRE(calc,
"CommodityIndexedCashFlow needs a valid future "
63 <<
"expiry calculator when using first future");
64 Date expiry = calc->expiryDate(pricingDate_, futureMonthOffset_);
65 if (dailyExpiryOffset_ != Null<Natural>()) {
66 expiry = index_->fixingCalendar().advance(expiry, dailyExpiryOffset_ * Days);
68 pricingDate_ = expiry;
74 Date ref = isInArrears ? endDate : startDate;
76 init(calc, ref, paymentTiming, startDate, endDate, paymentLag, paymentConvention, paymentCalendar, pricingCalendar,
77 includeEndDate, excludeStartDate);
80void CommodityIndexedCashFlow::performCalculations()
const {
81 Date today = Settings::instance().evaluationDate();
83 if (isAveragingFrontMonthCashflow(today)) {
84 for (
const auto& pd : spotAveragingPricingDates_) {
85 double fxRate = (fxIndex_) ? this->fxIndex()->fixing(pricingDate_) : 1.0;
87 price_ += fxRate * spotIndex_->fixing(pd);
89 price_ += fxRate * index_->fixing(pricingDate_);
92 price_ /=
static_cast<double>(spotAveragingPricingDates_.size());
94 double fxRate = (fxIndex_) ? this->fxIndex()->fixing(pricingDate_) : 1.0;
95 price_ = fxRate * index_->fixing(pricingDate_);
100Real CommodityIndexedCashFlow::amount()
const {
105Real CommodityIndexedCashFlow::fixing()
const {
110bool CommodityIndexedCashFlow::isAveragingFrontMonthCashflow(
const QuantLib::Date& asof)
const {
111 return (isAveraging_ && useFuturePrice_ && !spotAveragingPricingDates_.empty() &&
112 *spotAveragingPricingDates_.begin() <= asof && spotIndex_ !=
nullptr);
115void CommodityIndexedCashFlow::accept(AcyclicVisitor& v) {
116 if (Visitor<CommodityIndexedCashFlow>* v1 =
dynamic_cast<Visitor<CommodityIndexedCashFlow>*
>(&v))
119 CommodityCashFlow::accept(v);
122void CommodityIndexedCashFlow::setPeriodQuantity(Real periodQuantity) { periodQuantity_ = periodQuantity; }
124void CommodityIndexedCashFlow::init(
const ext::shared_ptr<FutureExpiryCalculator>& calc,
const Date& contractDate,
125 const PaymentTiming paymentTiming,
const Date& startDate,
const Date& endDate,
126 const Natural paymentLag,
const BusinessDayConvention paymentConvention,
127 const Calendar& paymentCalendar,
128 const QuantLib::Calendar& pricingCalendar,
129 bool includeEndDate,
bool excludeStartDate) {
131 pricingDate_ = index_->fixingCalendar().adjust(pricingDate_, Preceding);
136 if (useFuturePrice_) {
137 QL_REQUIRE(calc,
"CommodityIndexedCashFlow needs a valid future expiry calculator when using "
138 <<
"the future settlement price as reference price");
139 expiry = calc->expiryDate(contractDate, futureMonthOffset_);
140 if (dailyExpiryOffset_ != Null<Natural>()) {
141 expiry = index_->fixingCalendar().advance(expiry, dailyExpiryOffset_ * Days);
143 index_ = index_->clone(expiry);
144 isAveraging_ = isAveraging_ && startDate != Date() && endDate != Date();
147 Calendar cal = pricingCalendar;
148 if (pricingCalendar == Calendar()) {
149 cal = index_->fixingCalendar();
153 spotIndex_ = ext::make_shared<CommoditySpotIndex>(index_->underlyingName(), cal,
154 index_->priceCurve());
156 registerWith(spotIndex_);
157 spotAveragingPricingDates_ =
158 pricingDates(startDate, endDate, cal, excludeStartDate, includeEndDate);
159 for (
const auto& d : spotAveragingPricingDates_) {
160 indices_.push_back({d, spotIndex_});
167 if (paymentDate_ == Date()) {
168 if (paymentTiming == PaymentTiming::InAdvance) {
169 QL_REQUIRE(startDate != Date(),
"CommodityIndexedCashFlow: startDate is null, can not derive paymentDate.");
170 paymentDate_ = startDate;
171 }
else if (paymentTiming == PaymentTiming::InArrears) {
172 QL_REQUIRE(endDate != Date(),
"CommodityIndexedCashFlow: endDate is null, can not derive paymentDate.");
173 paymentDate_ = endDate;
174 }
else if (paymentTiming == PaymentTiming::RelativeToExpiry) {
177 "CommodityIndexedCashFlow: payment relative to expiry date only possibly when future price is used.");
178 paymentDate_ = expiry;
180 paymentDate_ = paymentCalendar.advance(paymentDate_, paymentLag, Days, paymentConvention);
184 pricingDate_ = index_->fixingCalendar().adjust(std::min(paymentDate_, pricingDate_), Preceding);
186 indices_.push_back({pricingDate_, index_});
188 registerWith(index_);
191CommodityIndexedLeg::CommodityIndexedLeg(
const Schedule& schedule,
const ext::shared_ptr<CommodityIndex>& index)
192 : schedule_(schedule), index_(index), paymentLag_(0), paymentCalendar_(NullCalendar()),
193 paymentConvention_(Unadjusted), pricingLag_(0), pricingLagCalendar_(NullCalendar()),
195 useFutureExpiryDate_(true), futureMonthOffset_(0), payAtMaturity_(false), dailyExpiryOffset_(Null<Natural>()),
196 isAveraging_(false), pricingCalendar_(NullCalendar()), includeEndDate_(true), excludeStartDate_(true) {}
329CommodityIndexedLeg::operator Leg()
const {
332 Size numberCashflows = schedule_.size() - 1;
335 QL_REQUIRE(!quantities_.empty(),
"No quantities given");
336 QL_REQUIRE(quantities_.size() <= numberCashflows,
337 "Too many quantities (" << quantities_.size() <<
"), only " << numberCashflows <<
" required");
338 if (useFuturePrice_) {
339 QL_REQUIRE(calc_,
"CommodityIndexedCashFlow needs a valid future expiry calculator when using first future");
341 if (!pricingDates_.empty()) {
342 QL_REQUIRE(pricingDates_.size() == numberCashflows,
"Expected the number of explicit pricing dates ("
343 << pricingDates_.size()
344 <<
") to equal the number of calculation periods ("
345 << numberCashflows <<
")");
347 if (!paymentDates_.empty()) {
348 QL_REQUIRE(paymentDates_.size() == numberCashflows,
"Expected the number of explicit payment dates ("
349 << paymentDates_.size()
350 <<
") to equal the number of calculation periods ("
351 << numberCashflows <<
")");
356 if (payAtMaturity_) {
357 paymentDate = paymentCalendar_.advance(schedule_.dates().back(), paymentLag_ * Days, paymentConvention_);
362 leg.reserve(numberCashflows);
363 for (Size i = 0; i < numberCashflows; ++i) {
365 Date start = schedule_.date(i);
366 Date end = schedule_.date(i + 1);
367 Real quantity = detail::get(quantities_, i, 1.0);
368 Real spread = detail::get(spreads_, i, 0.0);
369 Real gearing = detail::get(gearings_, i, 1.0);
370 Date pricingDate = detail::get(pricingDates_, i, Date());
371 bool excludeStart = i == 0 ? false : excludeStartDate_;
372 bool includeEnd = i == numberCashflows - 1 ? true : includeEndDate_;
375 if (!paymentDates_.empty()) {
376 paymentDate = paymentDates_[i];
379 leg.push_back(ext::make_shared<CommodityIndexedCashFlow>(
380 quantity, start, end, index_, paymentLag_, paymentCalendar_, paymentConvention_, pricingLag_,
381 pricingLagCalendar_, spread, gearing, paymentTiming_, inArrears_, useFuturePrice_, useFutureExpiryDate_,
382 futureMonthOffset_, calc_, paymentDate, pricingDate, dailyExpiryOffset_, fxIndex_, isAveraging_,
383 pricingCalendar_, includeEnd, excludeStart));
Cash flow dependent on a single commodity spot price or futures settlement price on a given pricing d...
CommodityIndexedCashFlow(QuantLib::Real quantity, const QuantLib::Date &pricingDate, const QuantLib::Date &paymentDate, const ext::shared_ptr< CommodityIndex > &index, QuantLib::Real spread=0.0, QuantLib::Real gearing=1.0, bool useFuturePrice=false, const Date &contractDate=Date(), const ext::shared_ptr< FutureExpiryCalculator > &calc=nullptr, QuantLib::Natural dailyExpiryOffset=QuantLib::Null< QuantLib::Natural >(), const ext::shared_ptr< FxIndex > &fxIndex=nullptr)
Constructor taking an explicit pricingDate and paymentDate.
Helper class building a sequence of commodity indexed cashflows.
QuantLib::Calendar pricingLagCalendar_
CommodityIndexedLeg & excludeStartDate(bool flag=true)
CommodityIndexedLeg & withPricingLagCalendar(const QuantLib::Calendar &pricingLagCalendar)
QuantLib::Calendar pricingCalendar_
CommodityIndexedLeg & paymentTiming(CommodityIndexedCashFlow::PaymentTiming paymentTiming)
QuantLib::BusinessDayConvention paymentConvention_
CommodityIndexedLeg & payAtMaturity(bool flag=false)
CommodityIndexedLeg & withIsAveraging(const bool isAveraging)
CommodityIndexedCashFlow::PaymentTiming paymentTiming_
CommodityIndexedLeg & includeEndDate(bool flag=true)
ext::shared_ptr< FutureExpiryCalculator > calc_
std::vector< QuantLib::Date > paymentDates_
CommodityIndexedLeg & withFutureMonthOffset(QuantLib::Natural futureMonthOffset)
CommodityIndexedLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedLeg & withPaymentDates(const std::vector< QuantLib::Date > &paymentDates)
QuantLib::Natural futureMonthOffset_
bool useFutureExpiryDate_
ext::shared_ptr< FxIndex > fxIndex_
CommodityIndexedLeg & withFxIndex(const ext::shared_ptr< FxIndex > &fxIndex)
QuantLib::Natural dailyExpiryOffset_
CommodityIndexedLeg & withFutureExpiryCalculator(const ext::shared_ptr< FutureExpiryCalculator > &calc=nullptr)
CommodityIndexedLeg & withPaymentLag(QuantLib::Natural paymentLag)
QuantLib::Natural paymentLag_
CommodityIndexedLeg & inArrears(bool flag=true)
CommodityIndexedLeg & withGearings(QuantLib::Real gearing)
CommodityIndexedLeg & withDailyExpiryOffset(QuantLib::Natural dailyExpiryOffset)
std::vector< QuantLib::Date > pricingDates_
CommodityIndexedLeg & withPaymentCalendar(const QuantLib::Calendar &paymentCalendar)
CommodityIndexedLeg & withPricingDates(const std::vector< QuantLib::Date > &pricingDates)
std::vector< QuantLib::Real > quantities_
QuantLib::Calendar paymentCalendar_
CommodityIndexedLeg & withSpreads(QuantLib::Real spread)
CommodityIndexedLeg & useFuturePrice(bool flag=false)
CommodityIndexedLeg & withPricingCalendar(const QuantLib::Calendar &pricingCalendar)
std::vector< QuantLib::Real > spreads_
CommodityIndexedLeg & withPaymentConvention(QuantLib::BusinessDayConvention paymentConvention)
std::vector< QuantLib::Real > gearings_
CommodityIndexedLeg & withPricingLag(QuantLib::Natural pricingLag)
QuantLib::Natural pricingLag_
CommodityIndexedLeg & useFutureExpiryDate(bool flag=true)
Cash flow dependent on a single commodity spot price or future's settlement price.
set< Date > pricingDates(const Date &s, const Date &e, const Calendar &pricingCalendar, bool excludeStart, bool includeEnd, bool useBusinessDays)