Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
equityoption.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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
19#include <boost/make_shared.hpp>
27#include <ql/errors.hpp>
28#include <ql/exercise.hpp>
29#include <ql/instruments/compositeinstrument.hpp>
30#include <ql/instruments/vanillaoption.hpp>
31
32using namespace QuantLib;
33
34namespace ore {
35namespace data {
36
37void EquityOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
38
39 // ISDA taxonomy
40 additionalData_["isdaAssetClass"] = string("Equity");
41 additionalData_["isdaBaseProduct"] = string("Option");
42 additionalData_["isdaSubProduct"] = string("Price Return Basic Performance");
43 // skip the transaction level mapping for now
44 additionalData_["isdaTransaction"] = string("");
45
46 additionalData_["quantity"] = quantity_;
47 additionalData_["strike"] = strike_.value();
48 additionalData_["strikeCurrency"] = strike_.currency();
49
50 // Set the assetName_ as it may have changed after lookup
52
53 Currency ccy = parseCurrencyWithMinors(currency_);
54 npvCurrency_ = notionalCurrency_ = ccy.code();
55
56 // Notional - we really need todays spot to get the correct notional.
57 // But rather than having it move around we use strike * quantity
59
60 QL_REQUIRE(option_.exerciseDates().size() == 1, "Invalid number of exercise dates");
62 // Set the maturity date equal to the expiry date. It may get updated below if option is cash settled with
63 // payment after expiry.
65
66 // Populate the index_ in case the option is automatic exercise.
67 const QuantLib::ext::shared_ptr<Market>& market = engineFactory->market();
68 index_ = *market->equityCurve(assetName_, engineFactory->configuration(MarketContext::pricing));
69
70 // check the equity currency
72 market->equityCurve(assetName_, engineFactory->configuration(MarketContext::pricing))->currency();
73 QL_REQUIRE(!underlyingCurrency_.empty(), "No equity currency in equityCurve for equity " << assetName_ << ".");
74
75 // Set the strike currency - if we have a minor currency, convert the strike
76 if (!strikeCurrency_.empty())
78 else if (strike_.currency().empty()) {
79 // If payoff currency and underlying currency are equivalent (and payoff currency could be a minor currency)
80 if (ccy == underlyingCurrency_) {
81 TLOG("Setting strike currency to payoff currency " << ccy << " for trade " << id() << ".");
82 strike_.setCurrency(ccy.code());
83 } else {
84 // If quanto payoff, then strike currency must be populated to avoid confusion over what the
85 // currency of the strike payoff is: can be either underlying currency or payoff currency
86 QL_FAIL("Strike currency must be specified for a quanto payoff for trade " << id() << ".");
87 }
88 }
89 // Quanto payoff condition, i.e. currency_ != underlyingCurrency_, will be checked in VanillaOptionTrade::build()
90 // Build the trade using the shared functionality in the base class.
91 if (strike_.currency() != underlyingCurrency_.code()) {
92
93 // We have a composite EQ Trade
94
95 Currency strikeCcy = parseCurrencyWithMinors(strikeCurrency_);
96 QL_REQUIRE(ccy == strikeCcy, "Equity composite option requires pay ccy ("
97 << ccy.code() << ") to match strike ccy (" << strikeCcy.code()
98 << "), quanto composite options are not supported (underlying currency is "
99 << underlyingCurrency_.code() << ")");
100
101 // Exercise
102 QuantLib::Exercise::Type exerciseType = parseExerciseType(option_.style());
103 QuantLib::ext::shared_ptr<Exercise> exercise;
104 switch (exerciseType) {
105 case QuantLib::Exercise::Type::European: {
106 exercise = QuantLib::ext::make_shared<EuropeanExercise>(expiryDate_);
107 break;
108 }
109 default:
110 QL_FAIL("Option Style " << option_.style() << " is not supported for an composite equity option");
111 }
112 Settlement::Type settlementType = parseSettlementType(option_.settlement());
113 // Create the instrument and then populate the name for the engine builder.
114 QuantLib::ext::shared_ptr<Instrument> vanilla;
115 if (exerciseType == Exercise::European && settlementType == Settlement::Cash) {
116 // We have a European cash settled option.
117
118 // Get the payment date.
119 const boost::optional<OptionPaymentData>& opd = option_.paymentData();
121 if (opd) {
122 if (opd->rulesBased()) {
123 const Calendar& cal = opd->calendar();
124 QL_REQUIRE(cal != Calendar(), "Need a non-empty calendar for rules based payment date.");
125 paymentDate = cal.advance(expiryDate_, opd->lag(), Days, opd->convention());
126 } else {
127 const vector<Date>& dates = opd->dates();
128 QL_REQUIRE(dates.size() == 1, "Need exactly one payment date for cash settled European option.");
129 paymentDate = dates[0];
130 }
131 QL_REQUIRE(paymentDate >= expiryDate_, "Payment date must be greater than or equal to expiry date.");
132 }
133
134 QL_REQUIRE(paymentDate <= expiryDate_,
135 "Payment date must equal expiry date for a Composite payoff. Trade: " << id() << ".");
136 }
137 QL_REQUIRE(forwardDate_ ==
138 QuantLib::Date(), "Composite payoff is not currently supported for Forward Options: Trade "
139 << id());
140 Option::Type type = parseOptionType(option_.callPut());
141 QuantLib::ext::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(type, strike_.value()));
142 vanilla = QuantLib::ext::make_shared<QuantLib::VanillaOption>(payoff, exercise);
143
144 string tradeTypeBuilder = "EquityEuropeanCompositeOption";
145
146 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(tradeTypeBuilder);
147 QL_REQUIRE(builder, "No builder found for " << tradeTypeBuilder);
148
149 // TODO cast and set pricing engine
150
151 auto compositeBuilder = QuantLib::ext::dynamic_pointer_cast<EquityEuropeanCompositeEngineBuilder>(builder);
152 vanilla->setPricingEngine(compositeBuilder->engine(assetName_, underlyingCurrency_,
154 setSensitivityTemplate(*compositeBuilder);
155
156 string configuration = Market::defaultConfiguration;
157 Position::Type positionType = parsePositionType(option_.longShort());
158 Real bsInd = (positionType == QuantLib::Position::Long ? 1.0 : -1.0);
159 Real mult = quantity_ * bsInd;
160
161 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
162 std::vector<Real> additionalMultipliers;
163 maturity_ =
164 std::max(maturity_, addPremiums(additionalInstruments, additionalMultipliers, mult, option_.premiumData(),
165 -bsInd, ccy, engineFactory, configuration));
166
167 instrument_ = QuantLib::ext::shared_ptr<InstrumentWrapper>(
168 new VanillaInstrument(vanilla, mult, additionalInstruments, additionalMultipliers));
169
170 } else {
171 VanillaOptionTrade::build(engineFactory);
172 }
173}
174
177 XMLNode* eqNode = XMLUtils::getChildNode(node, "EquityOptionData");
178 QL_REQUIRE(eqNode, "No EquityOptionData Node");
179 option_.fromXML(XMLUtils::getChildNode(eqNode, "OptionData"));
180 XMLNode* tmp = XMLUtils::getChildNode(eqNode, "Underlying");
181 if (!tmp)
182 tmp = XMLUtils::getChildNode(eqNode, "Name");
184 currency_ = XMLUtils::getChildValue(eqNode, "Currency", true);
185 strike_.fromXML(eqNode);
186
187 strikeCurrency_ = XMLUtils::getChildValue(eqNode, "StrikeCurrency", false);
188 if (!strikeCurrency_.empty())
189 WLOG("EquityOption::fromXML: node StrikeCurrency is deprecated, please use StrikeData node");
190 quantity_ = XMLUtils::getChildValueAsDouble(eqNode, "Quantity", true);
191}
192
195 XMLNode* eqNode = doc.allocNode("EquityOptionData");
196 XMLUtils::appendNode(node, eqNode);
197
198 XMLUtils::appendNode(eqNode, option_.toXML(doc));
200 XMLUtils::addChild(doc, eqNode, "Currency", currency_);
201
202 XMLUtils::appendNode(eqNode, strike_.toXML(doc));
203 if (!strikeCurrency_.empty())
204 XMLUtils::addChild(doc, eqNode, "StrikeCurrency", strikeCurrency_);
205
206 XMLUtils::addChild(doc, eqNode, "Quantity", quantity_);
207
208 return node;
209}
210
211std::map<AssetClass, std::set<std::string>> EquityOption::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
212 return {{AssetClass::EQ, std::set<std::string>({equityName()})}};
213}
214
215} // namespace data
216} // namespace ore
Engine builder for equity options.
const string & equityName() const
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
Add underlying Equity names.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
EquityUnderlying equityUnderlying_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
void fromXML(XMLNode *node) override
Definition: underlying.cpp:81
XMLNode * toXML(XMLDocument &doc) const override
Definition: underlying.cpp:102
static const string defaultConfiguration
Default configuration label.
Definition: market.hpp:296
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 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
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
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
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
Vanilla Instrument Wrapper.
QuantLib::Date expiryDate_
Store the option expiry date.
const QuantLib::Date paymentDate() const
QuantLib::Date forwardDate_
Store the (optional) forward date.
QuantLib::ext::shared_ptr< QuantLib::Index > index_
An index is needed if the option is to be automatically exercised on expiry.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
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.
Engine builder for equity composite options.
Equity Option data model and serialization.
Exercise::Type parseExerciseType(const std::string &s)
Convert text to QuantLib::Exercise::Type.
Definition: parsers.cpp:466
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
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
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Reference data model and serialization.