Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
doubledigitaloption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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
23namespace ore {
24namespace data {
25
26std::pair<std::string, std::string> getLowerAndUpperBound(const std::string& type, const std::string& binaryLevelA,
27 const std::string& binaryLevelB) {
28 if (type == "Call") {
29 return {binaryLevelA, ore::data::to_string(QL_MAX_REAL)};
30 } else if (type == "Put") {
31 return {ore::data::to_string(QL_MIN_REAL), binaryLevelA};
32 } else if (type == "Collar") {
33 return {binaryLevelA, binaryLevelB};
34 } else {
35 QL_FAIL("DoubleDigitalOption got unexpected option type '"
36 << type << "'. Valid values are 'Call', 'Put' and 'Collar'.");
37 }
38}
39
40void DoubleDigitalOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& factory) {
41
42 // set script parameters
43
44 clear();
46
47 events_.emplace_back("Expiry", expiry_);
48 events_.emplace_back("Settlement", settlement_);
49
50
51 std::string lowerBound1, upperBound1, lowerBound2, upperBound2;
52 std::tie(lowerBound1, upperBound1) = getLowerAndUpperBound(type1_, binaryLevel1_, binaryLevelUpper1_);
53 std::tie(lowerBound2, upperBound2) = getLowerAndUpperBound(type2_, binaryLevel2_, binaryLevelUpper2_);
54
55 numbers_.emplace_back("Number", "BinaryPayout", binaryPayout_);
56 numbers_.emplace_back("Number", "LowerBound1", lowerBound1);
57 numbers_.emplace_back("Number", "UpperBound1", upperBound1);
58 numbers_.emplace_back("Number", "LowerBound2", lowerBound2);
59 numbers_.emplace_back("Number", "UpperBound2", upperBound2);
60
61 Position::Type position = parsePositionType(position_);
62 numbers_.emplace_back("Number", "LongShort", position == Position::Long ? "1" : "-1");
63
64 currencies_.emplace_back("Currency", "PayCcy", payCcy_);
65
66 // check underlying types
67 QL_REQUIRE(underlying1_->type() == "Equity" || underlying1_->type() == "Commodity" ||
68 underlying1_->type() == "FX" || underlying1_->type() == "InterestRate",
69 "underlying type " << underlying1_->type() << " not supported");
70 QL_REQUIRE(underlying2_->type() == "Equity" || underlying2_->type() == "Commodity" ||
71 underlying2_->type() == "FX" || underlying2_->type() == "InterestRate",
72 "underlying type " << underlying2_->type() << " not supported");
73 if (underlying3_) {
74 QL_REQUIRE(underlying3_->type() == "Equity" || underlying3_->type() == "Commodity" ||
75 underlying3_->type() == "FX" || underlying3_->type() == "InterestRate",
76 "underlying type " << underlying3_->type() << " not supported");
77
78 QL_REQUIRE(underlying1_->type() == underlying3_->type(),
79 "Underlying1 and Underlying3 must belong to the same asset class. Got "
80 << underlying1_->type() << " and " << underlying3_->type());
81 }
82 if (underlying4_) {
83 QL_REQUIRE(underlying4_->type() == "Equity" || underlying4_->type() == "Commodity" ||
84 underlying4_->type() == "FX" || underlying4_->type() == "InterestRate",
85 "underlying type " << underlying4_->type() << " not supported");
86
87 QL_REQUIRE(underlying2_->type() == underlying4_->type(),
88 "Underlying2 and Underlying4 must belong to the same asset class. Got "
89 << underlying2_->type() << " and " << underlying4_->type());
90 }
91
92 // set product tag accordingly
93 if (underlying1_->type() == "InterestRate" && underlying2_->type() == "InterestRate")
94 productTag_ = "MultiUnderlyingIrOption";
95 else if (underlying1_->type() == "InterestRate" || underlying2_->type() == "InterestRate")
96 productTag_ = "IrHybrid({AssetClass})";
97 else
98 productTag_ = "MultiAssetOption({AssetClass})";
99
100 LOG("ProductTag=" << productTag_);
101
102 // set script
103
104 string underlying1Str, underlying2Str;
105 underlying1Str = underlying3_ ? "(Underlying1(Expiry) - Underlying3(Expiry))" : "Underlying1(Expiry)";
106 underlying2Str = underlying4_ ? "(Underlying2(Expiry) - Underlying4(Expiry))" : "Underlying2(Expiry)";
107
108 // clang-format off
109 script_ = {
110 {"", ScriptedTradeScriptData("NUMBER ExerciseProbability;\n"
111 "IF " + underlying1Str + " >= LowerBound1 AND " + underlying1Str + " <= UpperBound1 AND\n"
112 " " + underlying2Str + " >= LowerBound2 AND " + underlying2Str + " <= UpperBound2 THEN\n"
113 " Option = LongShort * LOGPAY( BinaryPayout, Expiry, Settlement, PayCcy);\n"
114 " ExerciseProbability = 1;\n"
115 "END;\n",
116 "Option",
117 {{"ExerciseProbability", "ExerciseProbability"},
118 {"currentNotional", "BinaryPayout"},
119 {"notionalCurrency", "PayCcy"}},
120 {})}};
121 // clang-format on
122
123 // build trade
124
125 ScriptedTrade::build(factory);
126}
127
129 indices_.emplace_back("Index", "Underlying1", scriptedIndexName(underlying1_));
130 indices_.emplace_back("Index", "Underlying2", scriptedIndexName(underlying2_));
131 if (underlying3_)
132 indices_.emplace_back("Index", "Underlying3", scriptedIndexName(underlying3_));
133 if (underlying4_)
134 indices_.emplace_back("Index", "Underlying4", scriptedIndexName(underlying4_));
135}
136
138 Trade::fromXML(node);
139 XMLNode* tradeDataNode = XMLUtils::getChildNode(node, "DoubleDigitalOptionData");
140 QL_REQUIRE(tradeDataNode, "DoubleDigitalOptionData node not found");
141 expiry_ = XMLUtils::getChildValue(tradeDataNode, "Expiry", true);
142 settlement_ = XMLUtils::getChildValue(tradeDataNode, "Settlement", true);
143 binaryPayout_ = XMLUtils::getChildValue(tradeDataNode, "BinaryPayout", true);
144 binaryLevel1_ = XMLUtils::getChildValue(tradeDataNode, "BinaryLevel1", true);
145 binaryLevel2_ = XMLUtils::getChildValue(tradeDataNode, "BinaryLevel2", true);
146 type1_ = XMLUtils::getChildValue(tradeDataNode, "Type1", true);
147 type2_ = XMLUtils::getChildValue(tradeDataNode, "Type2", true);
148 position_ = XMLUtils::getChildValue(tradeDataNode, "Position", true);
149
151 XMLUtils::getChildValue(tradeDataNode, "BinaryLevelUpper1", type1_ == "Collar");
153 XMLUtils::getChildValue(tradeDataNode, "BinaryLevelUpper2", type2_ == "Collar");
154
155 QL_REQUIRE((type1_ != "Collar" && binaryLevelUpper1_.empty()) ||
156 (type1_ == "Collar" && !binaryLevelUpper1_.empty()),
157 "A non empty upper bound 'BinaryLevelUpper1' is required if and only if a type1 is set to 'Collar', "
158 "please check trade xml.");
159
160 QL_REQUIRE((type2_ != "Collar" && binaryLevelUpper2_.empty()) ||
161 (type2_ == "Collar" && !binaryLevelUpper2_.empty()),
162 "A non empty upper bound 'BinaryLevelUpper2' is required if and only if a type2 is set to 'Collar', "
163 "please check trade xml.");
164
165 XMLNode* tmp = XMLUtils::getChildNode(tradeDataNode, "Underlying1");
166 if (!tmp)
167 tmp = XMLUtils::getChildNode(tradeDataNode, "Name1");
168 UnderlyingBuilder underlyingBuilder1("Underlying1", "Name1");
169 underlyingBuilder1.fromXML(tmp);
170 underlying1_ = underlyingBuilder1.underlying();
171
172 tmp = XMLUtils::getChildNode(tradeDataNode, "Underlying2");
173 if (!tmp)
174 tmp = XMLUtils::getChildNode(tradeDataNode, "Name2");
175 UnderlyingBuilder underlyingBuilder2("Underlying2", "Name2");
176 underlyingBuilder2.fromXML(tmp);
177 underlying2_ = underlyingBuilder2.underlying();
178
179 tmp = XMLUtils::getChildNode(tradeDataNode, "Underlying3");
180 if (!tmp)
181 tmp = XMLUtils::getChildNode(tradeDataNode, "Name3");
182 if (tmp) {
183 UnderlyingBuilder underlyingBuilder3("Underlying3", "Name3");
184 underlyingBuilder3.fromXML(tmp);
185 underlying3_ = underlyingBuilder3.underlying();
186 }
187
188 tmp = XMLUtils::getChildNode(tradeDataNode, "Underlying4");
189 if (!tmp)
190 tmp = XMLUtils::getChildNode(tradeDataNode, "Name4");
191 if (tmp) {
192 UnderlyingBuilder underlyingBuilder4("Underlying4", "Name4");
193 underlyingBuilder4.fromXML(tmp);
194 underlying4_ = underlyingBuilder4.underlying();
195 }
196
197 payCcy_ = XMLUtils::getChildValue(tradeDataNode, "PayCcy", true);
198
199 initIndices();
200}
201
203 XMLNode* node = Trade::toXML(doc);
204 XMLNode* tradeNode = doc.allocNode("DoubleDigitalOptionData");
205 XMLUtils::appendNode(node, tradeNode);
206 XMLUtils::addChild(doc, tradeNode, "Expiry", expiry_);
207 XMLUtils::addChild(doc, tradeNode, "Settlement", settlement_);
208 XMLUtils::addChild(doc, tradeNode, "BinaryPayout", binaryPayout_);
209 XMLUtils::addChild(doc, tradeNode, "BinaryLevel1", binaryLevel1_);
210 XMLUtils::addChild(doc, tradeNode, "BinaryLevel2", binaryLevel2_);
211 if (!binaryLevelUpper1_.empty()) {
212 XMLUtils::addChild(doc, tradeNode, "BinaryLevelUpper1", binaryLevelUpper1_);
213 }
214 if (!binaryLevelUpper2_.empty()) {
215 XMLUtils::addChild(doc, tradeNode, "BinaryLevelUpper2", binaryLevelUpper2_);
216 }
217 XMLUtils::addChild(doc, tradeNode, "Type1", type1_);
218 XMLUtils::addChild(doc, tradeNode, "Type2", type2_);
219 XMLUtils::addChild(doc, tradeNode, "Position", position_);
220 XMLUtils::appendNode(tradeNode, underlying1_->toXML(doc));
221 XMLUtils::appendNode(tradeNode, underlying2_->toXML(doc));
222 if (underlying3_)
223 XMLUtils::appendNode(tradeNode, underlying3_->toXML(doc));
224 if (underlying4_)
225 XMLUtils::appendNode(tradeNode, underlying4_->toXML(doc));
226 XMLUtils::addChild(doc, tradeNode, "PayCcy", payCcy_);
227 return node;
228}
229
230} // namespace data
231} // namespace ore
QuantLib::ext::shared_ptr< Underlying > underlying4_
QuantLib::ext::shared_ptr< Underlying > underlying1_
QuantLib::ext::shared_ptr< Underlying > underlying3_
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
QuantLib::ext::shared_ptr< Underlying > underlying2_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
std::vector< ScriptedTradeEventData > events_
std::vector< ScriptedTradeValueTypeData > currencies_
std::vector< ScriptedTradeValueTypeData > indices_
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 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 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
double digital option wrapper for scripted trade
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Definition: utilities.cpp:614
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
std::pair< std::string, std::string > getLowerAndUpperBound(const std::string &type, const std::string &binaryLevelA, const std::string &binaryLevelB)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
some utility functions
string conversion utilities