Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commodityswaption.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
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 <ql/cashflows/coupon.hpp>
20#include <ql/cashflows/simplecashflow.hpp>
21#include <ql/exercise.hpp>
22
27
32
33#include <boost/algorithm/string/case_conv.hpp>
34
35#include <algorithm>
36
37using namespace QuantLib;
38using std::lower_bound;
39using std::sort;
40
41namespace ore {
42namespace data {
43
44void CommoditySwaption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
45
46 reset();
47
48 DLOG("CommoditySwaption::build() called for trade " << id());
49
50 // ISDA taxonomy
51 additionalData_["isdaAssetClass"] = std::string("Commodity");
52 additionalData_["isdaBaseProduct"] = std::string("Other");
53 additionalData_["isdaSubProduct"] = std::string("");
54 // skip the transaction level mapping for now
55 additionalData_["isdaTransaction"] = std::string("");
56
57 // Swaption details
58 Settlement::Type settleType = parseSettlementType(option_.settlement());
59
60 // Just set a consistent method here if it is left empty
61 Settlement::Method settleMethod = Settlement::PhysicalOTC;
62 if (option_.settlementMethod().empty()) {
63 if (settleType == Settlement::Cash) {
64 settleMethod = Settlement::CollateralizedCashPrice;
65 }
66 } else {
68 }
69
70 QL_REQUIRE(option_.exerciseDates().size() == 1, "Commodity swaption must be European");
71 Date exDate = parseDate(option_.exerciseDates().front());
72 QL_REQUIRE(exDate >= Settings::instance().evaluationDate(),
73 "Exercise date, " << io::iso_date(exDate) << ", should be in the future relative to the valuation date "
74 << io::iso_date(Settings::instance().evaluationDate()));
75
76 // Build the underyling swap and check exercise date
77 QuantLib::ext::shared_ptr<QuantLib::Swap> swap = buildSwap(engineFactory);
78 QL_REQUIRE(exDate <= startDate_, "Expected the expiry date, " << io::iso_date(exDate)
79 << " to be on or before the swap start date "
80 << io::iso_date(startDate_));
81
82 // Build the swaption
83 exercise_ = QuantLib::ext::make_shared<EuropeanExercise>(exDate);
84 QuantLib::ext::shared_ptr<QuantExt::GenericSwaption> swaption =
85 QuantLib::ext::make_shared<QuantExt::GenericSwaption>(swap, exercise_, settleType, settleMethod);
86
87 // Set the swaption's pricing engine
88 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder(tradeType_);
89 QuantLib::ext::shared_ptr<CommoditySwaptionEngineBuilder> engineBuilder =
90 QuantLib::ext::dynamic_pointer_cast<CommoditySwaptionEngineBuilder>(builder);
91 auto configuration = builder->configuration(MarketContext::pricing);
92 Currency currency = parseCurrency(ccy_);
93 QuantLib::ext::shared_ptr<PricingEngine> engine = engineBuilder->engine(currency, name_);
94 setSensitivityTemplate(*engineBuilder);
95 swaption->setPricingEngine(engine);
96
97 // Set the instrument wrapper properly
98 Position::Type positionType = parsePositionType(option_.longShort());
99 if (settleType == Settlement::Cash) {
100 Real multiplier = positionType == Position::Long ? 1.0 : -1.0;
101 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(swaption, multiplier);
102 } else {
103 instrument_ = QuantLib::ext::make_shared<EuropeanOptionWrapper>(swaption, positionType == Position::Long, exDate,
104 settleType == Settlement::Physical, swap);
105 }
106 // use underlying maturity independent of settlement type, following ISDA GRID/AANA guidance
107 maturity_ = swap->maturityDate();
108}
109
110QuantLib::Real CommoditySwaption::notional() const {
111 return commoditySwap_->notional();
112}
113
114QuantLib::ext::shared_ptr<QuantLib::Swap> CommoditySwaption::buildSwap(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
115
116 // Some checks to make sure the underlying swap is supported
117 QL_REQUIRE(legData_.size() == 2, "Expected two commodity legs but found " << legData_.size());
118 QL_REQUIRE(legData_[0].currency() == legData_[1].currency(), "Cross currency commodity swap not supported");
119 QL_REQUIRE(legData_[0].isPayer() != legData_[1].isPayer(),
120 "Both commodity legs are " << (legData_[0].isPayer() ? "paying" : "receiving"));
121
122 QL_REQUIRE(legData_[0].legType() == "CommodityFixed" || legData_[0].legType() == "CommodityFloating",
123 "Leg type needs to be CommodityFixed or CommodityFloating but 1st leg has type "
124 << legData_[0].legType());
125 QL_REQUIRE(legData_[1].legType() == "CommodityFixed" || legData_[1].legType() == "CommodityFloating",
126 "Leg type needs to be CommodityFixed or CommodityFloating but 2nd leg has type "
127 << legData_[1].legType());
128
129 if (legData_[0].legType() == "CommodityFixed") {
130 QL_REQUIRE(legData_[1].legType() == "CommodityFloating",
131 "1st leg is CommodityFixed so 2nd leg should be CommodityFloating but is " << legData_[1].legType());
132 auto floatLeg = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegData>(legData_[1].concreteLegData());
133 name_ = floatLeg->name();
134 } else {
135 auto floatLeg = QuantLib::ext::dynamic_pointer_cast<CommodityFloatingLegData>(legData_[0].concreteLegData());
136 QL_REQUIRE(floatLeg, "first leg has type " << legData_[0].legType() << ", expected CommodityFloating");
137 name_ = floatLeg->name();
138 }
139
140 // Build the underlying commodity swap
141 commoditySwap_ = QuantLib::ext::make_shared<CommoditySwap>(envelope(), legData_);
142 commoditySwap_->build(engineFactory);
143
144 // Get the QuantLib::Swap from the commodity swap
145 auto qlInstrument = commoditySwap_->instrument()->qlInstrument();
146 QuantLib::ext::shared_ptr<QuantLib::Swap> swap = QuantLib::ext::dynamic_pointer_cast<QuantLib::Swap>(qlInstrument);
147 QL_REQUIRE(swap, "Expected an underlying swap instrument from CommoditySwap");
148
149 // Populate relevant member variables, notonal and notional currency are set by the underlying Swap build already.
150 startDate_ = swap->startDate();
151 ccy_ = npvCurrency_ = legData_[0].currency();
152 notional_ = Null<Real>();
153 notionalCurrency_ = commoditySwap_->notionalCurrency();
154
155 return swap;
156}
157
158std::map<AssetClass, std::set<std::string>>
159CommoditySwaption::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
160
161 std::map<AssetClass, std::set<std::string>> result;
162
163 for (auto ld : legData_) {
164 set<string> indices = ld.indices();
165 for (auto ind : indices) {
166 QuantLib::ext::shared_ptr<Index> index = parseIndex(ind);
167 // only handle commodity
168 if (auto ci = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityIndex>(index)) {
169 result[AssetClass::COM].insert(ci->name());
170 }
171 }
172 }
173 return result;
174}
175
177
178 Trade::fromXML(node);
179
180 XMLNode* swapNode = XMLUtils::getChildNode(node, "CommoditySwaptionData");
181 QL_REQUIRE(swapNode, "No CommoditySwaptionData node");
182
183 // Get the option data
184 option_.fromXML(XMLUtils::getChildNode(swapNode, "OptionData"));
185
186 // Get the leg data i.e. the leg data describing the underlying swap
187 vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(swapNode, "LegData");
188 QL_REQUIRE(nodes.size() == 2, "Two commodity swap legs expected, found " << nodes.size());
189 legData_.clear();
190 for (Size i = 0; i < nodes.size(); i++) {
191 auto ld = createLegData();
192 ld->fromXML(nodes[i]);
193 legData_.push_back(*ld);
194 }
195}
196
198 XMLNode* node = Trade::toXML(doc);
199
200 // Add the root CommoditySwaptionData node
201 XMLNode* swaptionNode = doc.allocNode("CommoditySwaptionData");
202 XMLUtils::appendNode(node, swaptionNode);
203
204 // Add the OptionData node
205 XMLUtils::appendNode(swaptionNode, option_.toXML(doc));
206
207 // Add the LegData nodes
208 for (Size i = 0; i < legData_.size(); i++)
209 XMLUtils::appendNode(swaptionNode, legData_[i].toXML(doc));
210
211 return node;
212}
213
214} // namespace data
215} // namespace ore
Engine builder for commodity swaps.
Engine builder for commodity swaptions.
vector< ore::data::LegData > legData_
ore::data::OptionData option_
virtual void fromXML(ore::data::XMLNode *node) override
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
Add underlying Commodity names.
QuantLib::ext::shared_ptr< QuantLib::Exercise > exercise_
QuantLib::Real notional() const override
Return the current notional in npvCurrency. See individual sub-classes for the precise definition.
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory) override
QuantLib::ext::shared_ptr< CommoditySwap > commoditySwap_
virtual ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
QuantLib::ext::shared_ptr< ore::data::LegData > createLegData() const
QuantLib::ext::shared_ptr< QuantLib::Swap > buildSwap(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &engineFactory)
const string & settlementMethod() const
Definition: optiondata.hpp:82
const string & longShort() const
Definition: optiondata.hpp:70
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 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
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
const Envelope & envelope() const
Definition: trade.hpp:135
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
Definition: trade.hpp:197
void reset()
Reset trade, clear all base class data. This does not reset accumulated timings for this trade.
Definition: trade.cpp:130
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 vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
Commodity swaption data model and serialization.
Settlement::Method parseSettlementMethod(const std::string &s)
Convert text to QuantLib::Settlement::Method.
Definition: parsers.cpp:450
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
QuantLib::ext::shared_ptr< Index > parseIndex(const string &s)
Convert std::string to QuantLib::Index.
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
Definition: parsers.cpp:434
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Wrapper for option instruments, tracks whether option has been exercised or not.
string conversion utilities