Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
equityoptionposition.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
24
25namespace ore {
26namespace data {
27
29 XMLUtils::checkNode(node, "Underlying");
30 XMLNode* n = XMLUtils::getChildNode(node, "Underlying");
31 QL_REQUIRE(n != nullptr, "EquityOptionUnderlyingData: expected child node Underlying");
33 n = XMLUtils::getChildNode(node, "OptionData");
34 QL_REQUIRE(n != nullptr, "EquityOptionUnderlyingData: expected child node OptionData");
37}
38
40 XMLNode* n = doc.allocNode("Underlying");
43 XMLUtils::addChild(doc, n, "Strike", strike_);
44 return n;
45}
46
48 XMLUtils::checkNode(node, "EquityOptionPositionData");
49 quantity_ = XMLUtils::getChildValueAsDouble(node, "Quantity", true);
50 auto c = XMLUtils::getChildrenNodes(node, "Underlying");
51 underlyings_.clear();
52 for (auto const n : c) {
54 underlyings_.back().fromXML(n);
55 }
56}
57
59 XMLNode* n = doc.allocNode("EquityOptionPositionData");
60 XMLUtils::addChild(doc, n, "Quantity", quantity_);
61 for (auto& u : underlyings_) {
62 XMLUtils::appendNode(n, u.toXML(doc));
63 }
64 return n;
65}
66
67void EquityOptionPosition::build(const QuantLib::ext::shared_ptr<ore::data::EngineFactory>& engineFactory) {
68
69 // ISDA taxonomy: not a derivative, but define the asset class at least
70 // so that we can determine a TRS asset class that has an EQ position underlying
71 additionalData_["isdaAssetClass"] = string("Equity");
72 additionalData_["isdaBaseProduct"] = string("");
73 additionalData_["isdaSubProduct"] = string("");
74 additionalData_["isdaTransaction"] = string("");
75
76 DLOG("EquityOptionPosition::build() called for " << id());
77 QL_REQUIRE(!data_.underlyings().empty(), "EquityOptionPosition::build(): no underlyings given");
78 options_.clear();
79 indices_.clear();
80 weights_.clear();
81 positions_.clear();
82 currencies_.clear();
83 fxConversion_.clear();
84
85 setSensitivityTemplate(std::string()); // default, will usually be overwritten below
86
87 for (auto const& u : data_.underlyings()) {
88
89 // get equity, populate weight, currency
90
91 auto eq = *engineFactory->market()->equityCurve(u.underlying().name(),
92 engineFactory->configuration(MarketContext::pricing));
93 weights_.push_back(u.underlying().weight());
94 QL_REQUIRE(!eq->currency().empty(),
95 "did not get currency for equity name '" << u.underlying().name() << "', is this set up?");
96 currencies_.push_back(eq->currency().code());
97 QuantLib::Position::Type pos = parsePositionType(u.optionData().longShort());
98 Real posInd = (pos == QuantLib::Position::Long ? 1.0 : -1.0);
99 positions_.push_back(posInd);
100
101 // build vanilla option and attach engine
102
103 Option::Type optionType = parseOptionType(u.optionData().callPut());
104 QuantLib::Exercise::Type exerciseType = parseExerciseType(u.optionData().style());
105 QL_REQUIRE(u.optionData().exerciseDates().size() == 1, "Invalid number of exercise dates");
106 Date optionExpiry = parseDate(u.optionData().exerciseDates().front());
107 QuantLib::ext::shared_ptr<Exercise> exercise;
108 switch (exerciseType) {
109 case QuantLib::Exercise::Type::European: {
110 exercise = QuantLib::ext::make_shared<EuropeanExercise>(optionExpiry);
111 break;
112 }
113 case QuantLib::Exercise::Type::American: {
114 exercise = QuantLib::ext::make_shared<AmericanExercise>(optionExpiry, u.optionData().payoffAtExpiry());
115 break;
116 }
117 default:
118 QL_FAIL("Option Style " << u.optionData().style() << " is not supported");
119 }
120 options_.push_back(QuantLib::ext::make_shared<VanillaOption>(
121 QuantLib::ext::make_shared<PlainVanillaPayoff>(optionType, u.strike()), exercise));
122 if (!options_.back()->isExpired()) {
123 std::string tradeTypeBuilder =
124 (exerciseType == QuantLib::Exercise::Type::European ? "EquityOption" : "EquityOptionAmerican");
125 QuantLib::ext::shared_ptr<VanillaOptionEngineBuilder> builder =
126 QuantLib::ext::dynamic_pointer_cast<VanillaOptionEngineBuilder>(engineFactory->builder(tradeTypeBuilder));
127 QL_REQUIRE(builder, "EquityOptionPosition::build(): no engine builder for '" << tradeTypeBuilder << "'");
128 options_.back()->setPricingEngine(builder->engine(u.underlying().name(), eq->currency(), optionExpiry));
129 setSensitivityTemplate(*builder);
130 }
131
132 // populate index for historical prices
133
134 // ensure the strike appears as 2400.2 (i.e. with decimal places as necessary)
135 std::ostringstream strikeStr;
136 strikeStr << u.strike();
137
138 string underlyingName = u.underlying().name();
139 if (engineFactory->referenceData() && engineFactory->referenceData()->hasData("Equity", underlyingName)) {
140 const auto& underlyingRef = engineFactory->referenceData()->getData("Equity", underlyingName);
141 if (auto equityRef = QuantLib::ext::dynamic_pointer_cast<EquityReferenceDatum>(underlyingRef))
142 underlyingName = equityRef->equityData().equityId;
143 }
144 indices_.push_back(QuantLib::ext::make_shared<QuantExt::GenericIndex>(
145 "GENERIC-MD/EQUITY_OPTION/PRICE/" + underlyingName + "/" + eq->currency().code() + "/" +
146 ore::data::to_string(optionExpiry) + "/" + strikeStr.str() + "/" +
147 (optionType == Option::Call ? "C" : "P"), optionExpiry));
148 }
149
150 // get fx quotes
151
152 isSingleCurrency_ = true;
153 npvCurrency_ = currencies_.front();
154 for (auto const& c : currencies_) {
155 // we use fxSpot() as opposed to fxRate() here to ensure consistency between NPV() and the fixing of an
156 // equivalent index representing the same basket
157 fxConversion_.push_back(
158 engineFactory->market()->fxSpot(c + npvCurrency_, engineFactory->configuration(MarketContext::pricing)));
159 if (npvCurrency_ != c)
160 isSingleCurrency_ = false;
161 }
162
163 // set instrument
164 auto qlInstr =
165 QuantLib::ext::make_shared<EquityOptionPositionInstrumentWrapper>(data_.quantity(), options_, weights_, positions_, fxConversion_);
166 qlInstr->setPricingEngine(QuantLib::ext::make_shared<EquityOptionPositionInstrumentWrapperEngine>());
167 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(qlInstr);
168
169 // no sensible way to set these members
170 maturity_ = Date::maxDate();
171 notional_ = Null<Real>();
173
174 // leave legs empty
175}
176
177void EquityOptionPosition::setNpvCurrencyConversion(const std::string& ccy, const Handle<Quote>& conversion) {
178 npvCurrency_ = ccy;
179 QuantLib::ext::static_pointer_cast<EquityOptionPositionInstrumentWrapper>(instrument_->qlInstrument())
180 ->setNpvCurrencyConversion(conversion);
181}
182
184 Trade::fromXML(node);
185 data_.fromXML(XMLUtils::getChildNode(node, "EquityOptionPositionData"));
186}
187
189 XMLNode* node = Trade::toXML(doc);
190 XMLUtils::appendNode(node, data_.toXML(doc));
191 return node;
192}
193
194std::map<AssetClass, std::set<std::string>>
195EquityOptionPosition::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
196 std::map<AssetClass, std::set<std::string>> result;
197 for (auto const& u : data_.underlyings()) {
198 result[AssetClass::EQ].insert(u.underlying().name());
199 }
200 return result;
201}
202
204 const Real quantity, const std::vector<QuantLib::ext::shared_ptr<QuantLib::VanillaOption>>& options,
205 const std::vector<Real>& weights, const std::vector<Real>& positions, const std::vector<Handle<Quote>>& fxConversion)
206 : quantity_(quantity), options_(options), weights_(weights), positions_(positions), fxConversion_(fxConversion) {
207 QL_REQUIRE(options_.size() == weights_.size(), "EquityOptionPositionInstrumentWrapper: options size ("
208 << options_.size() << ") must match weights size ("
209 << weights_.size() << ")");
210 QL_REQUIRE(fxConversion_.empty() || fxConversion_.size() == options_.size(),
211 "EquityPositionInstrumentWrapper: fxConversion size ("
212 << fxConversion_.size() << ") must match options size (" << options_.size() << ")");
213 for (auto const& o : options)
214 registerWith(o);
215 for (auto const& fx : fxConversion)
216 registerWith(fx);
217}
218
219void EquityOptionPositionInstrumentWrapper::setNpvCurrencyConversion(const Handle<Quote>& npvCcyConversion) {
220 unregisterWith(npvCcyConversion_);
221 npvCcyConversion_ = npvCcyConversion;
222 registerWith(npvCcyConversion_);
223 update();
224}
225
227 for (auto const& o : options_)
228 if (!o->isExpired())
229 return false;
230 return true;
231}
232
236 QL_REQUIRE(a != nullptr, "wrong argument type in EquityOptionPositionInstrumentWrapper");
237 a->quantity_ = quantity_;
238 a->options_ = options_;
239 a->weights_ = weights_;
243}
244
245void EquityOptionPositionInstrumentWrapper::fetchResults(const QuantLib::PricingEngine::results* r) const {
246 Instrument::fetchResults(r);
247}
248
250 Real result = 0.0;
251 for (Size i = 0; i < arguments_.options_.size(); ++i) {
252 Real tmp = arguments_.quantity_ * arguments_.options_[i]->NPV();
253 if (!arguments_.fxConversion_[i].empty()) {
254 tmp *= arguments_.fxConversion_[i]->value();
255 }
256 result += tmp * arguments_.weights_[i] * arguments_.positions_[i];
257 }
258 if (!arguments_.npvCcyConversion_.empty()) {
259 result *= arguments_.npvCcyConversion_->value();
260 }
261 results_.value = result;
262}
263
264} // namespace data
265} // namespace ore
Abstract engine builders for European and American Options.
const Instrument::results * results_
const std::vector< EquityOptionUnderlyingData > & underlyings() const
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
std::vector< EquityOptionUnderlyingData > underlyings_
std::vector< QuantLib::ext::shared_ptr< QuantLib::VanillaOption > > options_
std::vector< QuantLib::ext::shared_ptr< QuantExt::GenericIndex > > indices_
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
void fromXML(XMLNode *node) override
std::vector< Handle< Quote > > fxConversion_
void setNpvCurrencyConversion(const std::string &ccy, const Handle< Quote > &conversion)
XMLNode * toXML(XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &) override
std::vector< std::string > currencies_
std::vector< QuantLib::ext::shared_ptr< QuantLib::VanillaOption > > options_
void fetchResults(const QuantLib::PricingEngine::results *) const override
std::vector< QuantLib::ext::shared_ptr< QuantLib::VanillaOption > > options_
EquityOptionPositionInstrumentWrapper(const Real quantity, const std::vector< QuantLib::ext::shared_ptr< QuantLib::VanillaOption > > &options, const std::vector< Real > &positions, const std::vector< Real > &weights, const std::vector< Handle< Quote > > &fxConversion={})
void setupArguments(QuantLib::PricingEngine::arguments *) const override
void setNpvCurrencyConversion(const Handle< Quote > &npvCcyConversion)
Serializable Equity Option Underlying Data, this represents one underlying in EquityOptionPositionDat...
XMLNode * toXML(XMLDocument &doc) const override
void fromXML(XMLNode *node) override
Definition: underlying.cpp:81
XMLNode * toXML(XMLDocument &doc) const override
Definition: underlying.cpp:102
virtual void fromXML(XMLNode *node) override
Definition: optiondata.cpp:32
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: optiondata.cpp:86
string npvCurrency_
Definition: trade.hpp:201
QuantLib::Real notional_
Definition: trade.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
void setSensitivityTemplate(const EngineBuilder &builder)
Definition: trade.cpp:295
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
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
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
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
Equity Option Position trade data model and serialization.
Exercise::Type parseExerciseType(const std::string &s)
Convert text to QuantLib::Exercise::Type.
Definition: parsers.cpp:466
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
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Reference data model and serialization.
Swap::arguments * arguments_