Implement the build method.
124 {
125
126 DLOG(
"CommoditySpreadOption::build() called for trade " <<
id());
127
128
132
134
139
140 QL_REQUIRE(legData_.size() == 2, "Only two legs supported");
141 QL_REQUIRE(legData_[0].currency() == legData_[1].currency(), "Both legs must have same currency");
142 QL_REQUIRE(legData_[0].isPayer() != legData_[1].isPayer(), "Need one payer and one receiver leg");
143
144 if (!optionData_.style().empty()) {
146 QL_REQUIRE(exerciseType == QuantLib::Exercise::Type::European, "Only European spread option supported");
147 }
148
151 Size payerLegId = legData_[0].isPayer() ? 0 : 1;
152
153
154 std::vector<QuantLib::ext::shared_ptr<QuantExt::FxIndex>> fxIndexes(2, nullptr);
157
158
159 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(tradeType_);
160 auto engineBuilder = QuantLib::ext::dynamic_pointer_cast<CommoditySpreadOptionEngineBuilder>(builder);
161
162 auto config = builder->configuration(MarketContext::pricing);
163
164
165 QL_REQUIRE(optionData_.exerciseDates().size() == 0,
166 "Only European spread option supported, expiry date is end_date of the period");
167
168
169
170 for (Size i = 0; i < legData_.size();
171 ++i) {
173
174
175
176 auto commLegData = (QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegData>(legData_[i].concreteLegData()));
177 QL_REQUIRE(commLegData, "CommoditySpreadOption leg data should be of type CommodityFloating");
178
179 auto legBuilder = engineFactory->legBuilder(legData_[i].legType());
180 auto cflb = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegBuilder>(legBuilder);
181
182 QL_REQUIRE(cflb, "CommoditySpreadOption: Expected a CommodityFloatingLegBuilder for leg "
183 << i << " but got " << legData_[i].legType());
184 Leg leg = cflb->buildLeg(legData_[i], engineFactory, requiredFixings_, config);
185
186
187 QL_REQUIRE(!leg.empty(), "CommoditySpreadOption: Leg " << i << " has no coupons");
188 auto index = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(leg.front())->index();
189
190
191 auto underlyingCcy = index->priceCurve()->currency();
192 auto tmpFx = commLegData->fxIndex();
193 if (tmpFx.empty()) {
194 QL_REQUIRE(underlyingCcy.code() == npvCurrency_,
195 "CommoditySpreadOption, inconsistent currencies: Settlement currency is "
196 << npvCurrency_ << ", leg " << i + 1 << " currency " << legData_[i].currency()
197 << ", underlying currency " << underlyingCcy << ", no FxIndex provided");
198 } else {
199 QL_REQUIRE(underlyingCcy.code() != npvCurrency_,
200 "CommoditySpreadOption, inconsistent currencies: Settlement currency is "
201 << npvCurrency_ << ", leg " << i + 1 << " currency " << legData_[i].currency()
202 << ", underlying currency " << underlyingCcy << ", FxIndex " << tmpFx << "provided");
204 auto foreign = underlyingCcy.code();
205 fxIndexes[i] =
buildFxIndex(tmpFx, domestic, foreign, engineFactory->market(),
206 engineFactory->configuration(MarketContext::pricing));
207
208 if (commLegData->isAveraged()) {
209 for (auto cf : leg) {
211 if (!fxIndexes[i]->fixingCalendar().isBusinessDay(
212 fixingDate)) {
213
214
215 Date adjustedFixingDate = fxIndexes[i]->fixingCalendar().adjust(fixingDate, Preceding);
217 } else {
219 }
220 }
221 }
222 }
223 legs_.push_back(leg);
225 }
226
227 QL_REQUIRE(legs_[0].
size() == legs_[1].
size(),
228 "CommoditySpreadOption: the two legs must contain the same number of options.");
229
230 QL_REQUIRE(legs_[0].
size() > 0,
"CommoditySpreadOption: need at least one option, please check the trade xml");
231
233 Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
234
235 QuantLib::ext::shared_ptr<QuantLib::Instrument> firstInstrument;
236 double firstMultiplier = 0.0;
237 vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
238 vector<Real> additionalMultipliers;
239
240 vector<Date> expiryDates;
241 for (
size_t i = 0; i <
legs_[0].size(); ++i) {
242 auto longFlow = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(legs_[1 - payerLegId][i]);
243 auto shortFlow = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(legs_[payerLegId][i]);
244 expiryDates.push_back(std::max(longFlow->lastPricingDate(), shortFlow->lastPricingDate()));
245 }
246
248
249 for (
size_t i = 0; i <
legs_[0].size(); ++i) {
250 auto longFlow = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(legs_[1 - payerLegId][i]);
251 auto shortFlow = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityCashFlow>(legs_[payerLegId][i]);
252
253 QuantLib::Real quantity = longFlow->periodQuantity();
254
255 QL_REQUIRE(quantity == shortFlow->periodQuantity(), "all cashflows must refer to the same quantity");
256
257 QuantLib::Date expiryDate = expiryDates[i];
258
259 QuantLib::Date paymentDate = longFlow->date();
260
261 QL_REQUIRE(paymentDate == shortFlow->date(),
262 "all cashflows must refer to the same paymentDate, its used as the settlementDate of the option");
263
264 paymentDateAdjuster->updatePaymentDate(expiryDate, paymentDate);
265
266 QL_REQUIRE(paymentDate >= expiryDate, "Payment date must be greater than or equal to expiry date.");
267
268 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
269
270
271
273
274
275 QuantLib::ext::shared_ptr<QuantExt::CommoditySpreadOption> spreadOption =
276 QuantLib::ext::make_shared<QuantExt::CommoditySpreadOption>(longFlow, shortFlow, exercise, quantity, strike_,
277 optionType, paymentDate, fxIndexes[1 - payerLegId],
278 fxIndexes[1 - payerLegId]);
279
280
281 QuantLib::ext::shared_ptr<PricingEngine> commoditySpreadOptionEngine =
282 engineBuilder->engine(ccy, longFlow->index(), shortFlow->index(), id());
283 spreadOption->setPricingEngine(commoditySpreadOptionEngine);
285 if (i > 0) {
286 additionalInstruments.push_back(spreadOption);
287 additionalMultipliers.push_back(bsInd);
288 } else {
289 firstInstrument = spreadOption;
290 firstMultiplier = bsInd;
291 }
292 }
293
294
295 auto configuration = engineBuilder->configuration(MarketContext::pricing);
296 maturity_ = std::max(maturity_,
addPremiums(additionalInstruments, additionalMultipliers, firstMultiplier,
297 optionData_.premiumData(), -bsInd, ccy, engineFactory, configuration));
298
299 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(firstInstrument, firstMultiplier, additionalInstruments,
300 additionalMultipliers);
301 if (!optionData_.premiumData().premiumData().empty()) {
302 auto premium = optionData_.premiumData().premiumData().front();
306 }
307}
const std::vector< ore::data::LegData > & legData() const
const ore::data::OptionData & optionData() const
QuantLib::Real strike() const
void addFixingDate(const QuantLib::Date &fixingDate, const std::string &indexName, const QuantLib::Date &payDate=Date::maxDate(), const bool alwaysAddIfPaysOnSettlement=false, const bool mandatoryFixing=true)
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
Date addPremiums(std::vector< QuantLib::ext::shared_ptr< Instrument > > &instruments, std::vector< Real > &multipliers, const Real tradeMultiplier, const PremiumData &premiumData, const Real premiumMultiplier, const Currency &tradeCurrency, const QuantLib::ext::shared_ptr< EngineFactory > &factory, const string &configuration)
void setSensitivityTemplate(const EngineBuilder &builder)
RequiredFixings requiredFixings_
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
void reset()
Reset trade, clear all base class data. This does not reset accumulated timings for this trade.
std::map< std::string, boost::any > additionalData_
Exercise::Type parseExerciseType(const std::string &s)
Convert text to QuantLib::Exercise::Type.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
#define DLOG(text)
Logging Macro (Level = Debug)
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
Size size(const ValueType &v)
QuantLib::ext::shared_ptr< OptionPaymentDateAdjuster > makeOptionPaymentDateAdjuster(CommoditySpreadOptionData &optionData, const std::vector< Date > &expiryDates)
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)