Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
fxdoubletouchoption.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 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
17#include <boost/make_shared.hpp>
28#include <ql/errors.hpp>
29#include <ql/exercise.hpp>
30#include <ql/instruments/barrieroption.hpp>
31#include <ql/instruments/compositeinstrument.hpp>
32#include <ql/instruments/swap.hpp>
33#include <ql/instruments/vanillaoption.hpp>
35
36using namespace QuantLib;
37
38namespace ore {
39namespace data {
40
41FxDoubleTouchOption::FxDoubleTouchOption(Envelope& env, OptionData option, BarrierData barrier, string foreignCurrency,
42 string domesticCurrency, string payoffCurrency, double payoffAmount,
43 string startDate, string calendar, string fxIndex)
44 : ore::data::Trade("FxDoubleTouchOption", env),
45 FxSingleAssetDerivative("", env, foreignCurrency, domesticCurrency), option_(option),
46 barrier_(barrier), startDate_(startDate), calendar_(calendar), fxIndex_(fxIndex), payoffAmount_(payoffAmount),
47 payoffCurrency_(payoffCurrency) {
48 DoubleBarrier::Type barrierType = parseDoubleBarrierType(barrier_.type());
49 switch (barrierType) {
50 case DoubleBarrier::KnockIn:
51 type_ = "KnockIn";
52 break;
53 case DoubleBarrier::KnockOut:
54 type_ = "KnockOut";
55 break;
56 default:
57 QL_FAIL("unsupported barrier type " << barrierType);
58 }
59}
60
61void FxDoubleTouchOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
62
63 // ISDA taxonomy
64 additionalData_["isdaAssetClass"] = string("Foreign Exchange");
65 additionalData_["isdaBaseProduct"] = string("Simple Exotic");
66 additionalData_["isdaSubProduct"] = string("Barrier");
67 additionalData_["isdaTransaction"] = string("");
68
69 additionalData_["payoffAmount"] = payoffAmount_;
70 additionalData_["payoffCurrency"] = payoffCurrency_;
71
75
76 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
77 Date start = ore::data::parseDate(startDate_);
78 Calendar cal = ore::data::parseCalendar(calendar_);
79
80 QL_REQUIRE(tradeActions().empty(), "TradeActions not supported for FxOption");
81 QL_REQUIRE(option_.exerciseDates().size() == 1, "Invalid number of exercise dates");
82 QL_REQUIRE(barrier_.levels().size() == 2, "Invalid number of barrier levels");
83 QL_REQUIRE(barrier_.style().empty() || barrier_.style() == "American", "Only american barrier style suppported");
84
85 // Parse trade data
86 Currency fgnCcy = parseCurrency(foreignCurrency_);
87 Currency domCcy = parseCurrency(domesticCurrency_);
88 Date expiryDate = parseDate(option_.exerciseDates().front());
89 DoubleBarrier::Type barrierType = parseDoubleBarrierType(barrier_.type());
90 bool payoffAtExpiry = option_.payoffAtExpiry();
91 double rebate = barrier_.rebate();
92 Position::Type positionType = parsePositionType(option_.longShort());
93
94 QL_REQUIRE(rebate == 0, "Rebates not supported for FxDoubleTouchOptions");
95 if (payoffAtExpiry == false) {
96 payoffAtExpiry = true;
97 DLOG("Payoff at hit not yet supported for FxDoubleTouchOptions, setting to payoff at expiry");
98 }
99
100 Date payDate = expiryDate;
101 const boost::optional<OptionPaymentData>& opd = option_.paymentData();
102 if (opd) {
103 if (opd->rulesBased()) {
104 payDate = opd->calendar().advance(expiryDate, opd->lag(), Days, opd->convention());
105 } else {
106 if (opd->dates().size() > 1)
108 "Found more than 1 payment date. The first one will be used.")
109 .log();
110 payDate = opd->dates().front();
111 }
112 }
113 QL_REQUIRE(payDate >= expiryDate, "Settlement date cannot be earlier than expiry date");
114 maturity_ = std::max(option_.premiumData().latestPremiumDate(), payDate);
115
116 Real levelLow = barrier_.levels()[0].value();
117 Real levelHigh = barrier_.levels()[1].value();
118 QL_REQUIRE(levelLow < levelHigh, "barrier levels are not in ascending order");
119
120 // Handle PayoffCurrency, we might have to flip the trade here
121 bool flipResults = false;
123 // Invert the trade, switch dom and for and flip Put/Call
124 levelLow = 1.0 / levelLow;
125 levelHigh = 1.0 / levelHigh;
126 std::swap(levelLow, levelHigh);
127 std::swap(fgnCcy, domCcy);
128 flipResults = true;
129 } else if (payoffCurrency_ != domesticCurrency_) {
130 QL_FAIL("Invalid Payoff currency (" << payoffCurrency_ << ") for FxDoubleTouchOption " << foreignCurrency_
132 }
133 DLOG("Setting up FxDoubleTouchOption with level " << levelLow << ", " << levelHigh << " foreign/bought " << fgnCcy
134 << " domestic/sold " << domCcy);
135 // from this point on it's important not to use domesticCurrency_, foreignCurrency_, barrier_.level(), etc
136 // rather the local variables (fgnCcy, domCcy, level, etc) should be used as they may have been flipped.
137
138 // create payoff and exercise, as well as leg of underlying instrument
139 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(new CashOrNothingPayoff(Option::Call, (levelLow + levelHigh) / 2, 1.0));
140 Leg leg;
141
142 leg.push_back(QuantLib::ext::shared_ptr<CashFlow>(new SimpleCashFlow(1.0, payDate)));
143
144 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
145
146 QuantLib::ext::shared_ptr<Instrument> doubleTouch =
147 QuantLib::ext::make_shared<DoubleBarrierOption>(barrierType, levelLow, levelHigh, 0.0, payoff, exercise);
148 QuantLib::ext::shared_ptr<Instrument> underlying = QuantLib::ext::make_shared<Swap>(Leg(), leg);
149
150 QuantLib::ext::shared_ptr<QuantExt::FxIndex> fxIndex;
151 if (!fxIndex_.empty())
152 fxIndex = buildFxIndex(fxIndex_, domCcy.code(), fgnCcy.code(), engineFactory->market(),
153 engineFactory->configuration(MarketContext::pricing));
154
155 // set pricing engines
156 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(tradeType_);
157 QL_REQUIRE(builder, "No builder found for " << tradeType_);
158 QuantLib::ext::shared_ptr<FxDoubleTouchOptionEngineBuilder> fxDoubleTouchOptBuilder =
159 QuantLib::ext::dynamic_pointer_cast<FxDoubleTouchOptionEngineBuilder>(builder);
160 doubleTouch->setPricingEngine(fxDoubleTouchOptBuilder->engine(fgnCcy, domCcy, payDate, flipResults));
161 setSensitivityTemplate(*fxDoubleTouchOptBuilder);
162
163 // if a knock-in option is triggered it becomes a simple forward cashflow
164 // which we price as a swap
165 builder = engineFactory->builder("Swap");
166 QL_REQUIRE(builder, "No builder found for Swap");
167 QuantLib::ext::shared_ptr<SwapEngineBuilderBase> swapBuilder =
168 QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(builder);
169 underlying->setPricingEngine(swapBuilder->engine(parseCurrency(payoffCurrency_), std::string(), std::string()));
170
171 bool isLong = (positionType == Position::Long) ? true : false;
172
173 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
174 std::vector<Real> additionalMultipliers;
175 addPremiums(additionalInstruments, additionalMultipliers, (isLong ? 1.0 : -1.0) * payoffAmount_,
176 option_.premiumData(), isLong ? -1.0 : 1.0, parseCurrency(payoffCurrency_), engineFactory,
177 builder->configuration(MarketContext::pricing));
178
179 Handle<Quote> spot = market->fxSpot(fgnCcy.code() + domCcy.code());
180 instrument_ = QuantLib::ext::make_shared<DoubleBarrierOptionWrapper>(
181 doubleTouch, isLong, expiryDate, false, underlying, barrierType, spot, levelLow, levelHigh, 0, domCcy,
182 start, fxIndex, cal, payoffAmount_, payoffAmount_, additionalInstruments, additionalMultipliers);
183
184
185 Calendar fixingCal = fxIndex ? fxIndex->fixingCalendar() : cal;
186 if (start != Date()) {
187 for (Date d = start; d <= expiryDate; d = fixingCal.advance(d, 1 * Days))
189 }
190
191}
192
193bool FxDoubleTouchOption::checkBarrier(Real spot, Barrier::Type type, Real barrier) {
194 switch (type) {
195 case Barrier::DownIn:
196 case Barrier::DownOut:
197 return spot <= barrier;
198 case Barrier::UpIn:
199 case Barrier::UpOut:
200 return spot >= barrier;
201 default:
202 QL_FAIL("unknown barrier type " << type);
203 }
204}
205
207 Trade::fromXML(node);
208 XMLNode* fxNode = XMLUtils::getChildNode(node, "FxDoubleTouchOptionData");
209 QL_REQUIRE(fxNode, "No FxDoubleTouchOptionData Node");
210 option_.fromXML(XMLUtils::getChildNode(fxNode, "OptionData"));
211 barrier_.fromXML(XMLUtils::getChildNode(fxNode, "BarrierData"));
212 DoubleBarrier::Type barrierType = parseDoubleBarrierType(barrier_.type());
213 switch (barrierType) {
214 case DoubleBarrier::KnockIn:
215 type_ = "KnockIn";
216 break;
217 case DoubleBarrier::KnockOut:
218 type_ = "KnockOut";
219 break;
220 default:
221 QL_FAIL("unsupported barrier type " << barrierType);
222 }
223
224 foreignCurrency_ = XMLUtils::getChildValue(fxNode, "ForeignCurrency", true);
225 domesticCurrency_ = XMLUtils::getChildValue(fxNode, "DomesticCurrency", true);
226 payoffCurrency_ = XMLUtils::getChildValue(fxNode, "PayoffCurrency", true);
227 startDate_ = XMLUtils::getChildValue(fxNode, "StartDate", false);
228 calendar_ = XMLUtils::getChildValue(fxNode, "Calendar", false);
229 fxIndex_ = XMLUtils::getChildValue(fxNode, "FXIndex", false);
230 payoffAmount_ = XMLUtils::getChildValueAsDouble(fxNode, "PayoffAmount", true);
231}
232
234 XMLNode* node = Trade::toXML(doc);
235 XMLNode* fxNode = doc.allocNode("FxDoubleTouchOptionData");
236 XMLUtils::appendNode(node, fxNode);
237 XMLUtils::appendNode(fxNode, option_.toXML(doc));
238 XMLUtils::appendNode(fxNode, barrier_.toXML(doc));
239 XMLUtils::addChild(doc, fxNode, "ForeignCurrency", foreignCurrency_);
240 XMLUtils::addChild(doc, fxNode, "DomesticCurrency", domesticCurrency_);
241 XMLUtils::addChild(doc, fxNode, "PayoffCurrency", payoffCurrency_);
242 XMLUtils::addChild(doc, fxNode, "PayoffAmount", payoffAmount_);
243 if (startDate_ != "")
244 XMLUtils::addChild(doc, fxNode, "StartDate", startDate_);
245 if (fxIndex_ != "")
246 XMLUtils::addChild(doc, fxNode, "FXIndex", fxIndex_);
247 if (calendar_ != "")
248 XMLUtils::addChild(doc, fxNode, "Calendar", calendar_);
249
250 return node;
251}
252
253} // namespace data
254} // namespace oreplus
Wrapper for option instruments, tracks whether option has been exercised or not.
Engine builder for Swaps.
Serializable obejct holding barrier data.
Definition: barrierdata.hpp:34
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
const std::string & style() const
Definition: barrierdata.hpp:51
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
const BarrierData & barrier() const
FxDoubleTouchOption()
Default constructor.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
bool checkBarrier(Real spot, Barrier::Type type, Real level)
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Base class for all single asset FX Derivaties.
void log() const
generate Boost log record to pass to corresponding sinks
Definition: log.cpp:491
Serializable object holding option data.
Definition: optiondata.hpp:42
const string & longShort() const
Definition: optiondata.hpp:70
virtual void fromXML(XMLNode *node) override
Definition: optiondata.cpp:32
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: optiondata.cpp:86
const bool & payoffAtExpiry() const
Definition: optiondata.hpp:75
const boost::optional< OptionPaymentData > & paymentData() const
Definition: optiondata.hpp:93
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.
Trade base class.
Definition: trade.hpp:55
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
void setSensitivityTemplate(const EngineBuilder &builder)
Definition: trade.cpp:295
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
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 Double One-Touch/No-Touch 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
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
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
market data related utilties
Calendar calendar
Definition: utilities.cpp:441
QuantLib::ext::shared_ptr< QuantExt::FxIndex > buildFxIndex(const string &fxIndex, const string &domestic, const string &foreign, const QuantLib::ext::shared_ptr< Market > &market, const string &configuration, bool useXbsCurves)
Definition: marketdata.cpp:137
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
Classes for structured trade warnings.