Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
fxdigitalbarrieroption.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 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/vanillaoption.hpp>
34
35using namespace QuantLib;
36
37namespace ore {
38namespace data {
39
40bool checkBarrier(Real spot, Barrier::Type type, Real barrier);
41
42void FxDigitalBarrierOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
43
44 // ISDA taxonomy
45 additionalData_["isdaAssetClass"] = string("Foreign Exchange");
46 additionalData_["isdaBaseProduct"] = string("Simple Exotic");
47 additionalData_["isdaSubProduct"] = string("Digital");
48 additionalData_["isdaTransaction"] = string("");
49
50 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
51
52 // Only American supported for now
53 QL_REQUIRE(tradeActions().empty(), "TradeActions not supported for FxOption");
54 QL_REQUIRE(option_.style() == "European", "Option Style unknown: " << option_.style());
55 QL_REQUIRE(option_.exerciseDates().size() == 1, "Invalid number of exercise dates");
56 QL_REQUIRE(strike_ > 0.0 && strike_ != Null<Real>(), "Invalid strike " << strike_);
57
58 Currency boughtCcy = parseCurrency(foreignCurrency_);
59 Currency soldCcy = parseCurrency(domesticCurrency_);
60 Real level = barrier_.levels()[0].value();
61 Date start = ore::data::parseDate(startDate_);
62 Real rebate = barrier_.rebate();
63 QL_REQUIRE(rebate >= 0, "rebate must be non-negative");
64
65 QL_REQUIRE(level > 0.0 && level != Null<Real>(), "Invalid level " << level);
66
67 // Payoff and Barrier Type
68 QL_REQUIRE(barrier_.style().empty() || barrier_.style() == "American", "Only american barrier style suppported");
69 Option::Type type = parseOptionType(option_.callPut());
70 Barrier::Type barrierType = parseBarrierType(barrier_.type());
71
72 // Handle PayoffCurrency, we might have to flip the trade here
73 Real strike = strike_;
74 bool flipResults = false;
75 if (payoffCurrency_ == "") {
76 DLOG("PayoffCurrency defaulting to " << domesticCurrency_ << " for FxDigitalBarrierOption " << id());
77 } else if (payoffCurrency_ == foreignCurrency_) {
78 // Invert the trade, switch dom and for and flip Put/Call
79 strike = 1.0 / strike;
80 level = 1.0 / level;
81 std::swap(boughtCcy, soldCcy);
82 type = type == Option::Call ? Option::Put : Option::Call;
83 switch (barrierType) {
84 case Barrier::DownIn:
85 barrierType = Barrier::UpIn;
86 break;
87 case Barrier::UpIn:
88 barrierType = Barrier::DownIn;
89 break;
90 case Barrier::DownOut:
91 barrierType = Barrier::UpOut;
92 break;
93 case Barrier::UpOut:
94 barrierType = Barrier::DownOut;
95 break;
96 }
97 flipResults = true;
98 } else if (payoffCurrency_ != domesticCurrency_) {
99 QL_FAIL("Invalid Payoff currency (" << payoffCurrency_ << ") for FxDigitalBarrierOption " << foreignCurrency_
101 }
102 DLOG("Setting up FxDigitalBarrierOption with strike " << strike << " level " << level << " foreign/bought "
103 << boughtCcy << " domestic/sold " << soldCcy);
104
105 // from this point on it's important not to use domesticCurrency_, foreignCurrency_, strike_, barrier_.level(), etc
106 // rather the local variables (boughtCcy, soldCcy, strike, level, etc) should be used as they may have been flipped.
107
108 additionalData_["payoffAmount"] = payoffAmount_;
109 additionalData_["payoffCurrency"] = payoffCurrency_;
110 additionalData_["effectiveForeignCurrency"] = boughtCcy.code();
111 additionalData_["effectiveDomesticCurrency"] = soldCcy.code();
112
113 npvCurrency_ = soldCcy.code(); // sold is the domestic
116
117 // Exercise
118 // Digital Barrier Options assume an American exercise that pays at expiry
119 Date expiryDate = parseDate(option_.exerciseDates().front());
120 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
121 maturity_ = std::max(option_.premiumData().latestPremiumDate(), expiryDate);
122
123 // Create a CashOrNothing payoff for digital options
124 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(new CashOrNothingPayoff(type, strike, payoffAmount_));
125
126 // QL does not have an FXDigitalBarrierOption, so we add a barrier option here and wrap
127 // it in a composite
128 QuantLib::ext::shared_ptr<Instrument> vanilla = QuantLib::ext::make_shared<VanillaOption>(payoff, exercise);
129 QuantLib::ext::shared_ptr<Instrument> barrier =
130 QuantLib::ext::make_shared<BarrierOption>(barrierType, level, rebate, payoff, exercise);
131
132 // Check if the barrier has been triggered already
133 Calendar cal = ore::data::parseCalendar(calendar_);
134 QuantLib::ext::shared_ptr<QuantExt::FxIndex> fxIndex;
135 if (!fxIndex_.empty())
136 fxIndex = buildFxIndex(fxIndex_, soldCcy.code(), boughtCcy.code(), engineFactory->market(),
137 engineFactory->configuration(MarketContext::pricing));
138
139 // set pricing engines
140 // we buy foreign with domestic(=sold ccy).
141 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(tradeType_);
142 QL_REQUIRE(builder, "No builder found for " << tradeType_);
143 QuantLib::ext::shared_ptr<FxDigitalBarrierOptionEngineBuilder> fxBarrierOptBuilder =
144 QuantLib::ext::dynamic_pointer_cast<FxDigitalBarrierOptionEngineBuilder>(builder);
145 // if an 'in' option is triggered it becomes an FxDigitalOption, so we need an fxDigitalOption pricer
146 builder = engineFactory->builder("FxDigitalOption");
147 QL_REQUIRE(builder, "No builder found for FxDigitalOption");
148 QuantLib::ext::shared_ptr<FxDigitalOptionEngineBuilder> fxOptBuilder =
149 QuantLib::ext::dynamic_pointer_cast<FxDigitalOptionEngineBuilder>(builder);
150 setSensitivityTemplate(*builder);
151
152 barrier->setPricingEngine(fxBarrierOptBuilder->engine(boughtCcy, soldCcy, expiryDate));
153 vanilla->setPricingEngine(fxOptBuilder->engine(boughtCcy, soldCcy, flipResults));
154
155 Position::Type positionType = parsePositionType(option_.longShort());
156 Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
157
158 // If premium data is provided
159 // 1) build the fee trade and pass it to the instrument wrapper for pricing
160 // 2) add fee payment as additional trade leg for cash flow reporting
161 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
162 std::vector<Real> additionalMultipliers;
163 addPremiums(additionalInstruments, additionalMultipliers, positionType == Position::Long ? 1.0 : -1.0,
164 option_.premiumData(), -bsInd, soldCcy, engineFactory,
165 fxOptBuilder->configuration(MarketContext::pricing));
166
167 Settlement::Type settleType = parseSettlementType(option_.settlement());
168
169 Handle<Quote> spot = market->fxSpot(boughtCcy.code() + soldCcy.code());
170 instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(new SingleBarrierOptionWrapper(
171 barrier, positionType == Position::Long ? true : false, expiryDate,
172 settleType == Settlement::Physical ? true : false, vanilla, barrierType, spot, level, rebate, soldCcy,
173 start, fxIndex, cal, 1, 1, additionalInstruments, additionalMultipliers));
174
175 if (start != Date()) {
176 for (Date d = start; d <= expiryDate; d = cal.advance(d, 1 * Days)) {
178 }
179 }
180}
181
182bool checkBarrier(Real spot, Barrier::Type type, Real barrier) {
183 switch (type) {
184 case Barrier::DownIn:
185 case Barrier::DownOut:
186 return spot <= barrier;
187 case Barrier::UpIn:
188 case Barrier::UpOut:
189 return spot >= barrier;
190 default:
191 QL_FAIL("unknown barrier type " << type);
192 }
193}
194
196 Trade::fromXML(node);
197 XMLNode* fxNode = XMLUtils::getChildNode(node, "FxDigitalBarrierOptionData");
198 QL_REQUIRE(fxNode, "No FxDigitalBarrierOptionData Node");
199 option_.fromXML(XMLUtils::getChildNode(fxNode, "OptionData"));
200 barrier_.fromXML(XMLUtils::getChildNode(fxNode, "BarrierData"));
201 startDate_ = XMLUtils::getChildValue(fxNode, "StartDate", false);
202 calendar_ = XMLUtils::getChildValue(fxNode, "Calendar", false);
203 fxIndex_ = XMLUtils::getChildValue(fxNode, "FXIndex", false);
204 strike_ = XMLUtils::getChildValueAsDouble(fxNode, "Strike", true);
205 payoffAmount_ = XMLUtils::getChildValueAsDouble(fxNode, "PayoffAmount", true);
206 payoffCurrency_ = XMLUtils::getChildValue(fxNode, "PayoffCurrency", false); // optional
207 foreignCurrency_ = XMLUtils::getChildValue(fxNode, "ForeignCurrency", true);
208 domesticCurrency_ = XMLUtils::getChildValue(fxNode, "DomesticCurrency", true);
209}
210
212 XMLNode* node = Trade::toXML(doc);
213 XMLNode* fxNode = doc.allocNode("FxDigitalBarrierOptionData");
214 XMLUtils::appendNode(node, fxNode);
215
216 XMLUtils::appendNode(fxNode, option_.toXML(doc));
217 XMLUtils::appendNode(fxNode, barrier_.toXML(doc));
218 if (startDate_ != "")
219 XMLUtils::addChild(doc, fxNode, "StartDate", startDate_);
220 if (calendar_ != "")
221 XMLUtils::addChild(doc, fxNode, "Calendar", calendar_);
222 if (fxIndex_ != "")
223 XMLUtils::addChild(doc, fxNode, "FXIndex", fxIndex_);
224 XMLUtils::addChild(doc, fxNode, "Strike", strike_);
225 XMLUtils::addChild(doc, fxNode, "PayoffAmount", payoffAmount_);
226 if (payoffCurrency_ != "")
227 XMLUtils::addChild(doc, fxNode, "PayoffCurrency", payoffCurrency_);
228 XMLUtils::addChild(doc, fxNode, "ForeignCurrency", foreignCurrency_);
229 XMLUtils::addChild(doc, fxNode, "DomesticCurrency", domesticCurrency_);
230
231 return node;
232}
233
234} // namespace data
235} // namespace oreplus
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
const std::string & style() const
Definition: barrierdata.hpp:51
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
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
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)
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
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.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
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
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
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
market data related utilties
bool checkBarrier(Real spot, Barrier::Type type, Real barrier)
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.