Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
multilegoption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 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
23
26
27#include <ql/cashflows/capflooredcoupon.hpp>
28#include <ql/cashflows/floatingratecoupon.hpp>
29
30#include <boost/make_shared.hpp>
31
32namespace ore {
33namespace data {
34
35using namespace QuantExt;
36
37void MultiLegOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
38
39 DLOG("Building MultiLegOption " << id());
40
41 QL_REQUIRE(!underlyingData_.empty(), "MultiLegOption: no underlying given");
42
43 Position::Type positionType = Position::Long;
44 Settlement::Type settleType = Settlement::Cash;
45 if (hasOption()) {
46 Exercise::Type exerciseType = parseExerciseType(optionData_.style());
47 QL_REQUIRE(exerciseType == Exercise::Bermudan || exerciseType == Exercise::European,
48 "MultiLegOption: exercise type must be bermudan or european");
49 settleType = parseSettlementType(optionData_.settlement());
50 positionType = parsePositionType(optionData_.longShort());
51 }
52
53 Date today = Settings::instance().evaluationDate();
54 Real multiplier = positionType == Position::Long ? 1.0 : -1.0;
55
56 auto builder =
57 QuantLib::ext::dynamic_pointer_cast<MultiLegOptionEngineBuilderBase>(engineFactory->builder("MultiLegOption"));
58 QL_REQUIRE(builder != nullptr, "wrong builder, expected multi leg option engine builder");
59
60 // build underlying legs
61
62 // TODO support notional exchanges, fx resets, more leg types
63 vector<Leg> underlyingLegs;
64 vector<bool> underlyingPayers;
65 vector<Currency> underlyingCurrencies;
66 legCurrencies_.clear();
67
68 for (Size i = 0; i < underlyingData_.size(); ++i) {
69 auto legBuilder = engineFactory->legBuilder(underlyingData_[i].legType());
70 underlyingLegs.push_back(legBuilder->buildLeg(underlyingData_[i], engineFactory, requiredFixings_,
71 builder->configuration(MarketContext::pricing)));
72 underlyingCurrencies.push_back(parseCurrency(underlyingData_[i].currency()));
73 legCurrencies_.push_back(underlyingData_[i].currency());
74 underlyingPayers.push_back(underlyingData_[i].isPayer());
75 DLOG("Added leg of type " << underlyingData_[i].legType() << " in currency " << underlyingData_[i].currency()
76 << " is payer " << underlyingData_[i].isPayer());
77 }
78
79 // build exercise option
80
81 QuantLib::ext::shared_ptr<Exercise> exercise;
82 vector<Date> exDates;
83 if (hasOption()) {
84 for (Size i = 0; i < optionData_.exerciseDates().size(); ++i) {
85 Date exDate = parseDate(optionData_.exerciseDates()[i]);
86 if (exDate > Settings::instance().evaluationDate())
87 exDates.push_back(exDate);
88 }
89 }
90 if (!exDates.empty()) {
91 std::sort(exDates.begin(), exDates.end());
92 exercise = QuantLib::ext::make_shared<BermudanExercise>(exDates);
93 DLOG("Added exercise with " << exDates.size() << " alive exercise dates.");
94 } else {
95 DLOG("No exercise added, instrument is equal to the underlying");
96 }
97
98 // build instrument
99
100 auto multiLegOption = QuantLib::ext::make_shared<QuantExt::MultiLegOption>(underlyingLegs, underlyingPayers,
101 underlyingCurrencies, exercise, settleType);
102
103 DLOG("QLE Instrument built.")
104
105 // extract underlying fixing dates and indices (needed in the engine builder for model calibration below)
106 // also add currencies from indices
107 vector<Date> underlyingFixingDates;
108 vector<QuantLib::ext::shared_ptr<InterestRateIndex>> underlyingIndices;
109 vector<Currency> allCurrencies;
110 for (auto const& c : underlyingCurrencies) {
111 if (std::find(allCurrencies.begin(), allCurrencies.end(), c) == allCurrencies.end()) {
112 allCurrencies.push_back(c);
113 }
114 }
115 for (auto const& l : underlyingLegs) {
116 for (auto const& c : l) {
117 auto flr = QuantLib::ext::dynamic_pointer_cast<QuantLib::FloatingRateCoupon>(c);
118 auto cfc = QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredCoupon>(c);
119 if (cfc != nullptr)
120 flr = cfc->underlying();
121 if (flr != nullptr) {
122 if (flr->fixingDate() > today) {
123 underlyingFixingDates.push_back(flr->fixingDate());
124 underlyingIndices.push_back(flr->index());
125 if (std::find(allCurrencies.begin(), allCurrencies.end(), flr->index()->currency()) ==
126 allCurrencies.end())
127 allCurrencies.push_back(flr->index()->currency());
128 }
129 }
130 }
131 }
132
133 DLOG("Extracted underlying currencies, indices and fixing dates.")
134
135 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
136 std::vector<Real> additionalMultipliers;
137 Date lastPremiumDate = addPremiums(additionalInstruments, additionalMultipliers, multiplier,
138 optionData_.premiumData(), -multiplier, parseCurrency(legCurrencies_.front()),
139 engineFactory, builder->configuration(MarketContext::pricing));
140
141 // get engine and assign it
142
143 std::sort(allCurrencies.begin(), allCurrencies.end(),
144 [](const Currency& a, const Currency& b) { return a.code() < b.code(); });
145 auto engine = builder->engine(id(), exDates, multiLegOption->maturityDate(), allCurrencies, underlyingFixingDates,
146 underlyingIndices);
147 multiLegOption->setPricingEngine(engine);
148 setSensitivityTemplate(*builder);
149
150 DLOG("Pricing engine set.")
151
152 // build instrument
153 // WARNING: we don't support an option wrapper here, i.e. the vanilla simulation will not work properly
154 instrument_ =
155 QuantLib::ext::make_shared<VanillaInstrument>(multiLegOption, multiplier, additionalInstruments, additionalMultipliers);
156
157 // popular trade members
158
159 legs_ = underlyingLegs;
160 legPayers_ = underlyingPayers;
161 notional_ = currentNotional(legs_.front());
162 maturity_ = std::max(lastPremiumDate, multiLegOption->maturityDate());
163 // npv currency is base currency of the pricing model
164 auto moe = QuantLib::ext::dynamic_pointer_cast<McMultiLegOptionEngine>(engine);
165 QL_REQUIRE(moe != nullptr, "MultiLegOption::build(): expected McMultiLegOptionEngine from engine builder");
166 npvCurrency_ = moe->model()->irlgm1f(0)->currency().code();
167
168 DLOG("Building MultiLegOption done");
169} // build
170
171void MultiLegOption::fromXML(XMLNode* node) {
172 Trade::fromXML(node);
173 underlyingData_.clear();
174 optionData_ = OptionData();
175 hasOption_ = false;
176 XMLNode* n0 = XMLUtils::getChildNode(node, "MultiLegOptionData");
177 XMLNode* n1 = XMLUtils::getChildNode(n0, "OptionData");
178 if (n1 != nullptr) {
179 optionData_.fromXML(n1);
180 hasOption_ = true;
181 }
182 vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(n0, "LegData");
183 for (auto const n : nodes) {
184 LegData ld;
185 ld.fromXML(n);
186 underlyingData_.push_back(ld);
187 }
188}
189
190XMLNode* MultiLegOption::toXML(XMLDocument& doc) const {
191 XMLNode* node = Trade::toXML(doc);
192 XMLNode* n0 = doc.allocNode("MultiLegOptionData");
193 XMLUtils::appendNode(node, n0);
194 if (hasOption_) {
195 XMLUtils::appendNode(n0, optionData_.toXML(doc));
196 for (auto& d : underlyingData_) {
197 XMLUtils::appendNode(n0, d.toXML(doc));
198 }
199 }
200 return node;
201}
202
203} // namespace data
204} // namespace ore
multi leg option engine builder
const std::vector< Leg > legs_
Serializable object holding leg data.
Definition: legdata.hpp:844
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:759
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Serializable object holding option data.
Definition: optiondata.hpp:42
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
Logic for calculating required fixing dates on legs.
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
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
Definition: parsers.cpp:434
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
Multileg Option data model.
Real currentNotional(const Leg &leg)
Definition: legdata.cpp:2435
Size size(const ValueType &v)
Definition: value.cpp:145
Serializable Credit Default Swap.
Definition: namespaces.docs:23