Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
basketoption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 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
21
24
25#include <boost/lexical_cast.hpp>
26
27namespace ore {
28namespace data {
29
30// clang-format off
31
32 static const std::string vanilla_basket_option_script =
33 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
34 "\n"
35 " NUMBER u, basketPrice, ExerciseProbability, Payoff, currentNotional;\n"
36 "\n"
37 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
38 " basketPrice = basketPrice + Underlyings[u](Expiry) * Weights[u];\n"
39 " END;\n"
40 "\n"
41 " Payoff = max(PutCall * (basketPrice - Strike), 0);\n"
42 "\n"
43 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
44 "\n"
45 " IF Payoff > 0 THEN\n"
46 " ExerciseProbability = 1;\n"
47 " END;\n"
48 " currentNotional = Notional * Strike;\n";
49
50 static const std::string asian_basket_option_script =
51 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
52 "\n"
53 " NUMBER d, u, basketPrice, ExerciseProbability, Payoff;\n"
54 " NUMBER currentNotional;\n"
55 "\n"
56 " FOR d IN (1, SIZE(ObservationDates), 1) DO\n"
57 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
58 " basketPrice = basketPrice + Underlyings[u](ObservationDates[d]) * Weights[u];\n"
59 " END;\n"
60 " END;\n"
61 "\n"
62 " basketPrice = basketPrice / SIZE(ObservationDates);\n"
63 "\n"
64 " Payoff = max(PutCall * (basketPrice - Strike), 0);\n"
65 "\n"
66 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
67 "\n"
68 " IF Payoff > 0 THEN\n"
69 " ExerciseProbability = 1;\n"
70 " END;\n"
71 "\n"
72 " currentNotional = Notional * Strike; \n";
73
74 static const std::string average_strike_basket_option_script =
75 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
76 "\n"
77 " NUMBER d, u, timeAverageBasketPrice, currentNotional;\n"
78 " FOR d IN (1, SIZE(ObservationDates), 1) DO\n"
79 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
80 " timeAverageBasketPrice = timeAverageBasketPrice\n"
81 " + Underlyings[u](ObservationDates[d]) * Weights[u];\n"
82 " END;\n"
83 " END;\n"
84 " timeAverageBasketPrice = timeAverageBasketPrice / SIZE(ObservationDates);\n"
85 "\n"
86 " NUMBER expiryBasketPrice;\n"
87 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
88 " expiryBasketPrice = expiryBasketPrice + Underlyings[u](Expiry) * Weights[u];\n"
89 " END;\n"
90 "\n"
91 " NUMBER Payoff;\n"
92 " Payoff = max(PutCall * (expiryBasketPrice - timeAverageBasketPrice), 0);\n"
93 "\n"
94 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
95 "\n"
96 " NUMBER ExerciseProbability;\n"
97 " IF Payoff > 0 THEN\n"
98 " ExerciseProbability = 1;\n"
99 " END;\n"
100 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
101 " currentNotional = currentNotional + Notional * Underlyings[u](ObservationDates[1]) * Weights[u];\n"
102 " END;\n";
103
104 static const std::string lookback_call_basket_option_script =
105 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
106 "\n"
107 " NUMBER d, u, basketPrice, minBasketPrice, currentNotional;\n"
108 " FOR d IN (1, SIZE(ObservationDates), 1) DO\n"
109 " basketPrice = 0;\n"
110 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
111 " basketPrice = basketPrice + Underlyings[u](ObservationDates[d]) * Weights[u];\n"
112 " END;\n"
113 " IF d == 1 THEN\n"
114 " minBasketPrice = basketPrice;\n"
115 " END;\n"
116 " IF basketPrice < minBasketPrice THEN\n"
117 " minBasketPrice = basketPrice;\n"
118 " END;\n"
119 " END;\n"
120 "\n"
121 " NUMBER expiryBasketPrice;\n"
122 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
123 " expiryBasketPrice = expiryBasketPrice + Underlyings[u](Expiry) * Weights[u];\n"
124 " END;\n"
125 "\n"
126 " NUMBER Payoff;\n"
127 " Payoff = max(expiryBasketPrice - minBasketPrice, 0);\n"
128 "\n"
129 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
130 "\n"
131 " NUMBER ExerciseProbability;\n"
132 " IF Payoff > 0 THEN\n"
133 " ExerciseProbability = 1;\n"
134 " END;\n"
135 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
136 " currentNotional = currentNotional + Notional * Underlyings[u](ObservationDates[1]) * Weights[u];\n"
137 " END;\n";
138
139 static const std::string lookback_put_basket_option_script =
140 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
141 "\n"
142 " NUMBER d, u, basketPrice, maxBasketPrice, currentNotional;\n"
143 " FOR d IN (1, SIZE(ObservationDates), 1) DO\n"
144 " basketPrice = 0;\n"
145 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
146 " basketPrice = basketPrice + Underlyings[u](ObservationDates[d]) * Weights[u];\n"
147 " END;\n"
148 " IF d == 1 THEN\n"
149 " maxBasketPrice = basketPrice;\n"
150 " END;\n"
151 " IF basketPrice > maxBasketPrice THEN\n"
152 " maxBasketPrice = basketPrice;\n"
153 " END;\n"
154 " END;\n"
155 "\n"
156 " NUMBER expiryBasketPrice;\n"
157 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
158 " expiryBasketPrice = expiryBasketPrice + Underlyings[u](Expiry) * Weights[u];\n"
159 " END;\n"
160 "\n"
161 " NUMBER Payoff;\n"
162 " Payoff = max(maxBasketPrice - expiryBasketPrice, 0);\n"
163 "\n"
164 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
165 "\n"
166 " NUMBER ExerciseProbability;\n"
167 " IF Payoff > 0 THEN\n"
168 " ExerciseProbability = 1;\n"
169 " END;\n"
170 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
171 " currentNotional = currentNotional + Notional * Underlyings[u](ObservationDates[1]) * Weights[u];\n"
172 " END;";
173
174// clang-format on
175
176void BasketOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
177
178 // set script parameters
179
180 clear();
181 initIndices();
182
183 QL_REQUIRE(optionData_.exerciseDates().size() == 1, "expected exactly one exercise date");
184 events_.emplace_back("Expiry", optionData_.exerciseDates().front());
185 events_.emplace_back("Settlement", settlement_.empty() ? optionData_.exerciseDates().front() : settlement_);
186
187 numbers_.emplace_back("Number", "Notional", notional_);
188 auto positionType = parsePositionType(optionData_.longShort());
189 numbers_.emplace_back("Number", "LongShort", positionType == Position::Long ? "1" : "-1");
190
191 std::string ccy = parseCurrencyWithMinors(currency_).code();
192 // if no strike ccy, set it to option ccy
193 string strike;
194 if (!tradeStrike_.empty()) {
195 if (tradeStrike_.currency().empty())
197 strike = boost::lexical_cast<std::string>(tradeStrike_.value());
198 }
199 currencies_.emplace_back("Currency", "PayCcy", ccy);
200
201 QL_REQUIRE(optionData_.payoffType2().empty() || optionData_.payoffType2() == "Arithmetic",
202 "BasketOption does not support payoffType2 = '" << optionData_.payoffType2()
203 << "', expected 'Arithmetic'");
204
205 std::string scriptToUse;
206 if (optionData_.payoffType() == "Vanilla") {
207 scriptToUse = vanilla_basket_option_script;
208 numbers_.emplace_back("Number", "PutCall", parseOptionType(optionData_.callPut()) == Option::Call ? "1" : "-1");
209 numbers_.emplace_back("Number", "Strike", strike);
210 } else if (optionData_.payoffType() == "Asian") {
211 scriptToUse = asian_basket_option_script;
212 numbers_.emplace_back("Number", "PutCall", parseOptionType(optionData_.callPut()) == Option::Call ? "1" : "-1");
213 events_.emplace_back("ObservationDates", observationDates_);
214 numbers_.emplace_back("Number", "Strike", strike);
215 } else if (optionData_.payoffType() == "AverageStrike") {
216 scriptToUse = average_strike_basket_option_script;
217 numbers_.emplace_back("Number", "PutCall", parseOptionType(optionData_.callPut()) == Option::Call ? "1" : "-1");
218 events_.emplace_back("ObservationDates", observationDates_);
219 } else if (optionData_.payoffType() == "LookbackCall") {
220 scriptToUse = lookback_call_basket_option_script;
221 events_.emplace_back("ObservationDates", observationDates_);
222 } else if (optionData_.payoffType() == "LookbackPut") {
223 scriptToUse = lookback_put_basket_option_script;
224 events_.emplace_back("ObservationDates", observationDates_);
225 } else {
226 QL_FAIL("payoff type '" << optionData_.payoffType() << "' not recognised");
227 }
228
229 // set product tag
230
231 productTag_ = "MultiAssetOption({AssetClass})";
232
233 // set script
234
235 script_ = {
236 {"", ScriptedTradeScriptData(scriptToUse, "Option",
237 {{"currentNotional", "currentNotional"}, {"notionalCurrency", "PayCcy"}}, {})}};
238
239 // build trade
240
241 ScriptedTrade::build(factory, optionData_.premiumData(), positionType == QuantLib::Position::Long ? -1.0 : 1.0);
242}
243
246
247 // ISDA taxonomy
248 // asset class set in the base class already
249 std::string assetClass = boost::any_cast<std::string>(additionalData_["isdaAssetClass"]);
250 if (assetClass == "Equity") {
251 additionalData_["isdaBaseProduct"] = string("Option");
252 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
253 } else if (assetClass == "Foreign Exchange") {
254 additionalData_["isdaBaseProduct"] = string("Complex Exotic");
255 additionalData_["isdaSubProduct"] = string("Generic");
256 } else if (assetClass == "Commodity") {
257 // isda taxonomy missing for this class, using the same as equity
258 additionalData_["isdaBaseProduct"] = string("Option");
259 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
260 } else {
261 WLOG("ISDA taxonomy incomplete for trade " << id());
262 }
263 additionalData_["isdaTransaction"] = string("Basket");
264}
265
267 std::vector<std::string> underlyings, weights;
268 for (auto const& u : underlyings_) {
269 underlyings.push_back(scriptedIndexName(u));
270 QL_REQUIRE(u->weight() != Null<Real>(), "underlying '" << u->name() << "' has no weight");
271 weights.push_back(boost::lexical_cast<std::string>(u->weight()));
272 }
273
274 indices_.emplace_back("Index", "Underlyings", underlyings);
275 numbers_.emplace_back("Number", "Weights", weights);
276}
277
279 Trade::fromXML(node);
280 XMLNode* dataNode = XMLUtils::getChildNode(node, tradeType() + "Data");
281 QL_REQUIRE(dataNode, tradeType() + "Data node not found");
282 notional_ = XMLUtils::getChildValue(dataNode, "Notional", true);
283 optionData_.fromXML(XMLUtils::getChildNode(dataNode, "OptionData"));
284 currency_ = XMLUtils::getChildValue(dataNode, "Currency");
285 tradeStrike_.fromXML(dataNode, false);
286 auto underlyingsNode = XMLUtils::getChildNode(dataNode, "Underlyings");
287 QL_REQUIRE(underlyingsNode, "No Underlyings node");
288 auto underlyings = XMLUtils::getChildrenNodes(underlyingsNode, "Underlying");
289 for (auto const& n : underlyings) {
290 UnderlyingBuilder underlyingBuilder;
291 underlyingBuilder.fromXML(n);
292 underlyings_.push_back(underlyingBuilder.underlying());
293 }
294
295 settlement_ = XMLUtils::getChildValue(dataNode, "Settlement");
296 if (XMLNode* n = XMLUtils::getChildNode(dataNode, "ObservationDates"))
298 initIndices();
299}
300
302 XMLNode* node = Trade::toXML(doc);
303 XMLNode* dataNode = doc.allocNode(tradeType() + "Data");
304 XMLUtils::appendNode(node, dataNode);
305 XMLUtils::addChild(doc, dataNode, "Notional", notional_);
306 XMLUtils::addChild(doc, dataNode, "Currency", currency_);
307 if (!tradeStrike_.empty())
309 XMLNode* underlyingsNode = doc.allocNode("Underlyings");
310 for (auto& n : underlyings_) {
311 XMLUtils::appendNode(underlyingsNode, n->toXML(doc));
312 }
313 XMLUtils::appendNode(dataNode, underlyingsNode);
314 XMLUtils::appendNode(dataNode, optionData_.toXML(doc));
315 if (!settlement_.empty())
316 XMLUtils::addChild(doc, dataNode, "Settlement", settlement_);
318 auto tmp = observationDates_.toXML(doc);
319 XMLUtils::setNodeName(doc, tmp, "ObservationDates");
320 XMLUtils::appendNode(dataNode, tmp);
321 }
322 return node;
323}
324
325} // namespace data
326} // namespace ore
basket option wrapper for scripted trade
void setIsdaTaxonomyFields() override
std::vector< QuantLib::ext::shared_ptr< ore::data::Underlying > > underlyings_
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
ScheduleData observationDates_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
const string & callPut() const
Definition: optiondata.hpp:71
const string & payoffType2() const
Definition: optiondata.hpp:73
const string & payoffType() const
Definition: optiondata.hpp:72
const string & longShort() const
Definition: optiondata.hpp:70
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
bool hasData() const
Check if has any dates/rules/derived schedules.
Definition: schedule.hpp:223
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:179
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:198
std::vector< ScriptedTradeEventData > events_
std::vector< ScriptedTradeValueTypeData > currencies_
std::vector< ScriptedTradeValueTypeData > indices_
virtual void setIsdaTaxonomyFields()
std::vector< ScriptedTradeValueTypeData > numbers_
std::map< std::string, ScriptedTradeScriptData > script_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
const string & tradeType() const
Definition: trade.hpp:133
std::map< std::string, boost::any > additionalData_
Definition: trade.hpp:224
XMLNode * toXML(XMLDocument &doc) const
Definition: tradestrike.cpp:86
void setCurrency(const std::string &currency)
void fromXML(XMLNode *node, const bool isRequired=true, const bool allowYieldStrike=false)
Definition: tradestrike.cpp:50
std::string currency()
const bool empty() const
QuantLib::Real value() const
const QuantLib::ext::shared_ptr< Underlying > & underlying()
Definition: underlying.hpp:266
void fromXML(XMLNode *node) override
Definition: underlying.cpp:305
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
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 void setNodeName(XMLDocument &doc, XMLNode *node, const string &name)
Definition: xmlutils.cpp:478
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
Currency parseCurrencyWithMinors(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:310
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
@ data
Definition: log.hpp:77
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Definition: utilities.cpp:614
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
some utility functions
string conversion utilities