Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
capfloorvolcurveconfig.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
24
25#include <ql/errors.hpp>
26
27#include <boost/algorithm/string.hpp>
28#include <boost/assign.hpp>
29#include <boost/bimap.hpp>
30
31using boost::assign::list_of;
32using QuantLib::BusinessDayConvention;
34using QuantLib::DayCounter;
35using QuantLib::Natural;
36using std::ostream;
37using std::set;
38using std::string;
39using std::vector;
40
41namespace ore {
42namespace data {
43
44typedef boost::bimap<string, CapFloorVolatilityCurveConfig::VolatilityType> BmType;
46 list_of<BmType::value_type>("Normal", CapFloorVolatilityCurveConfig::VolatilityType::Normal)(
49
50// Allowable interpolation strings for time and strike interpolation
51// BackwardFlat is not allowed for strike interpolation but that is handled elsewhere.
52const set<string> validInterps = {"Linear", "LinearFlat", "BackwardFlat", "Cubic", "CubicFlat"};
53
55 const string& curveID, const string& curveDescription, const VolatilityType& volatilityType, bool extrapolate,
56 bool flatExtrapolation, bool inlcudeAtm, const vector<string>& tenors, const vector<string>& strikes,
57 const DayCounter& dayCounter, Natural settleDays, const Calendar& calendar,
58 const BusinessDayConvention& businessDayConvention, const std::string& index,
59 const QuantLib::Period& rateComputationPeriod, const Size onCapSettlementDays, const string& discountCurve,
60 const string& interpolationMethod, const string& interpolateOn, const string& timeInterpolation,
61 const string& strikeInterpolation, const vector<string>& atmTenors, const BootstrapConfig& bootstrapConfig,
62 const string& inputType, const boost::optional<ParametricSmileConfiguration>& parametricSmileConfiguration)
63 : CurveConfig(curveID, curveDescription), volatilityType_(volatilityType), extrapolate_(extrapolate),
64 flatExtrapolation_(flatExtrapolation), includeAtm_(inlcudeAtm), tenors_(tenors), strikes_(strikes),
65 dayCounter_(dayCounter), settleDays_(settleDays), calendar_(calendar),
66 businessDayConvention_(businessDayConvention), index_(index), rateComputationPeriod_(rateComputationPeriod),
67 onCapSettlementDays_(onCapSettlementDays), discountCurve_(discountCurve),
68 interpolationMethod_(interpolationMethod), interpolateOn_(interpolateOn), timeInterpolation_(timeInterpolation),
69 strikeInterpolation_(strikeInterpolation), atmTenors_(atmTenors), bootstrapConfig_(bootstrapConfig),
70 inputType_(inputType), parametricSmileConfiguration_(parametricSmileConfiguration) {
71
72 // Set extrapolation string. "Linear" just means extrapolation allowed and non-flat.
73 extrapolation_ = !extrapolate_ ? "None" : (flatExtrapolation_ ? "Flat" : "Linear");
74
75 // Set type_
76 configureType();
77
78 // Check that we have a valid configuration
79 validate();
80
81 // Populate required curve ids
82 populateRequiredCurveIds();
83
84 // Populate quotes
85 populateQuotes();
86}
87
89 const std::string& curveID, const std::string& curveDescription, const std::string& proxySourceCurveId,
90 const std::string& proxySourceIndex, const std::string& proxyTargetIndex,
91 const QuantLib::Period& proxySourceRateComputationPeriod, const QuantLib::Period& proxyTargetRateComputationPeriod)
92 : CurveConfig(curveID, curveDescription), proxySourceCurveId_(proxySourceCurveId),
93 proxySourceIndex_(proxySourceIndex), proxyTargetIndex_(proxyTargetIndex),
94 proxySourceRateComputationPeriod_(proxySourceRateComputationPeriod),
95 proxyTargetRateComputationPeriod_(proxyTargetRateComputationPeriod) {
97}
98
100
101 XMLUtils::checkNode(node, "CapFloorVolatility");
102 curveID_ = XMLUtils::getChildValue(node, "CurveId", true);
103 curveDescription_ = XMLUtils::getChildValue(node, "CurveDescription", true);
104
105 if (auto p = XMLUtils::getChildNode(node, "ProxyConfig")) {
106 // read in proxy config
107
108 auto source = XMLUtils::getChildNode(p, "Source");
109 QL_REQUIRE(source != nullptr,
110 "CapFloorVolatilityCurveConfig (" << curveID_ << "): ProxyConfig requires child node 'Source'");
111 proxySourceCurveId_ = XMLUtils::getChildValue(source, "CurveId", true);
112 proxySourceIndex_ = XMLUtils::getChildValue(source, "Index", true);
114 parsePeriod(XMLUtils::getChildValue(source, "RateComputationPeriod", false, "0D"));
115
116 auto target = XMLUtils::getChildNode(p, "Target");
117 QL_REQUIRE(target != nullptr,
118 "CapFloorVolatilityCurveConfig (" << curveID_ << "): ProxyConfig requires child node 'Target'");
119 proxyTargetIndex_ = index_ = XMLUtils::getChildValue(target, "Index", true);
121 parsePeriod(XMLUtils::getChildValue(target, "RateComputationPeriod", false, "0D"));
122 onCapSettlementDays_ = parseInteger(XMLUtils::getChildValue(target, "ONCapSettlementDays", false, "0"));
123
125
126 } else {
127 // read in quote-based config
128
129 // Set the volatility type
130 configureVolatilityType(XMLUtils::getChildValue(node, "VolatilityType", true));
131
132 // Set the extrapolation variables
133 extrapolation_ = XMLUtils::getChildValue(node, "Extrapolation", true);
135
136 // The mandatory variables
137 includeAtm_ = XMLUtils::getChildValueAsBool(node, "IncludeAtm", true);
138 calendar_ = parseCalendar(XMLUtils::getChildValue(node, "Calendar", true));
139 dayCounter_ = parseDayCounter(XMLUtils::getChildValue(node, "DayCounter", true));
141 parseBusinessDayConvention(XMLUtils::getChildValue(node, "BusinessDayConvention", true));
142 if (auto iborNode = XMLUtils::getChildNode(node, "IborIndex")) {
143 WLOG("CapFloorVolatilityCurveConfig (" << curveID_
144 << "): The IborIndex node is deprecated, use Index instead.");
145 index_ = XMLUtils::getNodeValue(iborNode);
146 } else if (auto indexNode = XMLUtils::getChildNode(node, "Index")) {
147 index_ = XMLUtils::getNodeValue(indexNode);
148 } else {
149 QL_FAIL("CapFloorVOlatilityCurveConfig (" << curveID_
150 << "): Index node (or the deprecated IborIndex node) expected");
151 }
152 discountCurve_ = XMLUtils::getChildValue(node, "DiscountCurve", true);
153
154 // rate computation period, only required for OIS indices (which we don't check here)
155 rateComputationPeriod_ = 0 * Days;
156 if (auto rcpNode = XMLUtils::getChildNode(node, "RateComputationPeriod")) {
158 }
159
160 // on cap settlement days, optional and only relevant for OIS indices
162 if (auto onsNode = XMLUtils::getChildNode(node, "ONCapSettlementDays")) {
164 }
165
166 // Settlement days (optional)
167 settleDays_ = 0;
168 if (XMLNode* n = XMLUtils::getChildNode(node, "SettlementDays")) {
169 Integer d = parseInteger(XMLUtils::getNodeValue(n));
170 QL_REQUIRE(d >= 0, "SettlementDays (" << d << ") must be non-negative");
171 settleDays_ = static_cast<Natural>(d);
172 }
173
174 // Variable on which to interpolate (optional)
175 interpolateOn_ = "TermVolatilities";
176 if (XMLNode* n = XMLUtils::getChildNode(node, "InterpolateOn")) {
178 }
179
180 // Interpolation in time direction (optional)
181 timeInterpolation_ = "LinearFlat";
182 if (XMLNode* n = XMLUtils::getChildNode(node, "TimeInterpolation")) {
184 }
185
186 // Interpolation in strike direction (optional)
187 strikeInterpolation_ = "LinearFlat";
188 if (XMLNode* n = XMLUtils::getChildNode(node, "StrikeInterpolation")) {
190 }
191
192 quoteIncludesIndexName_ = XMLUtils::getChildValueAsBool(node, "QuoteIncludesIndexName", false, false);
193
194 // Tenors and strikes. Optional as we may have an ATM curve and hence only AtmTenors.
195 tenors_ = XMLUtils::getChildrenValuesAsStrings(node, "Tenors", false);
196 strikes_ = XMLUtils::getChildrenValuesAsStrings(node, "Strikes", false);
197
198 // Optional flag, if set to true some tenor/strike quotes can be omitted
199 optionalQuotes_ = XMLUtils::getChildValueAsBool(node, "OptionalQuotes", false, false);
200
201 // Interpolation for cap floor term volatilities (optional)
202 interpolationMethod_ = "BicubicSpline";
203 if (XMLNode* n = XMLUtils::getChildNode(node, "InterpolationMethod")) {
205 }
206
207 // Tenors for ATM volatilities.
208 atmTenors_ = XMLUtils::getChildrenValuesAsStrings(node, "AtmTenors", false);
209 QL_REQUIRE(!tenors_.empty() || !atmTenors_.empty(), "Tenors and AtmTenors cannot both be empty");
210 if (atmTenors_.empty()) {
212 }
213
214 // Optional bootstrap configuration
215 if (XMLNode* n = XMLUtils::getChildNode(node, "BootstrapConfig")) {
217 }
218
219 // Optional parametric smile configuration
220 if(XMLNode* n = XMLUtils::getChildNode(node, "ParametricSmileConfiguration")) {
223 }
224
225 // Optional Input Type
226 inputType_ = "TermVolatilities";
227 if (XMLNode* n = XMLUtils::getChildNode(node, "InputType")) {
229 }
230
231 // Set type_
233
234 // Check that we have a valid configuration
235 validate();
236
237 // Populate quotes
239
240 // Populate required curve ids
242 }
243
244 // Optional report config
245 if (auto tmp = XMLUtils::getChildNode(node, "Report")) {
247 }
248}
249
251
252 XMLNode* node = doc.allocNode("CapFloorVolatility");
253 XMLUtils::addChild(doc, node, "CurveId", curveID_);
254 XMLUtils::addChild(doc, node, "CurveDescription", curveDescription_);
255
256 if (!proxySourceCurveId_.empty()) {
257 // write out proxy config
258 auto proxy = XMLUtils::addChild(doc, node, "ProxyConfig");
259 auto source = XMLUtils::addChild(doc, proxy, "Source");
260 auto target = XMLUtils::addChild(doc, proxy, "Target");
261 XMLUtils::addChild(doc, source, "CurveId", proxySourceCurveId_);
262 XMLUtils::addChild(doc, source, "Index", proxySourceIndex_);
263 XMLUtils::addChild(doc, target, "Index", proxyTargetIndex_);
264 if (proxySourceRateComputationPeriod_ != 0 * Days)
265 XMLUtils::addChild(doc, source, "RateComputationPeriod", proxySourceRateComputationPeriod_);
266 if (proxyTargetRateComputationPeriod_ != 0 * Days)
267 XMLUtils::addChild(doc, target, "RateComputationPeriod", proxyTargetRateComputationPeriod_);
268 } else {
269 // write out quote based config
270 XMLUtils::addChild(doc, node, "VolatilityType", toString(volatilityType_));
271 XMLUtils::addChild(doc, node, "Extrapolation", extrapolation_);
272 XMLUtils::addChild(doc, node, "InterpolationMethod", interpolationMethod_);
273 XMLUtils::addChild(doc, node, "IncludeAtm", includeAtm_);
274 XMLUtils::addChild(doc, node, "DayCounter", to_string(dayCounter_));
275 XMLUtils::addChild(doc, node, "Calendar", to_string(calendar_));
276 XMLUtils::addChild(doc, node, "BusinessDayConvention", to_string(businessDayConvention_));
277 XMLUtils::addGenericChildAsList(doc, node, "Tenors", tenors_);
278 XMLUtils::addGenericChildAsList(doc, node, "Strikes", strikes_);
279 XMLUtils::addChild(doc, node, "OptionalQuotes", optionalQuotes_);
280 XMLUtils::addChild(doc, node, "Index", index_);
281 if (rateComputationPeriod_ != 0 * Days) {
282 XMLUtils::addChild(doc, node, "RateComputationPeriod", rateComputationPeriod_);
283 }
284 if (onCapSettlementDays_ != 0) {
285 XMLUtils::addChild(doc, node, "ONCapSettlementDays", (int)onCapSettlementDays_);
286 }
287 XMLUtils::addChild(doc, node, "DiscountCurve", discountCurve_);
288 XMLUtils::addGenericChildAsList(doc, node, "AtmTenors", atmTenors_);
289 XMLUtils::addChild(doc, node, "SettlementDays", static_cast<int>(settleDays_));
290 XMLUtils::addChild(doc, node, "InterpolateOn", interpolateOn_);
291 XMLUtils::addChild(doc, node, "TimeInterpolation", timeInterpolation_);
292 XMLUtils::addChild(doc, node, "StrikeInterpolation", strikeInterpolation_);
293 XMLUtils::addChild(doc, node, "QuoteIncludesIndexName", quoteIncludesIndexName_);
295 XMLUtils::addChild(doc, node, "InputType", inputType_);
296 }
297
299 return node;
300}
301
303 if (interpolationMethod_ == "BicubicSpline") {
304 return QuantExt::CapFloorTermVolSurfaceExact::InterpolationMethod::BicubicSpline;
305 } else if (interpolationMethod_ == "Bilinear") {
306 return QuantExt::CapFloorTermVolSurfaceExact::InterpolationMethod::Bilinear;
307 } else {
308 QL_FAIL("Invalid InterpolationMethod " << interpolationMethod_);
309 }
310}
311
313 QL_REQUIRE(volatilityTypeMap.right.count(type) > 0,
314 "Volatility type (" << static_cast<int>(type) << ") is not valid");
315 return volatilityTypeMap.right.at(type);
316}
317
319 if (!discountCurve().empty())
321 if (!proxySourceCurveId_.empty())
323 parseCurveSpec(proxySourceCurveId_)->curveConfigID());
324 if (!proxySourceIndex_.empty())
326 if (!proxyTargetIndex_.empty())
328}
329
331 string tenor;
332 QuantLib::ext::shared_ptr<IborIndex> index = parseIborIndex(index_, tenor);
333 // for ON indices we get back an empty string
334 if (tenor.empty())
335 tenor = "1D";
336 return tenor;
337}
338
340 string tenor;
341 // Ibor index term and currency (do not allow for convention based ibor indices here)
342 auto index = parseIborIndex(index_, tenor);
343 return index->currency().code();
344}
345
347
348 // Cap floor quotes are for the form:
349 // CAPFLOOR/(RATE_LNVOL|RATE_NVOL|RATE_SLNVOL)/<CCY>/<TENOR>/<IBOR_TENOR>/<ATM>/<RELATIVE>/<STRIKE> or
350 // CAPFLOOR/(RATE_LNVOL|RATE_NVOL|RATE_SLNVOL)/<CCY>/<IndexName>/<TENOR>/<IBOR_TENOR>/<ATM>/<RELATIVE>/<STRIKE>
351 string ccy = currency();
352 string tenor = indexTenor();
353
354 // Volatility quote stem
356 string stem = "CAPFLOOR/" + to_string(qType) + "/" + ccy + "/";
358 stem += index() + "/";
359
360 // Cap floor matrix quotes. So, ATM flag is false i.e. 0 and RELATIVE flag is false also as strikes are absolute.
361 for (const string& t : tenors_) {
362 for (const string& s : strikes_) {
363 quotes_.push_back(stem + t + "/" + tenor + "/0/0/" + s);
364 }
365 }
366
367 // ATM quotes. So, ATM flag is true i.e. 1 and RELATIVE flag is true with strike set to 0.
369 for (const string& t : atmTenors_) {
370 quotes_.push_back(stem + t + "/" + tenor + "/1/1/0");
371 }
372 }
373
374 // Cap floor shift quote depends only on the currency and ibor tenor and is of the form:
375 // CAPFLOOR/SHIFT/<CCY>/<IBOR_TERM> or
376 // CAPFLOOR/SHIFT/<CCY>/<IndexName>/<IBOR_TERM> or
378 quotes_.push_back("CAPFLOOR/SHIFT/" + ccy + "/" + (quoteIncludesIndexName() ? index() + "/" : "") + tenor);
379 }
380}
381
383 QL_REQUIRE(extrapolation == "Linear" || extrapolation == "Flat" || extrapolation == "None",
384 "Extrapolation must be one of Linear, Flat or None");
385 extrapolate_ = extrapolation == "None" ? false : true;
386 flatExtrapolation_ = extrapolation == "Linear" ? false : true;
387}
388
390 QL_REQUIRE(volatilityTypeMap.left.count(type) > 0, "Volatility type value '" << type << "' is not valid");
392}
393
395 if (inputType_ == "TermVolatilities")
397 else if (inputType_ == "OptionletVolatilities")
399 else
400 QL_FAIL("InputType " << inputType_ << " not supported");
401}
402
404 QL_REQUIRE(interpolateOn_ == "TermVolatilities" || interpolateOn_ == "OptionletVolatilities",
405 "InterpolateOn (" << interpolateOn_ << ") must be TermVolatilities or OptionletVolatilities");
406 QL_REQUIRE(validInterps.count(timeInterpolation_) == 1,
407 "TimeInterpolation, " << timeInterpolation_ << ", not recognised");
408 QuantExt::SabrParametricVolatility::ModelVariant dummySabrVariant;
409 QL_REQUIRE(validInterps.count(strikeInterpolation_) == 1 ||
410 tryParse(strikeInterpolation_, dummySabrVariant,
411 std::function<QuantExt::SabrParametricVolatility::ModelVariant(const std::string&)>(
412 [](const std::string& s) { return parseSabrParametricVolatilityModelVariant(s); })),
413 "StrikeInterpolation, " << strikeInterpolation_ << ", not recognised");
414 QL_REQUIRE(strikeInterpolation_ != "BackwardFlat", "BackwardFlat StrikeInterpolation is not allowed");
415 if (!strikes_.empty()) {
416 QL_REQUIRE(!tenors_.empty(), "Tenors must be given for a surface (strikes are given)");
417 }
418}
419
421 switch (volatilityType_) {
428 default:
429 QL_FAIL("Unknown VolatilityType (" << static_cast<int>(volatilityType_) << ")");
430 }
431}
432
434 switch (type) {
437 return ShiftedLognormal;
439 return Normal;
440 default:
441 QL_FAIL("Unknown VolatilityType (" << static_cast<int>(type) << ")");
442 }
443}
444
445} // namespace data
446} // namespace ore
Cap floor volatility curve configuration class.
void fromXML(ore::data::XMLNode *node) override
ore::data::XMLNode * toXML(ore::data::XMLDocument &doc) const override
void populateRequiredCurveIds()
Populate required curve ids.
void configureVolatilityType(const std::string &type)
Set the value of volatilityType_ based on the value of type.
void populateQuotes()
Populate the quotes vector.
void configureType()
Set the value of type_ i.e. the type of cap floor structure that is configured.
XMLNode * toXML(XMLDocument &doc) const override
VolatilityType
The type of volatility quotes that have been configured.
QuantLib::BusinessDayConvention businessDayConvention_
void configureExtrapolation(const std::string &extrapolation)
void validate() const
Validate the configuration.
QuantExt::CapFloorTermVolSurfaceExact::InterpolationMethod interpolationMethod() const
boost::optional< ParametricSmileConfiguration > parametricSmileConfiguration_
std::string toString(VolatilityType type) const
Convert VolatilityType type to string.
Base curve configuration.
Definition: curveconfig.hpp:41
vector< string > quotes_
Definition: curveconfig.hpp:74
map< CurveSpec::CurveType, set< string > > requiredCurveIds_
Definition: curveconfig.hpp:75
QuoteType
Supported market quote types.
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static void addGenericChildAsList(XMLDocument &doc, XMLNode *n, const string &name, const vector< T > &values, const string &attrName="", const string &attr="")
Definition: xmlutils.hpp:144
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
Definition: xmlutils.cpp:296
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static string getNodeValue(XMLNode *node)
Get a node's value.
Definition: xmlutils.cpp:489
static vector< string > getChildrenValuesAsStrings(XMLNode *node, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:342
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
CurveSpec parser.
QuantLib::ext::shared_ptr< CurveSpec > parseCurveSpec(const string &s)
function to convert a string into a curve spec
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
bool tryParse(const std::string &str, T &obj, std::function< T(const std::string &)> parser)
Definition: parsers.hpp:427
SabrParametricVolatility::ModelVariant parseSabrParametricVolatilityModelVariant(const std::string &s)
Parse SabrParametricVolatility::ModelVariant.
Definition: parsers.cpp:1458
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
Map text representations to QuantLib/QuantExt types.
@ data
Definition: log.hpp:77
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Calendar calendar
Definition: utilities.cpp:441
boost::bimap< string, CapFloorVolatilityCurveConfig::VolatilityType > BmType
VolatilityType volatilityType(CapFloorVolatilityCurveConfig::VolatilityType type)
Imply QuantLib::VolatilityType from CapFloorVolatilityCurveConfig::VolatilityType.
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
const set< string > validInterps
const BmType volatilityTypeMap
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
vector< Real > strikes
string conversion utilities