45vector<string> strPositions(
const vector<Position::Type>& positions) {
46 vector<string> res(positions.size());
47 transform(positions.begin(), positions.end(), res.begin(), [](
const Position::Type& pt) { return to_string(pt); });
51struct TempOptionData {
53 Position::Type position;
64 const vector<Position::Type>& callPositions,
const vector<Real>& callStrikes,
65 const vector<Position::Type>& putPositions,
const vector<Real>& putStrikes,
66 Real premium,
const string& premiumCurrency,
const Date& premiumPayDate,
67 const string& style,
const string& settlement,
69 const string& fxIndex,
const bool isDigital, Real payoffPerUnit)
70 :
Trade(
"CommodityOptionStrip", envelope), legData_(legData), callPositions_(callPositions),
71 callStrikes_(callStrikes), putPositions_(putPositions), putStrikes_(putStrikes),
73 settlement_(settlement),
74 callBarrierData_(callBarrierData), putBarrierData_(putBarrierData), fxIndex_(fxIndex), isDigital_(isDigital),
75 unaryPayoff_(payoffPerUnit) {
76 if (!QuantLib::close_enough(premium, 0.0)) {
77 QL_REQUIRE(premiumPayDate != Date(),
"The premium is non-zero so its payment date needs to be provided");
78 QL_REQUIRE(!premiumCurrency.empty(),
"The premium is non-zero so its currency needs to be provided");
79 premiumData_ =
PremiumData(premium, premiumCurrency, premiumPayDate);
88 DLOG(
"CommodityOptionStrip::build() called for trade " <<
id());
93 additionalData_[
"isdaSubProduct"] = std::string(
"Price Return Basic Performance");
101 commLegData_ = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegData>(conLegData);
102 QL_REQUIRE(
commLegData_,
"CommodityOptionStrip leg data should be of type CommodityFloating");
107 auto cflb = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegBuilder>(legBuilder);
108 QL_REQUIRE(cflb,
"Expected a CommodityFloatingLegBuilder for leg type " <<
legData_.
legType());
121 if (
commLegData_->isAveraged() && !cflb->allAveraging()) {
128 legs_.push_back(leg);
133std::map<ore::data::AssetClass, std::set<std::string>>
135 std::map<ore::data::AssetClass, std::set<std::string>> result;
138 for (
auto ind : indices) {
139 QuantLib::ext::shared_ptr<Index> index =
parseIndex(ind);
141 if (
auto ci = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityIndex>(index)) {
153 QL_REQUIRE(stripNode,
"No CommodityOptionStripData Node");
188 QL_REQUIRE(n,
"A strip of commodity digital options requires PayoffPerUnit node");
243 WLOG(
"Style should be European when the commodity option strip is a strip of APOs. Ignoring style "
244 <<
style_ <<
" and proceeding as if European.");
249 WLOG(
"Settlement should be Cash when the commodity option strip is a strip of APOs. Ignoring settlement "
255 vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
256 vector<Real> additionalMultipliers;
258 for (Size i = 0; i < leg.size(); i++) {
259 auto cf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedAverageCashFlow>(leg[i]);
260 QL_REQUIRE(cf,
"Expected a CommodityIndexedAverageCashFlow while building APO");
263 vector<TempOptionData> tempData;
264 Date exerciseDate = cf->indices().rbegin()->first;
265 vector<string> strExerciseDate = {
to_string(exerciseDate)};
267 string stemId =
id() +
"_" + strExerciseDate[0] +
"_";
271 string id = stemId +
"call";
272 tempData.push_back({
"Call", position, strike,
id});
277 string id = stemId +
"put";
278 tempData.push_back({
"Put", position, strike,
id});
284 Date start = cf->indices().begin()->first;
288 for (
const auto& tempDatum : tempData) {
289 QuantLib::ext::shared_ptr<Trade> commOption;
290 OptionData optionData(
to_string(tempDatum.position), tempDatum.type,
"European",
true, strExerciseDate);
292 commOption = QuantLib::ext::make_shared<CommodityAveragePriceOption>(
296 to_string(cf->date()), cf->gearing(), cf->spread(), cf->quantityFrequency(),
301 auto undCcy = cf->index()->priceCurve()->currency();
303 "Strips of commodity digital options do not support intra-currency trades yet.");
304 commOption = QuantLib::ext::make_shared<CommodityDigitalAveragePriceOption>(
309 cf->gearing(), cf->spread(), cf->quantityFrequency(),
314 commOption->id() = tempDatum.id;
315 commOption->build(engineFactory);
316 QuantLib::ext::shared_ptr<InstrumentWrapper> instWrapper = commOption->instrument();
318 additionalInstruments.push_back(instWrapper->qlInstrument());
319 additionalMultipliers.push_back(instWrapper->multiplier());
326 auto underlyingCcy = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedAverageCashFlow>(leg[0])->index()->priceCurve()->currency();
332 QL_REQUIRE(additionalInstruments.size() > 0,
"Expected commodity APO strip to have at least one instrument");
335 auto qlInst = additionalInstruments.back();
336 auto qlInstMult = additionalMultipliers.back();
337 additionalInstruments.pop_back();
338 additionalMultipliers.pop_back();
348 QuantLib::ext::make_shared<VanillaInstrument>(qlInst, qlInstMult, additionalInstruments, additionalMultipliers);
361 bool automaticExercise =
settlement ==
"Cash";
364 vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
365 vector<Real> additionalMultipliers;
367 for (Size i = 0; i < leg.size(); i++) {
369 auto cf = QuantLib::ext::dynamic_pointer_cast<CommodityIndexedCashFlow>(leg[i]);
370 QL_REQUIRE(cf,
"Expected a CommodityIndexedCashFlow while building standard option");
373 Date exerciseDate = cf->pricingDate();
374 vector<string> strExerciseDate = {
to_string(exerciseDate)};
377 boost::optional<OptionPaymentData> paymentData = boost::none;
380 Date paymentDate = cf->date();
381 vector<string> strPaymentDate = {
to_string(paymentDate)};
394 vector<TempOptionData> tempData;
395 string stemId =
id() +
"_" + strExerciseDate[0] +
"_";
399 string id = stemId +
"call";
400 tempData.push_back({
"Call", position, strike,
id});
405 string id = stemId +
"put";
406 tempData.push_back({
"Put", position, strike,
id});
410 for (
const auto& tempDatum : tempData) {
413 QL_REQUIRE(cf->gearing() > 0.0,
"Gearing (" << cf->gearing() <<
") should be positive.");
414 QL_REQUIRE(cf->spread() < tempDatum.strike || QuantLib::close_enough(cf->spread(), tempDatum.strike),
415 "Spread (" << cf->spread() <<
") should be less than strike (" << tempDatum.strike <<
").");
418 Real effectiveQuantity = cf->gearing() * cf->periodQuantity();
421 settlement,
"",
PremiumData(), {}, {},
"",
"",
"", {}, {},
"",
"",
"",
"",
"",
422 automaticExercise, boost::none, paymentData);
425 QuantLib::ext::shared_ptr<Trade> commOption;
427 commOption = QuantLib::ext::make_shared<CommodityOption>(
429 effectiveStrike, cf->useFuturePrice(), cf->index()->expiryDate());
431 auto undCcy = cf->index()->priceCurve()->currency();
432 QL_REQUIRE(undCcy.code() ==
legData_.
currency(),
"Strips of commodity digital options do not support intra-currency trades yet.");
433 commOption = QuantLib::ext::make_shared<CommodityDigitalOption>(
435 cf->useFuturePrice(), cf->index()->expiryDate());
437 commOption->id() = tempDatum.id;
438 commOption->build(engineFactory);
439 QuantLib::ext::shared_ptr<InstrumentWrapper> instWrapper = commOption->instrument();
441 additionalInstruments.push_back(instWrapper->qlInstrument());
442 additionalMultipliers.push_back(instWrapper->multiplier());
450 QL_REQUIRE(additionalInstruments.size() > 0,
"Expected commodity option strip to have at least one instrument");
453 auto qlInst = additionalInstruments.back();
454 auto qlInstMult = additionalMultipliers.back();
455 additionalInstruments.pop_back();
456 additionalMultipliers.pop_back();
462 DLOG(
"Option premium added for commodity option strip " <<
id());
466 QuantLib::ext::make_shared<VanillaInstrument>(qlInst, qlInstMult, additionalInstruments, additionalMultipliers);
471 QL_REQUIRE(numberPeriods > 0,
"Expected at least one period in the commodity option strip");
477 <<
"call strikes (" <<
callStrikes_.size() <<
") should be 1 or equal to "
478 <<
"the number of periods in the strip (" << numberPeriods <<
")");
480 "The number of position "
481 <<
"flags provided with the call strikes (" <<
callPositions_.size()
482 <<
") should be 1 or equal to "
483 <<
"the number of periods in the strip (" << numberPeriods <<
")");
489 <<
"put strikes (" <<
putStrikes_.size() <<
") should be 1 or equal to "
490 <<
"the number of periods in the strip (" << numberPeriods <<
")");
492 "The number of position "
493 <<
"flags provided with the put strikes (" <<
putPositions_.size()
494 <<
") should be 1 or equal to "
495 <<
"the number of periods in the strip (" << numberPeriods <<
")");
Engine builder for commodity average price options.
Serializable obejct holding barrier data.
virtual void fromXML(ore::data::XMLNode *node) override
virtual ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
const std::string & settlement() const
std::vector< QuantLib::Real > putStrikes_
ore::data::LegData legData_
virtual void fromXML(ore::data::XMLNode *node) override
void buildAPOs(const QuantLib::Leg &leg, const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory)
Build an average price option strip.
std::map< ore::data::AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
Add underlying Commodity names.
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory) override
Implement the build method.
QuantLib::ext::shared_ptr< CommodityFloatingLegData > commLegData_
std::vector< QuantLib::Position::Type > callPositions_
const bool isDigital() const
virtual ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
std::vector< QuantLib::Position::Type > putPositions_
std::vector< QuantLib::Real > callStrikes_
const Real payoffPerUnit() const
const std::string & style() const
void buildStandardOptions(const QuantLib::Leg &leg, const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory)
Build a standard option strip.
BarrierData callBarrierData_
BarrierData putBarrierData_
void check(QuantLib::Size numberPeriods) const
Perform checks before building.
Serializable object holding generic trade data, reporting dimensions.
Serializable object holding leg data.
const string & paymentConvention() const
const string & currency() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
const string & legType() const
const std::string & paymentCalendar() const
const std::set< std::string > & indices() const
const string & paymentLag() const
QuantLib::ext::shared_ptr< LegAdditionalData > concreteLegData() const
Serializable object holding option data.
Serializable object holding premium data.
const std::vector< PremiumDatum > & premiumData() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
virtual void fromXML(XMLNode *node) override
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)
virtual XMLNode * toXML(XMLDocument &doc) const override
string & id()
Set the trade id.
RequiredFixings requiredFixings_
const Envelope & envelope() const
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_
QuantLib::Real value() const
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static vector< Real > getChildrenValuesAsDoubles(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static string getNodeValue(XMLNode *node)
Get a node's value.
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static void appendNode(XMLNode *parent, XMLNode *child)
Commodity Average Price Option data model and serialization.
Commodity digital option representation as call spread.
Commodity fixed and floating leg builders.
Commodity option representation.
Commodity option strip data model and serialization.
Logic for calculating required fixing dates on legs.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
bool parseBool(const string &s)
Convert text to bool.
QuantLib::ext::shared_ptr< Index > parseIndex(const string &s)
Convert std::string to QuantLib::Index.
Real parseReal(const string &s)
Convert text to Real.
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
RandomVariable max(RandomVariable x, const RandomVariable &y)
@ CalculationPeriodEndDate
std::string to_string(const LocationInfo &l)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
string conversion utilities