19#include <boost/make_shared.hpp>
32#include <ql/errors.hpp>
33#include <ql/exercise.hpp>
34#include <ql/instruments/barrieroption.hpp>
35#include <ql/instruments/barriertype.hpp>
36#include <ql/instruments/compositeinstrument.hpp>
37#include <ql/instruments/vanillaoption.hpp>
63 Date today = Settings::instance().evaluationDate();
64 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
71 QL_REQUIRE(
barriers_.size() == 2,
"Invalid number of barriers");
72 QL_REQUIRE(
barriers_[0].levels().
size() == 1,
"Invalid number of barrier levels");
73 QL_REQUIRE(
barriers_[1].levels().
size() == 1,
"Invalid number of barrier levels");
74 QL_REQUIRE(
barriers_[0].rebate() == 0,
"rebates are not supported for KIKO options");
75 QL_REQUIRE(
barriers_[1].rebate() == 0,
"rebates are not supported for KIKO options");
77 "only american barrier style supported");
79 "only american barrier style supported");
80 QL_REQUIRE(
tradeActions().empty(),
"TradeActions not supported for FxBarrierOption");
88 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(
new PlainVanillaPayoff(type, strike));
94 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate);
97 QuantLib::ext::shared_ptr<Instrument> vanilla = QuantLib::ext::make_shared<VanillaOption>(payoff, exercise);
103 Barrier::Type knockInType;
104 Barrier::Type knockOutType;
107 switch (tmpBarrier) {
108 case Barrier::Type::UpIn:
109 case Barrier::Type::DownIn:
112 knockInType = tmpBarrier;
115 case Barrier::Type::UpOut:
116 case Barrier::Type::DownOut:
119 knockOutType = tmpBarrier;
123 QL_FAIL(
"unsupported barrier type provided");
125 QL_REQUIRE(knockOutType == Barrier::Type::UpOut || knockOutType == Barrier::Type::DownOut,
126 "KIKO barrier requires one KnockOut barrier");
127 QL_REQUIRE(knockInType == Barrier::Type::UpIn || knockInType == Barrier::Type::DownIn,
128 "KIKO barrier requires one KnockIn barrier");
130 Real knockInLevel =
barriers_[knockInIndex].levels()[0].value();
131 Real knockOutLevel =
barriers_[knockOutIndex].levels()[0].value();
133 QL_REQUIRE(knockInLevel != knockOutLevel,
"different levels must be provided");
135 bool knockedIn =
false;
136 bool knockedOut =
false;
139 QuantLib::ext::shared_ptr<QuantExt::FxIndex>
fxIndex;
141 auto fxi = market->fxIndex(
fxIndex_);
151 QL_REQUIRE(
fxIndex_ !=
"",
"no fxIndex provided");
152 QL_REQUIRE(
calendar_ !=
"",
"no calendar provided");
153 bool inverted =
false;
154 if (
fxIndex->sourceCurrency() == soldCcy &&
fxIndex->targetCurrency() == boughtCcy) {
157 QL_REQUIRE(
fxIndex->sourceCurrency() == boughtCcy &&
fxIndex->targetCurrency() == soldCcy,
158 "Invalid FX Index " <<
fxIndex_ <<
"for bought " << boughtCcy <<
"and sold " << soldCcy);
162 while (d < today && !knockedIn && !knockedOut) {
163 Real fixing = Null<Real>();
164 if (
fxIndex->fixingCalendar().isBusinessDay(d)) {
165 fixing =
fxIndex->pastFixing(d);
167 if (fixing == 0.0 || fixing == Null<Real>()) {
168 ALOG(
"Got invalid FX fixing for index " <<
fxIndex_ <<
" on " << d
169 <<
"Skipping this date, assuming no trigger");
172 fixing = 1.0 / fixing;
173 ALOG(
"Checking FX fixing for index " <<
fxIndex_ <<
" on " << d <<
", value " << fixing);
176 knockedIn =
checkBarrier(fixing, knockInType, knockInLevel);
178 knockedOut =
checkBarrier(fixing, knockOutType, knockOutLevel);
180 d = cal.advance(d, 1, Days);
185 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(
"FxOption");
186 QL_REQUIRE(builder,
"No FxOption builder found");
187 QuantLib::ext::shared_ptr<FxEuropeanOptionEngineBuilder> fxOptBuilder =
188 QuantLib::ext::dynamic_pointer_cast<FxEuropeanOptionEngineBuilder>(builder);
189 vanilla->setPricingEngine(fxOptBuilder->engine(boughtCcy, soldCcy, expiryDate));
193 Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
195 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
196 std::vector<Real> additionalMultipliers;
197 addPremiums(additionalInstruments, additionalMultipliers,
202 QuantLib::ext::shared_ptr<Instrument> barrier =
203 QuantLib::ext::make_shared<QuantLib::BarrierOption>(knockOutType, knockOutLevel, 0, payoff, exercise);
205 builder = engineFactory->builder(
"FxBarrierOption");
206 QL_REQUIRE(builder,
"No FxBarrierOption builder found");
207 QuantLib::ext::shared_ptr<FxBarrierOptionEngineBuilder> fxBarrierOptBuilder =
208 QuantLib::ext::dynamic_pointer_cast<FxBarrierOptionEngineBuilder>(builder);
209 barrier->setPricingEngine(fxBarrierOptBuilder->engine(boughtCcy, soldCcy, expiryDate, expiryDate));
213 QuantLib::ext::shared_ptr<InstrumentWrapper> koInstrument =
215 barrier, positionType == Position::Long ?
true :
false, expiryDate,
216 settleType == Settlement::Physical ?
true :
false, vanilla, knockOutType, spot, knockOutLevel, 0, soldCcy,
220 if (knockedIn || knockedOut) {
221 DLOG(
"This trade has been knocked-in, building a knock out option");
226 Handle<Quote> fx = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
227 vector<QuantLib::ext::shared_ptr<InstrumentWrapper>> iw;
228 std::vector<Handle<Quote>> fxRates;
230 DLOG(
"adding a knock out option to our composite trade");
231 iw.push_back(koInstrument);
232 fxRates.push_back(fx);
235 std::vector<Real> flippedAdditionalMultipliers;
236 for (
auto a : additionalMultipliers)
237 flippedAdditionalMultipliers.push_back(-1 * a);
243 if ((knockOutType == Barrier::Type::UpOut && knockInType == Barrier::Type::UpIn) ||
244 (knockOutType == Barrier::Type::DownOut && knockInType == Barrier::Type::DownIn)) {
245 DLOG(
"Barrier Types are UpIn/UpOut or DownIn/DownOut, we add a single Barrier Knock Out Option to our composite trade");
247 QuantLib::ext::shared_ptr<Instrument> barrier2 =
248 QuantLib::ext::make_shared<QuantLib::BarrierOption>(knockOutType, knockInLevel, 0, payoff, exercise);
249 barrier2->setPricingEngine(fxBarrierOptBuilder->engine(boughtCcy, soldCcy, expiryDate, expiryDate));
251 QuantLib::ext::shared_ptr<InstrumentWrapper> koInstrument2 =
253 barrier2, positionType == Position::Long ?
false :
true, expiryDate,
254 settleType == Settlement::Physical ?
true :
false, vanilla, knockOutType, spot, knockInLevel, 0,
257 iw.push_back(koInstrument2);
258 fxRates.push_back(fx);
264 DLOG(
"We add a Double Barrier Knock Out Option to our composite trade");
265 builder = engineFactory->builder(
"FxDoubleBarrierOption");
266 QL_REQUIRE(builder,
"No FxDoubleBarrierOption builder found");
267 QuantLib::ext::shared_ptr<FxDoubleBarrierOptionEngineBuilder> fxDoubleBarrierOptBuilder =
268 QuantLib::ext::dynamic_pointer_cast<FxDoubleBarrierOptionEngineBuilder>(builder);
270 QuantLib::ext::shared_ptr<Instrument> doubleBarrier = QuantLib::ext::make_shared<DoubleBarrierOption>(
271 DoubleBarrier::Type::KnockOut, std::min(knockInLevel, knockOutLevel),
272 std::max(knockInLevel, knockOutLevel), 0, payoff, exercise);
273 doubleBarrier->setPricingEngine(fxDoubleBarrierOptBuilder->engine(boughtCcy, soldCcy, expiryDate));
276 QuantLib::ext::shared_ptr<InstrumentWrapper> dkoInstrument =
278 doubleBarrier, positionType == Position::Long ?
false :
true, expiryDate,
279 settleType == Settlement::Physical ?
true :
false, vanilla, DoubleBarrier::Type::KnockOut, spot,
280 std::min(knockInLevel, knockOutLevel), std::max(knockInLevel, knockOutLevel), 0, soldCcy,
283 iw.push_back(dkoInstrument);
284 fxRates.push_back(fx);
289 if (start != Date()) {
290 for (Date d = start; d <= expiryDate; d = cal.advance(d, 1 * Days))
297 case Barrier::DownIn:
298 case Barrier::DownOut:
299 return spot <= barrier;
302 return spot >= barrier;
304 QL_FAIL(
"unknown barrier type " << type);
311 QL_REQUIRE(fxNode,
"No FxKIKOBarrierOptionData Node");
314 QL_REQUIRE(barrierNode,
"No Barriers node");
320 QL_REQUIRE(
barriers_.size() == 2,
"A KIKO barrier requires two BarrierData nodes");
Wrapper for option instruments, tracks whether option has been exercised or not.
Engine builder for FX Options.
Serializable obejct holding barrier data.
Composite Instrument Wrapper.
vector< BarrierData > barriers_
const vector< BarrierData > & barriers() const
const string & startDate() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
const string & fxIndex() const
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.
std::string soldCurrency_
std::string boughtCurrency_
const string & callPut() const
const string & longShort() const
const string & style() const
const string & settlement() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
const PremiumData & premiumData() const
const vector< string > & exerciseDates() const
QuantLib::Date latestPremiumDate() const
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.
virtual void fromXML(XMLNode *node) override
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)
void setSensitivityTemplate(const EngineBuilder &builder)
virtual XMLNode * toXML(XMLDocument &doc) const override
RequiredFixings requiredFixings_
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static void appendNode(XMLNode *parent, XMLNode *child)
used to store multiple trade wrappers
FX Double Barrier Option data model and serialization.
FX Option data model and serialization.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Barrier::Type parseBarrierType(const std::string &s)
Convert std::string to QuantLib::BarrierType.
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define ALOG(text)
Logging Macro (Level = Alert)
Size size(const ValueType &v)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.