24#ifndef quantext_commodity_average_basis_price_curve_hpp
25#define quantext_commodity_average_basis_price_curve_hpp
27#include <ql/math/comparison.hpp>
28#include <ql/patterns/lazyobject.hpp>
29#include <ql/quote.hpp>
30#include <ql/termstructures/interpolatedcurve.hpp>
31#include <ql/time/calendars/nullcalendar.hpp>
32#include <ql/utilities/dataformatters.hpp>
46template <
class Interpolator>
48 public QuantLib::LazyObject,
49 protected QuantLib::InterpolatedCurve<Interpolator> {
55 const std::map<QuantLib::Date, QuantLib::Handle<QuantLib::Quote>>& basisData,
56 const QuantLib::ext::shared_ptr<FutureExpiryCalculator>& basisFec,
57 const QuantLib::ext::shared_ptr<CommodityIndex>& index,
58 const QuantLib::ext::shared_ptr<FutureExpiryCalculator>& baseFec,
bool addBasis =
true,
59 bool priceAsHistFixing =
true,
const Interpolator& interpolator = Interpolator());
74 QuantLib::Date
maxDate()
const override;
75 QuantLib::Time
maxTime()
const override;
80 QuantLib::Time
minTime()
const override;
81 std::vector<QuantLib::Date>
pillarDates()
const override;
82 const QuantLib::Currency&
currency()
const override {
return baseIndex_->priceCurve()->currency(); }
87 const std::vector<QuantLib::Time>&
times()
const {
return this->times_; }
88 const std::vector<QuantLib::Real>&
prices()
const {
return this->data_; }
94 QuantLib::Real
priceImpl(QuantLib::Time t)
const override;
98 std::map<QuantLib::Date, QuantLib::Handle<QuantLib::Quote> >
basisData_;
118template <
class Interpolator>
120 const QuantLib::Date& referenceDate,
const std::map<QuantLib::Date, QuantLib::Handle<QuantLib::Quote> >& basisData,
121 const QuantLib::ext::shared_ptr<FutureExpiryCalculator>& basisFec,
const QuantLib::ext::shared_ptr<CommodityIndex>& index,
122 const QuantLib::ext::shared_ptr<FutureExpiryCalculator>& baseFec,
bool addBasis,
bool priceAsHistFixing,
123 const Interpolator& interpolator)
125 QuantLib::InterpolatedCurve<Interpolator>(interpolator), basisData_(basisData) {
127 "CommodityAverageBasisPriceCurve requires baseIndex with priceCurve");
128 using QuantLib::Date;
129 using QuantLib::Schedule;
130 using QuantLib::io::iso_date;
131 using QuantLib::io::ordinal;
140 if (it->first < referenceDate) {
145 dates_.push_back(it->first);
146 basisTimes_.push_back(timeFromReference(it->first));
151 registerWith(it->second);
163 Date start =
basisFec_->priorExpiry(
false, referenceDate);
171 QL_REQUIRE(start < end,
"Expected that the start date, " << io::iso_date(start)
172 <<
", would be strictly less than the end date, "
173 << io::iso_date(end) <<
".");
174 vector<Date> expiries{ start + 1 * Days };
175 vector<Time> scheduleTimes;
176 while (start < end) {
177 start =
basisFec_->nextExpiry(
true, start + 1 * Days);
178 expiries.push_back(start);
179 Time t = timeFromReference(start);
182 this->times_.push_back(t);
185 scheduleTimes.push_back(t);
187 QL_REQUIRE(start == end,
"Expected that the start date, " << io::iso_date(start) <<
", to equal the end date, "
189 <<
", after creating the sequence of expiry dates.");
192 sort(this->times_.begin(), this->times_.end());
194 auto it = unique(this->times_.begin(), this->times_.end(), [](
double s,
double t) { return close(s, t); });
195 QL_REQUIRE(it == this->times_.end(),
"Unexpected duplicate time, " << *it <<
", in the times vector.");
196 this->data_.resize(this->times_.size());
203 QL_REQUIRE(
baseLeg_.size() == scheduleTimes.size(),
"Unexpected number of averaging cashflows in the leg: "
204 <<
"got " <<
baseLeg_.size() <<
" but expected "
205 << scheduleTimes.size());
208 for (Size i = 0; i < this->times_.size(); i++) {
209 for (Size j = 0; j < scheduleTimes.size(); j++) {
211 if (this->times_[i] < scheduleTimes[j] || close(this->times_[i], scheduleTimes[j])) {
213 "Should not already have a mapping for the " << ordinal(i) <<
" time.");
218 if (j == scheduleTimes.size()) {
219 QL_FAIL(
"Could not map the " << ordinal(i) <<
" time, " << this->times_[i] <<
", to a cashflow.");
225 QuantLib::InterpolatedCurve<Interpolator>::setupInterpolation();
229 QuantLib::LazyObject::update();
236 for (
const auto& kv : basisData_) {
237 basisValues_[basisIdx] = addBasis_ ? kv.second->value() : -kv.second->value();
240 basisInterpolation_.update();
243 for (Size i = 0; i < this->times_.size(); i++) {
245 Real baseValue = baseLeg_[legIndexMap_.at(i)]->amount();
249 if (this->times_[i] < basisTimes_.front()) {
250 basis = basisValues_.front();
251 }
else if (this->times_[i] > basisTimes_.back()) {
252 basis = basisValues_.back();
254 basis = basisInterpolation_(this->times_[i],
true);
258 this->data_[i] = baseValue + basis;
260 this->interpolation_.update();
264 return dates_.back();
268 return this->times_.back();
272 return this->times_.front();
275template <
class Interpolator>
280template <
class Interpolator>
283 return this->interpolation_(t,
true);
Commodity average basis price curve.
QuantLib::Time minTime() const override
The minimum time for which the curve can return values.
void performCalculations() const override
CommodityAverageBasisPriceCurve(const QuantLib::Date &referenceDate, const std::map< QuantLib::Date, QuantLib::Handle< QuantLib::Quote > > &basisData, const QuantLib::ext::shared_ptr< FutureExpiryCalculator > &basisFec, const QuantLib::ext::shared_ptr< CommodityIndex > &index, const QuantLib::ext::shared_ptr< FutureExpiryCalculator > &baseFec, bool addBasis=true, bool priceAsHistFixing=true, const Interpolator &interpolator=Interpolator())
Curve constructed from dates and quotes.
const QuantLib::Currency & currency() const override
The currency in which prices are expressed.
std::vector< Time > basisTimes_
std::vector< QuantLib::Date > dates_
std::map< QuantLib::Size, QuantLib::Size > legIndexMap_
std::vector< Real > basisValues_
const std::vector< QuantLib::Time > & times() const
std::map< QuantLib::Date, QuantLib::Handle< QuantLib::Quote > > basisData_
QuantLib::Leg baseLeg_
The averaging cashflows will give the base curve prices.
QuantLib::Date maxDate() const override
const std::vector< QuantLib::Real > & prices() const
std::vector< QuantLib::Date > pillarDates() const override
The pillar dates for the PriceTermStructure.
Interpolation basisInterpolation_
QuantLib::Real priceImpl(QuantLib::Time t) const override
Price calculation.
QuantLib::Time maxTime() const override
QuantLib::ext::shared_ptr< FutureExpiryCalculator > baseFec_
QuantLib::ext::shared_ptr< FutureExpiryCalculator > basisFec_
QuantLib::ext::shared_ptr< CommodityIndex > baseIndex_
Helper class building a sequence of commodity indexed average cashflows.
CommodityIndexedAverageLeg & useFuturePrice(bool flag=false)
CommodityIndexedAverageLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedAverageLeg & withFutureExpiryCalculator(const ext::shared_ptr< FutureExpiryCalculator > &calc=nullptr)
An interface for a commodity price curve created from a base price curve and a collection of basis qu...
Cash flow dependent on the average commodity spot price or future's settlement price over a period....
Base class for classes that perform date calculations for future contracts.
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)