Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commoditydigitalapo.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
23
26#include <ql/instruments/compositeinstrument.hpp>
27
28using namespace QuantExt;
29using namespace QuantLib;
30using std::map;
31using std::set;
32using std::string;
33
34namespace ore {
35namespace data {
36
38 const Envelope& envelope, const OptionData& optionData, Real strike, Real digitalCashPayoff, const string& currency,
39 const string& name, CommodityPriceType priceType, const string& startDate, const string& endDate,
40 const string& paymentCalendar, const string& paymentLag, const string& paymentConvention,
41 const string& pricingCalendar, const string& paymentDate, Real gearing, Spread spread,
42 CommodityQuantityFrequency commodityQuantityFrequency, CommodityPayRelativeTo commodityPayRelativeTo,
43 QuantLib::Natural futureMonthOffset, QuantLib::Natural deliveryRollDays, bool includePeriodEnd,
44 const BarrierData& barrierData, const std::string& fxIndex)
45 : Trade("CommodityDigitalAveragePriceOption", envelope), optionData_(optionData), barrierData_(barrierData),
46 strike_(strike), digitalCashPayoff_(digitalCashPayoff), currency_(currency), name_(name),
47 priceType_(priceType),
48 startDate_(startDate), endDate_(endDate), paymentCalendar_(paymentCalendar), paymentLag_(paymentLag),
49 paymentConvention_(paymentConvention), pricingCalendar_(pricingCalendar), paymentDate_(paymentDate),
50 gearing_(gearing), spread_(spread), commodityQuantityFrequency_(commodityQuantityFrequency),
51 commodityPayRelativeTo_(commodityPayRelativeTo), futureMonthOffset_(futureMonthOffset),
52 deliveryRollDays_(deliveryRollDays), includePeriodEnd_(includePeriodEnd), fxIndex_(fxIndex) {}
53
54void CommodityDigitalAveragePriceOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
55
56 reset();
57
58 DLOG("CommodityDigitalAveragePriceOption::build() called for trade " << id());
59
60 // ISDA taxonomy, assuming Commodity follows the Equity template
61 additionalData_["isdaAssetClass"] = std::string("Commodity");
62 additionalData_["isdaBaseProduct"] = std::string("Option");
63 additionalData_["isdaSubProduct"] = std::string("Price Return Basic Performance");
64 // skip the transaction level mapping for now
65 additionalData_["isdaTransaction"] = std::string("");
66
67 QL_REQUIRE(optionData_.exerciseDates().size() == 1, "Invalid number of excercise dates");
68 Date exDate = parseDate(optionData_.exerciseDates().front());
69
70
71 Real strikeSpread = strike_ * 0.01; // FIXME, what is a usual spread here, and where should we put it?
72 Real strike1 = strike_ - strikeSpread / 2;
73 Real strike2 = strike_ + strikeSpread / 2;
75 envelope(), optionData_, 1.0, strike1, currency_, name_, priceType_, startDate_, endDate_, paymentCalendar_,
76 paymentLag_, paymentConvention_, pricingCalendar_, paymentDate_, gearing_, spread_, commodityQuantityFrequency_,
77 commodityPayRelativeTo_, futureMonthOffset_, deliveryRollDays_, includePeriodEnd_, barrierData_, fxIndex_);
78
79 CommodityAveragePriceOption opt2(envelope(), optionData_, 1.0, strike2, currency_, name_, priceType_,
80 startDate_, endDate_, paymentCalendar_,
81 paymentLag_, paymentConvention_, pricingCalendar_, paymentDate_, gearing_, spread_, commodityQuantityFrequency_,
82 commodityPayRelativeTo_, futureMonthOffset_, deliveryRollDays_, includePeriodEnd_, barrierData_, fxIndex_);
83
84 opt1.build(engineFactory);
85 opt2.build(engineFactory);
86
87 setSensitivityTemplate(opt1.sensitivityTemplate());
88
89 QuantLib::ext::shared_ptr<Instrument> inst1 = opt1.instrument()->qlInstrument();
90 QuantLib::ext::shared_ptr<Instrument> inst2 = opt2.instrument()->qlInstrument();
91
92 QuantLib::ext::shared_ptr<CompositeInstrument> composite = QuantLib::ext::make_shared<CompositeInstrument>();
93 // add and subtract such that the long call spread and long put spread have positive values
94 if (optionData_.callPut() == "Call") {
95 composite->add(inst1);
96 composite->subtract(inst2);
97 } else if (optionData_.callPut() == "Put") {
98 composite->add(inst2);
99 composite->subtract(inst1);
100 } else {
101 QL_FAIL("OptionType Call or Put required in CommodityDigitalOption " << id());
102 }
103
104 Position::Type positionType = parsePositionType(optionData_.longShort());
105 Real bsIndicator = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
106 Real multiplier = digitalCashPayoff_ * bsIndicator / strikeSpread;
107 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
108 std::vector<Real> additionalMultipliers;
109 // FIXME: Do we need to retrieve the engine builder's configuration
110 string configuration = Market::defaultConfiguration;
111 Currency ccy = parseCurrencyWithMinors(currency_);
112
113 maturity_ =
114 std::max(exDate, addPremiums(additionalInstruments, additionalMultipliers, multiplier,
115 optionData_.premiumData(), -bsIndicator, ccy, engineFactory, configuration));
116
117 instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
118 new VanillaInstrument(composite, multiplier, additionalInstruments, additionalMultipliers));
119
120 npvCurrency_ = currency_;
121 notional_ = digitalCashPayoff_;
122 notionalCurrency_ = currency_;
123
124 // LOG the volatility if the trade expiry date is in the future.
125 if (exDate > Settings::instance().evaluationDate()) {
126 DLOG("Implied vol for " << tradeType_ << " on " << name_ << " with expiry " << exDate << " and strike "
127 << strike_ << " is "
128 << engineFactory->market()->commodityVolatility(name_)->blackVol(exDate, strike_));
129 }
130
131 additionalData_["payoff"] = digitalCashPayoff_;
132 additionalData_["strike"] = strike_;
133 additionalData_["optionType"] = optionData_.callPut();
134 additionalData_["strikeCurrency"] = currency_;
135}
136
137std::map<AssetClass, std::set<std::string>> CommodityDigitalAveragePriceOption::underlyingIndices(
138 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
139 return {{AssetClass::COM, std::set<std::string>({name_})}};
140}
141
142void CommodityDigitalAveragePriceOption::fromXML(XMLNode* node) {
143
144 Trade::fromXML(node);
145
146 XMLNode* apoNode = XMLUtils::getChildNode(node, "CommodityDigitalAveragePriceOptionData");
147 QL_REQUIRE(apoNode, "No CommodityDigitalAveragePriceOptionData Node");
148
149 optionData_.fromXML(XMLUtils::getChildNode(apoNode, "OptionData"));
150 if(auto b = XMLUtils::getChildNode(apoNode, "BarrierData")) {
151 barrierData_.fromXML(b);
152 }
153 name_ = XMLUtils::getChildValue(apoNode, "Name", true);
154 currency_ = XMLUtils::getChildValue(apoNode, "Currency", true);
155 strike_ = XMLUtils::getChildValueAsDouble(apoNode, "Strike", true);
156 digitalCashPayoff_ = XMLUtils::getChildValueAsDouble(apoNode, "DigitalCashPayoff", true);
157 priceType_ = parseCommodityPriceType(XMLUtils::getChildValue(apoNode, "PriceType", true));
158 startDate_ = XMLUtils::getChildValue(apoNode, "StartDate", true);
159 endDate_ = XMLUtils::getChildValue(apoNode, "EndDate", true);
160 paymentCalendar_ = XMLUtils::getChildValue(apoNode, "PaymentCalendar", true);
161 paymentLag_ = XMLUtils::getChildValue(apoNode, "PaymentLag", true);
162 paymentConvention_ = XMLUtils::getChildValue(apoNode, "PaymentConvention", true);
163 pricingCalendar_ = XMLUtils::getChildValue(apoNode, "PricingCalendar", true);
164
165 paymentDate_ = XMLUtils::getChildValue(apoNode, "PaymentDate", false);
166
167 gearing_ = 1.0;
168 if (XMLNode* n = XMLUtils::getChildNode(apoNode, "Gearing")) {
169 gearing_ = parseReal(XMLUtils::getNodeValue(n));
170 }
171
172 spread_ = XMLUtils::getChildValueAsDouble(apoNode, "Spread", false);
173
174 commodityQuantityFrequency_ = CommodityQuantityFrequency::PerCalculationPeriod;
175 if (XMLNode* n = XMLUtils::getChildNode(apoNode, "CommodityQuantityFrequency")) {
176 commodityQuantityFrequency_ = parseCommodityQuantityFrequency(XMLUtils::getNodeValue(n));
177 }
178
179 commodityPayRelativeTo_ = CommodityPayRelativeTo::CalculationPeriodEndDate;
180 if (XMLNode* n = XMLUtils::getChildNode(apoNode, "CommodityPayRelativeTo")) {
181 commodityPayRelativeTo_ = parseCommodityPayRelativeTo(XMLUtils::getNodeValue(n));
182 }
183
184 futureMonthOffset_ = XMLUtils::getChildValueAsInt(apoNode, "FutureMonthOffset", false);
185 deliveryRollDays_ = XMLUtils::getChildValueAsInt(apoNode, "DeliveryRollDays", false);
186
187 includePeriodEnd_ = true;
188 if (XMLNode* n = XMLUtils::getChildNode(apoNode, "IncludePeriodEnd")) {
189 includePeriodEnd_ = parseBool(XMLUtils::getNodeValue(n));
190 }
191
192 if (XMLNode* n = XMLUtils::getChildNode(apoNode, "FXIndex")){
193 fxIndex_ = XMLUtils::getNodeValue(n);
194 }
195}
196
197XMLNode* CommodityDigitalAveragePriceOption::toXML(XMLDocument& doc) const {
198
199 XMLNode* node = Trade::toXML(doc);
200
201 XMLNode* apoNode = doc.allocNode("CommodityDigitalAveragePriceOptionData");
202 XMLUtils::appendNode(node, apoNode);
203
204 XMLUtils::appendNode(apoNode, optionData_.toXML(doc));
205 if (barrierData_.initialized())
206 XMLUtils::appendNode(apoNode, barrierData_.toXML(doc));
207 XMLUtils::addChild(doc, apoNode, "Name", name_);
208 XMLUtils::addChild(doc, apoNode, "Currency", currency_);
209 XMLUtils::addChild(doc, apoNode, "Strike", strike_);
210 XMLUtils::addChild(doc, apoNode, "DigitalCashPayoff", digitalCashPayoff_);
211 XMLUtils::addChild(doc, apoNode, "PriceType", to_string(priceType_));
212 XMLUtils::addChild(doc, apoNode, "StartDate", startDate_);
213 XMLUtils::addChild(doc, apoNode, "EndDate", endDate_);
214 XMLUtils::addChild(doc, apoNode, "PaymentCalendar", paymentCalendar_);
215 XMLUtils::addChild(doc, apoNode, "PaymentLag", paymentLag_);
216 XMLUtils::addChild(doc, apoNode, "PaymentConvention", paymentConvention_);
217 XMLUtils::addChild(doc, apoNode, "PricingCalendar", pricingCalendar_);
218 XMLUtils::addChild(doc, apoNode, "PaymentDate", paymentDate_);
219 XMLUtils::addChild(doc, apoNode, "Gearing", gearing_);
220 XMLUtils::addChild(doc, apoNode, "Spread", spread_);
221 XMLUtils::addChild(doc, apoNode, "CommodityQuantityFrequency", to_string(commodityQuantityFrequency_));
222 XMLUtils::addChild(doc, apoNode, "CommodityPayRelativeTo", to_string(commodityPayRelativeTo_));
223 XMLUtils::addChild(doc, apoNode, "FutureMonthOffset", static_cast<int>(futureMonthOffset_));
224 XMLUtils::addChild(doc, apoNode, "DeliveryRollDays", static_cast<int>(deliveryRollDays_));
225 XMLUtils::addChild(doc, apoNode, "IncludePeriodEnd", includePeriodEnd_);
226 if(!fxIndex_.empty()){
227 XMLUtils::addChild(doc, apoNode, "FXIndex", fxIndex_);
228 }
229
230 return node;
231}
232
233} // namespace data
234} // namespace ore
Vanilla Instrument Wrapper.
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
Commodity Average Price Option data model and serialization.
Currency parseCurrencyWithMinors(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:310
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
SimpleQuote & spread_
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
CommodityQuantityFrequency
CommodityPriceType parseCommodityPriceType(const string &s)
CommodityPayRelativeTo parseCommodityPayRelativeTo(const string &s)
void reset(const ASTNodePtr root)
Definition: astresetter.cpp:44
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
CommodityQuantityFrequency parseCommodityQuantityFrequency(const string &s)
Convert text to QuantExt::CommodityQuantityFrequency.
Definition: parsers.cpp:1192
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
string conversion utilities
string name