Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
basketvarianceswap.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
24#include <boost/lexical_cast.hpp>
25
26namespace ore {
27namespace data {
28
29void BasketVarianceSwap::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
30
31 auto builder = QuantLib::ext::dynamic_pointer_cast<ScriptedTradeEngineBuilder>(factory->builder("ScriptedTrade"));
32
33 // set script parameters
34
35 clear();
37
38 // check underlying types
39 QL_REQUIRE(underlyings_.size() > 0, "No underlyings were provided");
40 string type = underlyings_.front()->type();
41 for (auto u : underlyings_) {
42 QL_REQUIRE(u->type() == type, "All of Underlyings must be from the same asset class.");
43 }
44
45 // dates/schedules
46 events_.emplace_back("ValuationSchedule", valuationSchedule_);
47 events_.emplace_back("SettlementDate", settlementDate_);
48
49 // numbers
50 numbers_.emplace_back("Number", "Strike", strike_);
51 numbers_.emplace_back("Number", "Notional", notional_);
52 numbers_.emplace_back("Number", "Cap", cap_.empty() ? "0" : cap_);
53 numbers_.emplace_back("Number", "Floor", floor_.empty() ? "0" : floor_);
54
55 // booleans
56 numbers_.emplace_back("Number", "LongShort", parsePositionType(longShort_) == Position::Long ? "1" : "-1");
57 numbers_.emplace_back("Number", "SquaredPayoff", squaredPayoff_ ? "1" : "-1");
58
59 // currencies
60 currencies_.emplace_back("Currency", "PayCcy", currency_);
61
62 // set product tag accordingly
63 if (type == "InterestRate") {
64 productTag_ = "MultiUnderlyingIrOption";
65 } else {
66 productTag_ = "MultiAssetOptionAD({AssetClass})";
67 }
68
69 LOG("ProductTag=" << productTag_);
70
71 // set script
72
73 script_ = {// clang-format off
75 "REQUIRE {Notional >= 0} AND {Strike >= 0};\n"
76 "REQUIRE {Cap >= 0} AND {Floor >= 0};\n"
77 "\n"
78 "NUMBER i, n;\n"
79 "n = SIZE(Underlyings);\n"
80 "\n"
81 "NUMBER sumOfWeights;\n"
82 "FOR i IN (1, n, 1) DO\n"
83 " sumOfWeights = sumOfWeights + Weights[i];\n"
84 "END;\n"
85 "REQUIRE sumOfWeights == 1;\n"
86 "\n"
87 "NUMBER d, expectedN, currPrice[n], prevPrice[n];\n"
88 "NUMBER realisedVariance, basketVariation, realisedVariation;\n"
89 "NUMBER strike, cap, floor, currentNotional, payoff;\n"
90 "\n"
91 "FOR d IN (2, SIZE(ValuationSchedule), 1) DO\n"
92 " basketVariation = 0;\n"
93 " FOR i IN (1, n, 1) DO\n"
94 " currPrice[i] = Underlyings[i](ValuationSchedule[d]);\n"
95 " prevPrice[i] = Underlyings[i](ValuationSchedule[d-1]);\n"
96 " basketVariation = basketVariation + Weights[i] * ln(currPrice[i]/prevPrice[i]);\n"
97 " END;\n"
98 " realisedVariance = realisedVariance + pow(basketVariation, 2);\n"
99 "END;\n"
100 "\n"
101 "expectedN = SIZE(ValuationSchedule) - 1;\n"
102 "realisedVariance = (252/expectedN) * realisedVariance;\n"
103 "\n"
104 "IF SquaredPayoff == 1 THEN\n"
105 " realisedVariation = realisedVariance;\n"
106 " currentNotional = pow(100, 2) * Notional / (2 * 100 * Strike);\n"
107 " strike = pow(Strike, 2);\n"
108 "ELSE\n"
109 " realisedVariation = sqrt(realisedVariance);\n"
110 " currentNotional = 100 * Notional;\n"
111 " strike = Strike;\n"
112 "END;\n"
113 "\n"
114 "IF Floor > 0 THEN\n"
115 " IF SquaredPayoff == 1 THEN\n"
116 " floor = pow(Floor, 2);\n"
117 " ELSE\n"
118 " floor = Floor;\n"
119 " END;\n"
120 " realisedVariation = max(floor * strike, realisedVariation);\n"
121 "END;\n"
122 "IF Cap > 0 THEN\n"
123 " IF SquaredPayoff == 1 THEN\n"
124 " cap = pow(Cap, 2);\n"
125 " ELSE\n"
126 " cap = Cap;\n"
127 " END;\n"
128 " realisedVariation = min(cap * strike, realisedVariation);\n"
129 "END;\n"
130 "\n"
131 "payoff = LongShort * currentNotional * (realisedVariation - strike);\n"
132 "\n"
133 "Swap = PAY(payoff, ValuationSchedule[SIZE(ValuationSchedule)],\n"
134 " SettlementDate, PayCcy);\n",
135 "Swap",
136 {{"RealisedVariance", "realisedVariance"},
137 {"currentNotional", "currentNotional"},
138 {"notionalCurrency", "PayCcy"}},
139 {})}};
140 // clang-format on
141
142 // build trade
143
144 ScriptedTrade::build(factory);
145}
146
149
150 // ISDA taxonomy
151 // asset class set in the base class already
152 std::string assetClass = boost::any_cast<std::string>(additionalData_["isdaAssetClass"]);
153 if (assetClass == "Equity") {
154 additionalData_["isdaBaseProduct"] = string("Swap");
155 additionalData_["isdaSubProduct"] = string("Parameter Return Variance");
156 } else if (assetClass == "Foreign Exchange") {
157 additionalData_["isdaBaseProduct"] = string("Complex Exotic");
158 additionalData_["isdaSubProduct"] = string("Generic");
159 } else if (assetClass == "Commodity") {
160 // isda taxonomy missing for this class, using the same as equity
161 additionalData_["isdaBaseProduct"] = string("Other");
162 additionalData_["isdaSubProduct"] = string("Parameter Return Variance");
163 } else {
164 WLOG("ISDA taxonomy incomplete for trade " << id());
165 }
166 additionalData_["isdaTransaction"] = string("Basket");
167}
168
170 std::vector<string> underlyings, weights;
171 for (auto const& u : underlyings_) {
172 underlyings.push_back(scriptedIndexName(u));
173 QL_REQUIRE(u->weight() != Null<Real>(), "underlying '" << u->name() << "' has no weight");
174 weights.push_back(boost::lexical_cast<std::string>(u->weight()));
175 }
176 indices_.emplace_back("Index", "Underlyings", underlyings);
177 numbers_.emplace_back("Number", "Weights", weights);
178}
179
181 Trade::fromXML(node);
182 XMLNode* tradeDataNode = XMLUtils::getChildNode(node, tradeType() + "Data");
183 QL_REQUIRE(tradeDataNode, "BasketVarianceSwapData node not found");
184 longShort_ = XMLUtils::getChildValue(tradeDataNode, "LongShort", true);
185 notional_ = XMLUtils::getChildValue(tradeDataNode, "Notional", true);
186 strike_ = XMLUtils::getChildValue(tradeDataNode, "Strike", true);
187 cap_ = XMLUtils::getChildValue(tradeDataNode, "Cap", false);
188 floor_ = XMLUtils::getChildValue(tradeDataNode, "Floor", false);
189
190 XMLNode* valuationSchedule = XMLUtils::getChildNode(tradeDataNode, "ValuationSchedule");
191 QL_REQUIRE(valuationSchedule, "No valuation schedule provided");
192 valuationSchedule_.fromXML(valuationSchedule);
193
194 XMLNode* underlyingsNode = XMLUtils::getChildNode(tradeDataNode, "Underlyings");
195 QL_REQUIRE(underlyingsNode, "Could not find an Underlyings node.");
196 auto underlyings = XMLUtils::getChildrenNodes(underlyingsNode, "Underlying");
197 for (auto const& u : underlyings) {
198 UnderlyingBuilder underlyingBuilder;
199 underlyingBuilder.fromXML(u);
200 underlyings_.push_back(underlyingBuilder.underlying());
201 }
202
203 settlementDate_ = XMLUtils::getChildValue(tradeDataNode, "SettlementDate", false);
204
205 string squaredPayoff = XMLUtils::getChildValue(tradeDataNode, "SquaredPayoff", false);
206 squaredPayoff_ = squaredPayoff.empty() ? false : parseBool(squaredPayoff);
207
208 currency_ = XMLUtils::getChildValue(tradeDataNode, "Currency", true);
209
210 initIndices();
211}
212
214 XMLNode* node = Trade::toXML(doc);
215 XMLNode* tradeNode = doc.allocNode(tradeType() + "Data");
216 XMLUtils::appendNode(node, tradeNode);
217 XMLUtils::addChild(doc, tradeNode, "LongShort", longShort_);
218 XMLUtils::addChild(doc, tradeNode, "Currency", currency_);
219 XMLUtils::addChild(doc, tradeNode, "Notional", notional_);
220 XMLUtils::addChild(doc, tradeNode, "Strike", strike_);
221
222 XMLNode* underlyingsNode = doc.allocNode("Underlyings");
223 for (auto const& u : underlyings_)
224 XMLUtils::appendNode(underlyingsNode, u->toXML(doc));
225 XMLUtils::appendNode(tradeNode, underlyingsNode);
226
227 XMLNode* valuationSchedule = valuationSchedule_.toXML(doc);
228 XMLUtils::setNodeName(doc, valuationSchedule, "ValuationSchedule");
229 XMLUtils::appendNode(tradeNode, valuationSchedule);
230
231 XMLUtils::addChild(doc, tradeNode, "SettlementDate", settlementDate_);
232 if (!cap_.empty()) {
233 XMLUtils::addChild(doc, tradeNode, "Cap", cap_);
234 }
235 if (!floor_.empty()) {
236 XMLUtils::addChild(doc, tradeNode, "Floor", floor_);
237 }
238 XMLUtils::addChild(doc, tradeNode, "SquaredPayoff", squaredPayoff_);
239
240 return node;
241}
242
243} // namespace data
244} // namespace ore
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
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
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
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
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#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
trade schedule data model and serialization
some utility functions
string conversion utilities