Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commoditydigitaloption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 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
19#include <boost/make_shared.hpp>
20
21#include <ql/errors.hpp>
22#include <ql/exercise.hpp>
23#include <ql/instruments/compositeinstrument.hpp>
24#include <ql/instruments/vanillaoption.hpp>
26
32
33using namespace std;
34using namespace QuantLib;
37
38namespace ore {
39namespace data {
40
42
43CommodityDigitalOption::CommodityDigitalOption(const Envelope& env, const OptionData& optionData, const string& name,
44 const string& currency, Real strike, Real payoff,
45 const boost::optional<bool>& isFuturePrice, const Date& futureExpiryDate)
46 : optionData_(optionData), name_(name), currency_(currency), strike_(strike), payoff_(payoff),
47 isFuturePrice_(isFuturePrice), futureExpiryDate_(futureExpiryDate) {
48 tradeType_ = "CommodityDigitalOption";
49}
50
51void CommodityDigitalOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
52
53 // ISDA taxonomy, assuming Commodity follows the Equity template
54 additionalData_["isdaAssetClass"] = std::string("Commodity");
55 additionalData_["isdaBaseProduct"] = std::string("Option");
56 additionalData_["isdaSubProduct"] = std::string("Price Return Basic Performance");
57 // skip the transaction level mapping for now
58 additionalData_["isdaTransaction"] = std::string("");
59
60 // Checks
61 QL_REQUIRE((strike_ > 0 || close_enough(strike_, 0.0)), "Commodity digital option requires a positive strike");
62 QL_REQUIRE(optionData_.exerciseDates().size() == 1, "Invalid number of exercise dates");
63
65
66 // Populate the index_ in case the option is automatic exercise.
67 // Intentionally use null calendar because we will ask for index value on the expiry date without adjustment.
68 const QuantLib::ext::shared_ptr<Market>& market = engineFactory->market();
69 index_ = *market->commodityIndex(name_, engineFactory->configuration(MarketContext::pricing));
71
72 // Assume future price if isFuturePrice_ is not explicitly set or if it is and true.
73 auto index = *market->commodityIndex(name_, engineFactory->configuration(MarketContext::pricing));
74
75 // If we are given an explicit future contract expiry date, use it, otherwise use option's expiry.
76 Date expiryDate;
77 if (futureExpiryDate_ != Date()) {
78 expiryDate = futureExpiryDate_;
79 } else {
80 // Get the expiry date of the option. This is the expiry date of the commodity future index.
81 const vector<string>& expiryDates = optionData_.exerciseDates();
82 QL_REQUIRE(expiryDates.size() == 1,
83 "Expected exactly one expiry date for CommodityDigitalOption but got " << expiryDates.size() << ".");
84 expiryDate = parseDate(expiryDates[0]);
85 }
86
87 // Clone the index with the relevant expiry date.
88 index_ = index->clone(expiryDate);
89
90 // Set the VanillaOptionTrade forwardDate_ if the index is a CommodityFuturesIndex - we possibly still have a
91 // CommoditySpotIndex at this point so check. Also, will only work for European exercise.
93 QL_REQUIRE(et == Exercise::European, "European style expected for CommodityDigitalOption");
94 if (et == Exercise::European && QuantLib::ext::dynamic_pointer_cast<CommodityFuturesIndex>(index_)) {
95 forwardDate_ = expiryDate;
96 }
97 }
98
99 // Build digital as call or put spread
100 Real strikeSpread = strike_ * 0.01; // FIXME, what is a usual spread here, and where should we put it?
101 Real strike1 = strike_ - strikeSpread/2;
102 Real strike2 = strike_ + strikeSpread/2;
106 opt1.build(engineFactory);
107 opt2.build(engineFactory);
108 QuantLib::ext::shared_ptr<Instrument> inst1 = opt1.instrument()->qlInstrument();
109 QuantLib::ext::shared_ptr<Instrument> inst2 = opt2.instrument()->qlInstrument();
110
112
113 QuantLib::ext::shared_ptr<CompositeInstrument> composite = QuantLib::ext::make_shared<CompositeInstrument>();
114 // add and subtract such that the long call spread and long put spread have positive values
115 if (optionData_.callPut() == "Call") {
116 composite->add(inst1);
117 composite->subtract(inst2);
118 }
119 else if (optionData_.callPut() == "Put") {
120 composite->add(inst2);
121 composite->subtract(inst1);
122 }
123 else {
124 QL_FAIL("OptionType Call or Put required in CommodityDigitalOption " << id());
125 }
126
127 Position::Type positionType = parsePositionType(optionData_.longShort());
128 Real bsIndicator = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
129 Real multiplier = payoff_ * bsIndicator / strikeSpread;
130 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
131 std::vector<Real> additionalMultipliers;
132 // FIXME: Do we need to retrieve the engine builder's configuration
133 string configuration = Market::defaultConfiguration;
134 Currency ccy = parseCurrencyWithMinors(currency_);
135 maturity_ = std::max(expiryDate_, addPremiums(additionalInstruments, additionalMultipliers, multiplier,
136 optionData_.premiumData(), -bsIndicator, ccy, engineFactory, configuration));
137
138 instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
139 new VanillaInstrument(composite, multiplier, additionalInstruments, additionalMultipliers));
140
144
145 // LOG the volatility if the trade expiry date is in the future.
146 if (expiryDate_ > Settings::instance().evaluationDate()) {
147 DLOG("Implied vol for " << tradeType_ << " on " << name_ << " with expiry " << expiryDate_
148 << " and strike " << strike_ << " is "
149 << market->commodityVolatility(name_)->blackVol(expiryDate_, strike_));
150 }
151
152 additionalData_["payoff"] = payoff_;
153 additionalData_["strike"] = strike_;
154 additionalData_["optionType"] = optionData_.callPut();
155 additionalData_["strikeCurrency"] = currency_;
156}
157
158std::map<AssetClass, std::set<std::string>>
159CommodityDigitalOption::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
160 return {{AssetClass::COM, std::set<std::string>({name_})}};
161}
162
164
165 Trade::fromXML(node);
166
167 XMLNode* commodityNode = XMLUtils::getChildNode(node, "CommodityDigitalOptionData");
168 QL_REQUIRE(commodityNode, "A commodity option needs a 'CommodityDigitalOptionData' node");
169
170 optionData_.fromXML(XMLUtils::getChildNode(commodityNode, "OptionData"));
171
172 name_ = XMLUtils::getChildValue(commodityNode, "Name", true);
173 currency_ = XMLUtils::getChildValue(commodityNode, "Currency", true);
174 strike_ = XMLUtils::getChildValueAsDouble(commodityNode, "Strike", true);
175 payoff_ = XMLUtils::getChildValueAsDouble(commodityNode, "Payoff", true);
176
177 isFuturePrice_ = boost::none;
178 if (XMLNode* n = XMLUtils::getChildNode(commodityNode, "IsFuturePrice"))
180
181 futureExpiryDate_ = Date();
182 if (XMLNode* n = XMLUtils::getChildNode(commodityNode, "FutureExpiryDate"))
184}
185
187
188 XMLNode* node = Trade::toXML(doc);
189
190 XMLNode* commodityNode = doc.allocNode("CommodityDigitalOptionData");
191 XMLUtils::appendNode(node, commodityNode);
192
193 XMLUtils::appendNode(commodityNode, optionData_.toXML(doc));
194
195 XMLUtils::addChild(doc, commodityNode, "Name", name_);
196 XMLUtils::addChild(doc, commodityNode, "Currency", currency_);
197 XMLUtils::addChild(doc, commodityNode, "Strike", strike_);
198 XMLUtils::addChild(doc, commodityNode, "Payoff", payoff_);
199
200 if (isFuturePrice_)
201 XMLUtils::addChild(doc, commodityNode, "IsFuturePrice", *isFuturePrice_);
202
203 if (futureExpiryDate_ != Date())
204 XMLUtils::addChild(doc, commodityNode, "FutureExpiryDate", to_string(futureExpiryDate_));
205
206 return node;
207}
208
209} // namespace data
210} // namespace ore
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
Add underlying Commodity names.
QuantLib::Date expiryDate_
Store the option expiry date.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory) override
Build underlying instrument and link pricing engine.
QuantLib::ext::shared_ptr< QuantLib::Index > index_
An index is needed if the option is to be automatically exercised on expiry.
Commodity option trade representation.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory) override
Build underlying instrument and link pricing engine.
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
static const string defaultConfiguration
Default configuration label.
Definition: market.hpp:296
Serializable object holding option data.
Definition: optiondata.hpp:42
const string & callPut() const
Definition: optiondata.hpp:71
const string & longShort() const
Definition: optiondata.hpp:70
const string & style() const
Definition: optiondata.hpp:74
virtual void fromXML(XMLNode *node) override
Definition: optiondata.cpp:32
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: optiondata.cpp:86
const PremiumData & premiumData() const
Definition: optiondata.hpp:83
const vector< string > & exerciseDates() const
Definition: optiondata.hpp:76
string npvCurrency_
Definition: trade.hpp:201
const std::string & sensitivityTemplate() const
Definition: trade.cpp:305
QuantLib::Real notional_
Definition: trade.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
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)
Definition: trade.cpp:58
void setSensitivityTemplate(const EngineBuilder &builder)
Definition: trade.cpp:295
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
string tradeType_
Definition: trade.hpp:196
const QuantLib::ext::shared_ptr< InstrumentWrapper > & instrument() const
Definition: trade.hpp:141
const Envelope & envelope() const
Definition: trade.hpp:135
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
Definition: trade.hpp:197
string notionalCurrency_
Definition: trade.hpp:203
std::map< std::string, boost::any > additionalData_
Definition: trade.hpp:224
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
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static string getNodeValue(XMLNode *node)
Get a node's value.
Definition: xmlutils.cpp:489
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
Commodity digital option representation as call spread.
Commodity option representation.
Pricing Engine Factory.
Exercise::Type parseExerciseType(const std::string &s)
Convert text to QuantLib::Exercise::Type.
Definition: parsers.cpp:466
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
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
string conversion utilities
string name