Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
rainbowoption.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
22
23#include <boost/lexical_cast.hpp>
24
25namespace ore {
26namespace data {
27
28// clang-format off
29
30 static const std::string best_of_asset_or_cash_rainbow_option_script =
31 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
32 " NUMBER u, thisPrice, bestPrice, Payoff, currentNotional;\n"
33 " NUMBER expUnderValue[SIZE(Underlyings)];\n"
34 " bestPrice = Strike;\n"
35 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
36 " expUnderValue[u] = Underlyings[u](Expiry);\n"
37 " thisPrice = Underlyings[u](Expiry) * Weights[u];\n"
38 " IF thisPrice > bestPrice THEN\n"
39 " bestPrice = thisPrice;\n"
40 " END;\n"
41 " END;\n"
42 " Option = LongShort * Notional * PAY(bestPrice, Expiry, Settlement, PayCcy);\n"
43 " currentNotional = Notional * Strike;\n";
44
45 static const std::string worst_of_asset_or_cash_rainbow_option_script =
46 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
47 " NUMBER u, thisPrice, worstPrice, Payoff, currentNotional;\n"
48 " NUMBER expUnderValue[SIZE(Underlyings)];\n"
49 " worstPrice = Strike;\n"
50 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
51 " expUnderValue[u] = Underlyings[u](Expiry);\n"
52 " thisPrice = Underlyings[u](Expiry) * Weights[u];\n"
53 " IF thisPrice < worstPrice THEN\n"
54 " worstPrice = thisPrice;\n"
55 " END;\n"
56 " END;\n"
57 " Option = LongShort * Notional * PAY(worstPrice, Expiry, Settlement, PayCcy);\n"
58 " currentNotional = Notional * Strike;\n";
59
60 static const std::string max_rainbow_option_script =
61 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
62 "\n"
63 " NUMBER u, thisPrice, maxPrice, Payoff, ExerciseProbability, currentNotional;\n"
64 " NUMBER expUnderValue[SIZE(Underlyings)];\n"
65 " maxPrice = 0;\n"
66 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
67 " expUnderValue[u] = Underlyings[u](Expiry);\n"
68 " thisPrice = Underlyings[u](Expiry) * Weights[u];\n"
69 " IF thisPrice > maxPrice THEN\n"
70 " maxPrice = thisPrice;\n"
71 " END;\n"
72 " END;\n"
73 "\n"
74 " Payoff = max(PutCall * (maxPrice - Strike), 0);\n"
75 "\n"
76 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
77 "\n"
78 " IF Payoff > 0 THEN\n"
79 " ExerciseProbability = 1;\n"
80 " END;\n"
81 " currentNotional = Notional * Strike;\n";
82
83 static const std::string min_rainbow_option_script =
84 " REQUIRE SIZE(Underlyings) == SIZE(Weights);\n"
85 " REQUIRE SIZE(Underlyings) > 0;\n"
86 "\n"
87 " NUMBER u, thisPrice, minPrice, Payoff, ExerciseProbability, currentNotional;\n"
88 " NUMBER expUnderValue[SIZE(Underlyings)];\n"
89 " minPrice = Underlyings[1](Expiry) * Weights[1];\n"
90 " FOR u IN (1, SIZE(Underlyings), 1) DO\n"
91 " expUnderValue[u] = Underlyings[u](Expiry);\n"
92 " thisPrice = Underlyings[u](Expiry) * Weights[u];\n"
93 " IF thisPrice < minPrice THEN\n"
94 " minPrice = thisPrice;\n"
95 " END;\n"
96 " END;\n"
97 "\n"
98 " Payoff = max(PutCall * (minPrice - Strike), 0);\n"
99 "\n"
100 " Option = LongShort * Notional * PAY(Payoff, Expiry, Settlement, PayCcy);\n"
101 "\n"
102 " IF Payoff > 0 THEN\n"
103 " ExerciseProbability = 1;\n"
104 " END;\n"
105 " currentNotional = Notional * Strike;\n";
106
107// clang-format on
108
109void RainbowOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
110
111 // set script parameters
112
113 clear();
114 initIndices();
115
116 QL_REQUIRE(optionData_.exerciseDates().size() == 1, "expected exactly one exercise date");
117 events_.emplace_back("Expiry", optionData_.exerciseDates().front());
118 events_.emplace_back("Settlement", settlement_.empty() ? optionData_.exerciseDates().front() : settlement_);
119
120 numbers_.emplace_back("Number", "Notional", notional_);
121 numbers_.emplace_back("Number", "LongShort",
122 parsePositionType(optionData_.longShort()) == Position::Long ? "1" : "-1");
123
124 currencies_.emplace_back("Currency", "PayCcy", currency_);
125
126 numbers_.emplace_back("Number", "Strike", strike_);
127
128 std::string scriptToUse;
129 if (optionData_.payoffType() == "BestOfAssetOrCash") {
130 scriptToUse = best_of_asset_or_cash_rainbow_option_script;
131 } else if (optionData_.payoffType() == "WorstOfAssetOrCash") {
132 scriptToUse = worst_of_asset_or_cash_rainbow_option_script;
133 } else if (optionData_.payoffType() == "MaxRainbow") {
134 scriptToUse = max_rainbow_option_script;
135 numbers_.emplace_back("Number", "PutCall", parseOptionType(optionData_.callPut()) == Option::Call ? "1" : "-1");
136 } else if (optionData_.payoffType() == "MinRainbow") {
137 scriptToUse = min_rainbow_option_script;
138 numbers_.emplace_back("Number", "PutCall", parseOptionType(optionData_.callPut()) == Option::Call ? "1" : "-1");
139 } else {
140 QL_FAIL("payoff type '" << optionData_.payoffType() << "' not recognised");
141 }
142
143 // set product tag
144
145 productTag_ = "MultiAssetOption({AssetClass})";
146
147 // set script
148
149 script_ = {{"", ScriptedTradeScriptData(scriptToUse, "Option",
150 {{"currentNotional", "currentNotional"},
151 {"notionalCurrency", "PayCcy"},
152 {"expectedUnderlyingValue", "expUnderValue"}},
153 {})}};
154
155 // build trade
156
157 ScriptedTrade::build(factory);
158}
159
162
163 // ISDA taxonomy
164 // asset class set in the base class already
165 std::string assetClass = boost::any_cast<std::string>(additionalData_["isdaAssetClass"]);
166 if (assetClass == "Equity") {
167 additionalData_["isdaBaseProduct"] = string("Other");
168 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
169 }
170 else if (assetClass == "Commodity") {
171 // isda taxonomy missing for this class, using the same as equity
172 additionalData_["isdaBaseProduct"] = string("Other");
173 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
174 }
175 else if (assetClass == "Foreign Exchange") {
176 additionalData_["isdaBaseProduct"] = string("Complex Exotic");
177 additionalData_["isdaSubProduct"] = string("Generic");
178 }
179 else {
180 WLOG("ISDA taxonomy incomplete for trade " << id());
181 }
182 additionalData_["isdaTransaction"] = string("Basket");
183}
184
186 std::vector<std::string> underlyings, weights;
187 for (auto const& u : underlyings_) {
188 underlyings.push_back(scriptedIndexName(u));
189 QL_REQUIRE(u->weight() != Null<Real>(), "underlying '" << u->name() << "' has no weight");
190 weights.push_back(boost::lexical_cast<std::string>(u->weight()));
191 }
192 indices_.emplace_back("Index", "Underlyings", underlyings);
193 numbers_.emplace_back("Number", "Weights", weights);
194}
195
197 Trade::fromXML(node);
198 XMLNode* dataNode = XMLUtils::getChildNode(node, tradeType() + "Data");
199 QL_REQUIRE(dataNode, tradeType() + "Data node not found");
200 currency_ = XMLUtils::getChildValue(dataNode, "Currency", true);
201 notional_ = XMLUtils::getChildValue(dataNode, "Notional", true);
202 strike_ = XMLUtils::getChildValue(dataNode, "Strike", true);
203 auto underlyingsNode = XMLUtils::getChildNode(dataNode, "Underlyings");
204 QL_REQUIRE(underlyingsNode, "No Underlyings node");
205 auto underlyings = XMLUtils::getChildrenNodes(underlyingsNode, "Underlying");
206 for (auto const& n : underlyings) {
207 UnderlyingBuilder underlyingBuilder;
208 underlyingBuilder.fromXML(n);
209 underlyings_.push_back(underlyingBuilder.underlying());
210 }
211 optionData_.fromXML(XMLUtils::getChildNode(dataNode, "OptionData"));
212 settlement_ = XMLUtils::getChildValue(dataNode, "Settlement");
213 initIndices();
214}
215
217 XMLNode* node = Trade::toXML(doc);
218 XMLNode* dataNode = doc.allocNode(tradeType() + "Data");
219 XMLUtils::appendNode(node, dataNode);
220 XMLUtils::addChild(doc, dataNode, "Currency", currency_);
221 XMLUtils::addChild(doc, dataNode, "Notional", notional_);
222 XMLUtils::addChild(doc, dataNode, "Strike", strike_);
223 XMLNode* underlyingsNode = doc.allocNode("Underlyings");
224 for (auto& n : underlyings_) {
225 XMLUtils::appendNode(underlyingsNode, n->toXML(doc));
226 }
227 XMLUtils::appendNode(dataNode, underlyingsNode);
228 XMLUtils::appendNode(dataNode, optionData_.toXML(doc));
229 if (!settlement_.empty())
230 XMLUtils::addChild(doc, dataNode, "Settlement", settlement_);
231 return node;
232}
233
234} // namespace data
235} // namespace ore
const string & callPut() const
Definition: optiondata.hpp:71
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 vector< string > & exerciseDates() const
Definition: optiondata.hpp:76
void setIsdaTaxonomyFields() override
std::vector< QuantLib::ext::shared_ptr< Underlying > > underlyings_
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
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
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 XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
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
rainbow option wrapper for scripted trade
some utility functions
string conversion utilities