Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
barrieroption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2021 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 ORE is free software: you can redistribute it and/or modify it
8 under the terms of the Modified BSD License. You should have received a
9 copy of the license along with this program.
10 The license is also available online at <http://opensourcerisk.org>
11 This program is distributed on the basis that it will form a useful
12 contribution to risk analytics and model standardisation, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
15 */
16
21
22#include <boost/make_shared.hpp>
30#include <ql/errors.hpp>
31#include <ql/exercise.hpp>
32#include <ql/instruments/barrieroption.hpp>
33#include <ql/instruments/barriertype.hpp>
35#include <ql/instruments/compositeinstrument.hpp>
36#include <ql/instruments/vanillaoption.hpp>
38#include <ql/instruments/doublebarrieroption.hpp>
39
40using namespace QuantLib;
41using namespace QuantExt;
42
43namespace ore {
44namespace data {
45
46void BarrierOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
47 QL_REQUIRE(tradeActions().empty(), "TradeActions not supported for FxBarrierOption");
48
50
51 QL_REQUIRE(barrier_.levels().size() > 0 && barrier_.levels().size() <= 2, "BarrierOption must have 1 or 2 levels");
52 QL_REQUIRE(option_.style() == "European", "Option Style unknown: " << option_.style());
53 QL_REQUIRE(option_.exerciseDates().size() == 1, "Invalid number of exercise dates");
54
55 // get the expiry date
56 Date expiryDate = parseDate(option_.exerciseDates().front());
57 Date payDate = expiryDate;
58 const boost::optional<OptionPaymentData>& opd = option_.paymentData();
59 if (opd) {
60 if (opd->rulesBased()) {
61 Calendar payCalendar = opd->calendar();
62 payDate = payCalendar.advance(expiryDate, opd->lag(), Days, opd->convention());
63 } else {
64 if (opd->dates().size() > 1)
66 "Found more than 1 payment date. The first one will be used.")
67 .log();
68 payDate = opd->dates().front();
69 }
70 }
71 QL_REQUIRE(payDate >= expiryDate, "Settlement date cannot be earlier than expiry date");
72
73 Real rebate = barrier_.rebate() / tradeMultiplier();
74 QL_REQUIRE(rebate >= 0, "rebate must be non-negative");
75
76
77 // set the maturity
78 maturity_ = std::max(option_.premiumData().latestPremiumDate(), payDate);
79
80 // fx base
81 // Payoff
82 Option::Type type = parseOptionType(option_.callPut());
83 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike()));
84
85 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
86 // QL does not have an FXBarrierOption, so we add a barrier option and a vanilla option here and wrap
87 // it in a composite to get the notional in.
88
89 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
90 std::vector<Real> additionalMultipliers;
91 Settlement::Type settleType = parseSettlementType(option_.settlement());
92 Position::Type positionType = parsePositionType(option_.longShort());
93
94 QuantLib::ext::shared_ptr<Instrument> vanilla;
95 QuantLib::ext::shared_ptr<Instrument> barrier;
96 QuantLib::ext::shared_ptr<InstrumentWrapper> instWrapper;
97
98 bool exercised = false;
99 Real exercisePrice = Null<Real>();
100
101 if (payDate > expiryDate) {
102 // Has the option been marked as exercised
103 const boost::optional<OptionExerciseData>& oed = option_.exerciseData();
104 if (oed) {
105 QL_REQUIRE(oed->date() == expiryDate, "The supplied exercise date ("
106 << io::iso_date(oed->date())
107 << ") should equal the option's expiry date ("
108 << io::iso_date(expiryDate) << ").");
109 exercised = true;
110 exercisePrice = oed->price();
111 }
112
113 QuantLib::ext::shared_ptr<Index> index;
115 index = getIndex();
116 QL_REQUIRE(index, "Barrier option trade with delayed payment "
117 << id() << ": the FXIndex node needs to be populated.");
118 requiredFixings_.addFixingDate(expiryDate, index->name(), payDate);
119 }
120 vanilla = QuantLib::ext::make_shared<CashSettledEuropeanOption>(payoff->optionType(), payoff->strike(), expiryDate,
121 payDate, option_.isAutomaticExercise(), index,
122 exercised, exercisePrice);
123 } else {
124 vanilla = QuantLib::ext::make_shared<VanillaOption>(payoff, exercise);
125 }
126
127 boost::variant<Barrier::Type, DoubleBarrier::Type> barrierType;
128 if (barrier_.levels().size() < 2) {
129 barrierType = parseBarrierType(barrier_.type());
130 barrier = QuantLib::ext::make_shared<QuantLib::BarrierOption>(QuantLib::ext::get<Barrier::Type>(barrierType), barrier_.levels()[0].value(),
131 rebate, payoff, exercise);
132 } else {
133 barrierType = parseDoubleBarrierType(barrier_.type());
134 barrier = QuantLib::ext::make_shared<QuantLib::DoubleBarrierOption>(QuantLib::ext::get<DoubleBarrier::Type>(barrierType),
135 barrier_.levels()[0].value(), barrier_.levels()[1].value(), rebate, payoff, exercise);
136 }
137
138 QuantLib::ext::shared_ptr<QuantLib::PricingEngine> barrierEngine = barrierPricingEngine(engineFactory, expiryDate, payDate);
139 QuantLib::ext::shared_ptr<QuantLib::PricingEngine> vanillaEngine = vanillaPricingEngine(engineFactory, expiryDate, payDate);
140
141 // set pricing engines
142 barrier->setPricingEngine(barrierEngine);
143 vanilla->setPricingEngine(vanillaEngine);
144
145 QuantLib::ext::shared_ptr<QuantLib::Index> index = getIndex();
146 const QuantLib::Handle<QuantLib::Quote>& spot = spotQuote();
147 if (barrier_.levels().size() < 2)
148 instWrapper = QuantLib::ext::make_shared<SingleBarrierOptionWrapper>(
149 barrier, positionType == Position::Long ? true : false, expiryDate,
150 settleType == Settlement::Physical ? true : false, vanilla, QuantLib::ext::get<Barrier::Type>(barrierType),
151 spot, barrier_.levels()[0].value(), rebate, tradeCurrency(), startDate_, index, calendar_,
152 tradeMultiplier(), tradeMultiplier(), additionalInstruments, additionalMultipliers);
153 else
154 instWrapper = QuantLib::ext::make_shared<DoubleBarrierOptionWrapper>(
155 barrier, positionType == Position::Long ? true : false, expiryDate,
156 settleType == Settlement::Physical ? true : false, vanilla, QuantLib::ext::get<DoubleBarrier::Type>(barrierType),
157 spot, barrier_.levels()[0].value(), barrier_.levels()[1].value(), rebate, tradeCurrency(), startDate_, index, calendar_,
158 tradeMultiplier(), tradeMultiplier(), additionalInstruments, additionalMultipliers);
159
160 instrument_ = instWrapper;
161
162 Calendar fixingCal = index ? index->fixingCalendar() : calendar_;
163 if (startDate_ != Null<Date>() && !indexFixingName().empty()) {
164 for (Date d = fixingCal.adjust(startDate_); d <= expiryDate; d = fixingCal.advance(d, 1 * Days)) {
166 }
167 }
168
169 // Add additional premium payments
170 Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
171 addPremiums(additionalInstruments, additionalMultipliers, bsInd * tradeMultiplier(), option_.premiumData(), -bsInd,
172 tradeCurrency(), engineFactory, engineFactory->configuration(MarketContext::pricing));
173}
174
175
177 Trade::fromXML(node);
178 XMLNode* dataNode = XMLUtils::getChildNode(node, tradeType_ + "Data");
179 QL_REQUIRE(dataNode, "No " + tradeType_ + " Node");
180 option_.fromXML(XMLUtils::getChildNode(dataNode, "OptionData"));
181 barrier_.fromXML(XMLUtils::getChildNode(dataNode, "BarrierData"));
182 startDate_ = ore::data::parseDate(XMLUtils::getChildValue(dataNode, "StartDate", false));
183 calendarStr_ = XMLUtils::getChildValue(dataNode, "Calendar", false);
185
186 additionalFromXml(dataNode);
187}
188
190 XMLNode* node = Trade::toXML(doc);
191 XMLNode* barNode = doc.allocNode(tradeType_ + "Data");
192 XMLUtils::appendNode(node, barNode);
193
194 XMLUtils::appendNode(barNode, option_.toXML(doc));
195 XMLUtils::appendNode(barNode, barrier_.toXML(doc));
196 if (startDate_ != Date())
197 XMLUtils::addChild(doc, barNode, "StartDate", to_string(startDate_));
198 if (!calendarStr_.empty())
199 XMLUtils::addChild(doc, barNode, "Calendar", calendarStr_);
200 additionalToXml(doc, barNode);
201
202 return node;
203}
204
206 if (fxIndexStr_.empty())
208 else
209 return fxIndexStr_;
210}
211
212void FxOptionWithBarrier::build(const QuantLib::ext::shared_ptr<ore::data::EngineFactory>& ef) {
213
214 // ISDA taxonomy
215 additionalData_["isdaAssetClass"] = string("Foreign Exchange");
216 additionalData_["isdaBaseProduct"] = string("Simple Exotic");
217 additionalData_["isdaSubProduct"] = string("Barrier");
218 additionalData_["isdaTransaction"] = string("");
219
220 additionalData_["boughAmount"] = boughtAmount_;
221 additionalData_["boughtCurrency"] = boughtCurrency_;
222 additionalData_["soldAmount"] = soldAmount_;
223 additionalData_["soldCurrency"] = soldCurrency_;
224
225 npvCurrency_ = soldCurrency_; // sold is the domestic
227 notionalCurrency_ = soldCurrency_; // sold is the domestic
228
229 QuantLib::Date expiryDate = parseDate(option().exerciseDates().front());
230 maturity_ = std::max(option().premiumData().latestPremiumDate(), expiryDate);
231
232 spotQuote_ = ef->market()->fxSpot(boughtCurrency_ + soldCurrency_);
233 fxIndex_ = ef->market()->fxIndex(indexFixingName(), ef->configuration(MarketContext::pricing)).currentLink();
234
236}
237
239 fxIndexStr_ = XMLUtils::getChildValue(node, "FXIndex", false);
240 boughtCurrency_ = XMLUtils::getChildValue(node, "BoughtCurrency", true);
241 soldCurrency_ = XMLUtils::getChildValue(node, "SoldCurrency", true);
242 boughtAmount_ = XMLUtils::getChildValueAsDouble(node, "BoughtAmount", true);
243 soldAmount_ = XMLUtils::getChildValueAsDouble(node, "SoldAmount", true);
244}
245
247 if (!fxIndexStr_.empty())
248 XMLUtils::addChild(doc, node, "FXIndex", fxIndexStr_);
249 XMLUtils::addChild(doc, node, "BoughtCurrency", boughtCurrency_);
250 XMLUtils::addChild(doc, node, "BoughtAmount", boughtAmount_);
251 XMLUtils::addChild(doc, node, "SoldCurrency", soldCurrency_);
252 XMLUtils::addChild(doc, node, "SoldAmount", soldAmount_);
253}
254
255
256void EquityOptionWithBarrier::build(const QuantLib::ext::shared_ptr<ore::data::EngineFactory>& ef) {
257
258 additionalData_["isdaAssetClass"] = string("Equity");
259 additionalData_["isdaBaseProduct"] = string("Option");
260 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
261 additionalData_["isdaTransaction"] = string("");
262
263 additionalData_["quantity"] = quantity_;
264 additionalData_["strike"] = tradeStrike_.value();
265 additionalData_["strikeCurrency"] = tradeStrike_.currency();
266
267 QuantLib::Date expiryDate = parseDate(option().exerciseDates().front());
268 maturity_ = std::max(option().premiumData().latestPremiumDate(), expiryDate);
269
270 if (tradeStrike_.currency().empty())
272
273 npvCurrency_ = currency_.code();
274
275 // Notional - we really need todays spot to get the correct notional.
276 // But rather than having it move around we use strike * quantity
279
280 eqIndex_ = ef->market()->equityCurve(equityName()).currentLink();
281
283}
284
286 XMLNode* tmp = XMLUtils::getChildNode(node, "Underlying");
287 if (!tmp)
288 tmp = XMLUtils::getChildNode(node, "Name");
290 currencyStr_ = XMLUtils::getChildValue(node, "Currency", true);
292 tradeStrike_.fromXML(node);
293 quantity_ = XMLUtils::getChildValueAsDouble(node, "Quantity", true);
294}
295
299 XMLUtils::addChild(doc, node, "Currency", currencyStr_);
300 XMLUtils::addChild(doc, node, "Quantity", quantity_);
301}
302
303} // namespace data
304} // namespace oreplus
Barrier Option data model and serialization.
Wrapper for option instruments, tracks whether option has been exercised or not.
Engine builder for FX Options.
const std::string & type() const
Definition: barrierdata.hpp:46
virtual void fromXML(ore::data::XMLNode *node) override
Definition: barrierdata.cpp:25
double rebate() const
Definition: barrierdata.hpp:47
virtual ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
Definition: barrierdata.cpp:49
std::vector< ore::data::TradeBarrier > levels() const
Definition: barrierdata.hpp:50
virtual QuantLib::ext::shared_ptr< QuantLib::PricingEngine > vanillaPricingEngine(const QuantLib::ext::shared_ptr< EngineFactory > &ef, const QuantLib::Date &expiryDate, const QuantLib::Date &paymentDate)=0
const BarrierData & barrier() const
virtual std::string indexFixingName()=0
virtual QuantLib::Real tradeMultiplier()=0
const ore::data::OptionData & option() const
virtual Currency tradeCurrency()=0
ore::data::OptionData option_
void fromXML(ore::data::XMLNode *node) override
virtual void checkBarriers()=0
check validity of barriers
virtual void additionalToXml(ore::data::XMLDocument &doc, ore::data::XMLNode *node) const =0
QuantLib::Calendar calendar_
ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
virtual QuantLib::ext::shared_ptr< QuantLib::PricingEngine > barrierPricingEngine(const QuantLib::ext::shared_ptr< EngineFactory > &ef, const QuantLib::Date &expiryDate, const QuantLib::Date &paymentDate)=0
virtual void additionalFromXml(ore::data::XMLNode *node)=0
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
virtual const QuantLib::Handle< QuantLib::Quote > & spotQuote()=0
virtual const QuantLib::Real strike()=0
virtual QuantLib::ext::shared_ptr< QuantLib::Index > getIndex()=0
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &ef) override
void additionalFromXml(ore::data::XMLNode *node) override
void additionalToXml(ore::data::XMLDocument &doc, ore::data::XMLNode *node) const override
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > eqIndex_
void fromXML(XMLNode *node) override
Definition: underlying.cpp:81
XMLNode * toXML(XMLDocument &doc) const override
Definition: underlying.cpp:102
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &ef) override
QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndex_
void additionalFromXml(ore::data::XMLNode *node) override
void additionalToXml(ore::data::XMLDocument &doc, ore::data::XMLNode *node) const override
QuantLib::Handle< QuantLib::Quote > spotQuote_
std::string indexFixingName() override
void log() const
generate Boost log record to pass to corresponding sinks
Definition: log.cpp:491
const string & callPut() const
Definition: optiondata.hpp:71
const string & longShort() const
Definition: optiondata.hpp:70
const string & style() const
Definition: optiondata.hpp:74
const string & settlement() const
Definition: optiondata.hpp:81
virtual void fromXML(XMLNode *node) override
Definition: optiondata.cpp:32
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: optiondata.cpp:86
bool isAutomaticExercise() const
Automatic exercise assumed false if not explicitly provided.
Definition: optiondata.hpp:117
const boost::optional< OptionPaymentData > & paymentData() const
Definition: optiondata.hpp:93
const boost::optional< OptionExerciseData > & exerciseData() const
Definition: optiondata.hpp:92
const PremiumData & premiumData() const
Definition: optiondata.hpp:83
const vector< string > & exerciseDates() const
Definition: optiondata.hpp:76
QuantLib::Date latestPremiumDate() const
Definition: premiumdata.cpp:28
void addFixingDate(const QuantLib::Date &fixingDate, const std::string &indexName, const QuantLib::Date &payDate=Date::maxDate(), const bool alwaysAddIfPaysOnSettlement=false, const bool mandatoryFixing=true)
Utility classes for Structured warnings, contains the Trade ID and Type.
TradeActions & tradeActions()
Set the trade actions.
Definition: trade.hpp:126
string npvCurrency_
Definition: trade.hpp:201
QuantLib::Real notional_
Definition: trade.hpp:202
virtual void fromXML(XMLNode *node) override
Definition: trade.cpp:34
Date addPremiums(std::vector< QuantLib::ext::shared_ptr< Instrument > > &instruments, std::vector< Real > &multipliers, const Real tradeMultiplier, const PremiumData &premiumData, const Real premiumMultiplier, const Currency &tradeCurrency, const QuantLib::ext::shared_ptr< EngineFactory > &factory, const string &configuration)
Definition: trade.cpp:58
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: trade.cpp:46
string tradeType_
Definition: trade.hpp:196
RequiredFixings requiredFixings_
Definition: trade.hpp:223
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
Definition: trade.hpp:197
string notionalCurrency_
Definition: trade.hpp:203
const string & tradeType() const
Definition: trade.hpp:133
std::map< std::string, boost::any > additionalData_
Definition: trade.hpp:224
XMLNode * toXML(XMLDocument &doc) const
Definition: tradestrike.cpp:86
void setCurrency(const std::string &currency)
void fromXML(XMLNode *node, const bool isRequired=true, const bool allowYieldStrike=false)
Definition: tradestrike.cpp:50
std::string currency()
QuantLib::Real value() const
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
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
Pricing Engine Factory.
FX Option data model and serialization.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
DoubleBarrier::Type parseDoubleBarrierType(const std::string &s)
Convert std::string to QuantLib::DoubleBarrierType.
Definition: parsers.cpp:1061
Currency parseCurrencyWithMinors(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:310
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
Barrier::Type parseBarrierType(const std::string &s)
Convert std::string to QuantLib::BarrierType.
Definition: parsers.cpp:1042
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
Definition: parsers.cpp:434
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
market data related utilties
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
Classes for structured trade warnings.