Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
defaultcurveconfig.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#include <ql/errors.hpp>
25
26#include <boost/algorithm/string.hpp>
27
28using QuantLib::Date;
29
30namespace ore {
31namespace data {
32
33DefaultCurveConfig::DefaultCurveConfig(const string& curveId, const string& curveDescription, const string& currency,
34 const std::map<int, Config>& configs)
35 : CurveConfig(curveId, curveDescription), currency_(currency), configs_(configs) {
38 // ensure priority in config is consistent to the key used in the map
39 for (auto& c : configs_)
40 c.second.priority() = c.first;
41}
42
43void DefaultCurveConfig::populateRequiredCurveIds(const std::string& discountCurveID,
44 const std::string& benchmarkCurveID, const std::string& sourceCurveID,
45 const std::vector<std::string>& multiSectionSourceCurveIds) {
46 if (!discountCurveID.empty())
47 requiredCurveIds_[CurveSpec::CurveType::Yield].insert(parseCurveSpec(discountCurveID)->curveConfigID());
48 if (!benchmarkCurveID.empty())
49 requiredCurveIds_[CurveSpec::CurveType::Yield].insert(parseCurveSpec(benchmarkCurveID)->curveConfigID());
50 if (!sourceCurveID.empty())
51 requiredCurveIds_[CurveSpec::CurveType::Yield].insert(parseCurveSpec(sourceCurveID)->curveConfigID());
52 for (auto const& s : multiSectionSourceCurveIds) {
53 if (!s.empty())
55 }
56}
57
59 for (auto const& config : configs_) {
60 populateRequiredCurveIds(config.second.discountCurveID(), config.second.benchmarkCurveID(),
61 config.second.sourceCurveID(), config.second.multiSectionSourceCurveIds());
62 }
63}
64
66 quotes_.clear();
67 for (auto const& config : configs_) {
68 for (const auto& kv : config.second.cdsQuotes()) {
69 quotes_.push_back(kv.first);
70 }
71 // recovery rate might be a hardcoded number, in which case we must not add this to the set of quotes
72 Real dummy;
73 if (!config.second.recoveryRateQuote().empty() && !tryParseReal(config.second.recoveryRateQuote(), dummy))
74 quotes_.insert(quotes_.begin(), config.second.recoveryRateQuote());
75 }
76}
77
79 XMLUtils::checkNode(node, "DefaultCurve");
80 curveID_ = XMLUtils::getChildValue(node, "CurveId", true);
81 curveDescription_ = XMLUtils::getChildValue(node, "CurveDescription", true);
82 currency_ = XMLUtils::getChildValue(node, "Currency", true);
83 if (auto configs = XMLUtils::getChildNode(node, "Configurations")) {
84 for (auto const& config : XMLUtils::getChildrenNodes(configs, "Configuration")) {
85 Config tmp;
86 tmp.fromXML(config);
87 QL_REQUIRE(configs_.find(tmp.priority()) == configs_.end(),
88 "DefaultCurveConfig::fromXML(): several configurations with same priority '" << tmp.priority()
89 << "' found.");
90 configs_[tmp.priority()] = tmp;
91 }
92 } else {
93 Config tmp;
94 tmp.fromXML(node);
95 configs_[0] = tmp;
96 }
99}
100
102 XMLNode* node = doc.allocNode("DefaultCurve");
103
104 XMLUtils::addChild(doc, node, "CurveId", curveID_);
105 XMLUtils::addChild(doc, node, "CurveDescription", curveDescription_);
106 XMLUtils::addChild(doc, node, "Currency", currency_);
107 auto configs = XMLUtils::addChild(doc, node, "Configurations");
108
109 for (auto& tmp : configs_) {
110 XMLUtils::appendNode(configs, tmp.second.toXML(doc));
111 }
112
113 return node;
114}
115
116DefaultCurveConfig::Config::Config(const Type& type, const string& discountCurveID, const string& recoveryRateQuote,
117 const DayCounter& dayCounter, const string& conventionID,
118 const std::vector<std::pair<std::string, bool>>& cdsQuotes, bool extrapolation,
119 const string& benchmarkCurveID, const string& sourceCurveID,
120 const std::vector<string>& pillars, const Calendar& calendar, const Size spotLag,
121 const Date& startDate, const BootstrapConfig& bootstrapConfig,
122 QuantLib::Real runningSpread, const QuantLib::Period& indexTerm,
123 const boost::optional<bool>& implyDefaultFromMarket, const bool allowNegativeRates,
124 const int priority)
125 : cdsQuotes_(cdsQuotes), type_(type), discountCurveID_(discountCurveID), recoveryRateQuote_(recoveryRateQuote),
126 dayCounter_(dayCounter), conventionID_(conventionID), extrapolation_(extrapolation),
127 benchmarkCurveID_(benchmarkCurveID), sourceCurveID_(sourceCurveID), pillars_(pillars), calendar_(calendar),
128 spotLag_(spotLag), startDate_(startDate), bootstrapConfig_(bootstrapConfig), runningSpread_(runningSpread),
129 indexTerm_(indexTerm), implyDefaultFromMarket_(implyDefaultFromMarket), allowNegativeRates_(allowNegativeRates),
130 priority_(priority) {}
131
133 auto prioStr = XMLUtils::getAttribute(node, "priority");
134 if (!prioStr.empty())
135 priority_ = parseInteger(prioStr);
136 cdsQuotes_.clear();
137 string type = XMLUtils::getChildValue(node, "Type", true);
138 if (type == "SpreadCDS") {
140 } else if (type == "HazardRate") {
142 } else if (type == "Price") {
144 } else if (type == "Benchmark") {
146 } else if (type == "MultiSection") {
148 } else if (type == "TransitionMatrix") {
150 } else if (type == "Null") {
152 } else {
153 QL_FAIL("Type " << type << " not recognized");
154 }
155 string dc = XMLUtils::getChildValue(node, "DayCounter", true);
157 extrapolation_ = XMLUtils::getChildValueAsBool(node, "Extrapolation"); // defaults to true
158 allowNegativeRates_ = false;
159 if (XMLNode* n = XMLUtils::getChildNode(node, "AllowNegativeRates")) {
161 }
162 if (type_ == Type::Benchmark) {
163 benchmarkCurveID_ = XMLUtils::getChildValue(node, "BenchmarkCurve", true);
164 sourceCurveID_ = XMLUtils::getChildValue(node, "SourceCurve", true);
165 pillars_ = XMLUtils::getChildrenValuesAsStrings(node, "Pillars", true);
166 spotLag_ = parseInteger(XMLUtils::getChildValue(node, "SpotLag", true));
167 calendar_ = parseCalendar(XMLUtils::getChildValue(node, "Calendar", true));
169 recoveryRateQuote_ = XMLUtils::getChildValue(node, "RecoveryRate", false);
170 } else if (type_ == Type::MultiSection) {
171 multiSectionSourceCurveIds_ = XMLUtils::getChildrenValues(node, "SourceCurves", "SourceCurve", true);
172 multiSectionSwitchDates_ = XMLUtils::getChildrenValues(node, "SwitchDates", "SwitchDate", true);
174 recoveryRateQuote_ = XMLUtils::getChildValue(node, "RecoveryRate", false);
175 } else if(type_ == Type::TransitionMatrix) {
176 initialState_ = XMLUtils::getChildValue(node, "InitialState", false);
177 states_ = parseListOfValues(XMLUtils::getChildValue(node, "States", false));
178 XMLNode* quotesNode = XMLUtils::getChildNode(node, "Quotes");
179 if (quotesNode) {
180 for (auto n : XMLUtils::getChildrenNodes(quotesNode, "Quote")) {
181 string attr = XMLUtils::getAttribute(n, "optional");
182 bool opt = (!attr.empty() && parseBool(attr));
183 cdsQuotes_.emplace_back(make_pair(XMLUtils::getNodeValue(n), opt));
184 }
185 }
186 recoveryRateQuote_ = XMLUtils::getChildValue(node, "RecoveryRate", false);
187 } else {
188 discountCurveID_ = XMLUtils::getChildValue(node, "DiscountCurve", false);
189 conventionID_ = XMLUtils::getChildValue(node, "Conventions", true);
190 XMLNode* quotesNode = XMLUtils::getChildNode(node, "Quotes");
191 if (quotesNode) {
192 for (auto n : XMLUtils::getChildrenNodes(quotesNode, "Quote")) {
193 string attr = XMLUtils::getAttribute(n, "optional");
194 bool opt = (!attr.empty() && parseBool(attr));
195 cdsQuotes_.emplace_back(make_pair(XMLUtils::getNodeValue(n), opt));
196 }
197 }
198 recoveryRateQuote_ = XMLUtils::getChildValue(node, "RecoveryRate", false);
200 calendar_ = Calendar();
201 spotLag_ = 0;
202 pillars_.clear();
203 // Read the optional start date
204 string d = XMLUtils::getChildValue(node, "StartDate", false);
205 if (d != "") {
206 if (type_ == Type::SpreadCDS || type_ == Type::Price) {
208 } else {
209 WLOG("'StartDate' is only used when type is 'SpreadCDS' or 'Price'");
210 }
211 }
212 string s = XMLUtils::getChildValue(node, "RunningSpread", false);
213 if (s.empty() && type_ == Type::Price) {
214 DLOG("'RunningSpread' is empty and type is 'Price' for default curve "
215 "so the running spread will need to be provided in the market quote.");
216 }
217 if (!s.empty()) {
219 }
220 string t = XMLUtils::getChildValue(node, "IndexTerm", false);
221 indexTerm_ = t.empty() ? 0 * Days : parsePeriod(t);
222 implyDefaultFromMarket_ = boost::none;
223 if (XMLNode* n = XMLUtils::getChildNode(node, "ImplyDefaultFromMarket"))
225 // Optional bootstrap configuration
226 if (XMLNode* n = XMLUtils::getChildNode(node, "BootstrapConfig")) {
228 }
229 }
230}
231
233 XMLNode* node = doc.allocNode("Configuration");
234 XMLUtils::addAttribute(doc, node, "priority", std::to_string(priority_));
235 if (type_ == Type::SpreadCDS || type_ == Type::HazardRate || type_ == Type::Price) {
236 if (type_ == Type::SpreadCDS) {
237 XMLUtils::addChild(doc, node, "Type", "SpreadCDS");
238 } else if (type_ == Type::HazardRate) {
239 XMLUtils::addChild(doc, node, "Type", "HazardRate");
240 } else {
241 XMLUtils::addChild(doc, node, "Type", "Price");
242 }
243 XMLUtils::addChild(doc, node, "DiscountCurve", discountCurveID_);
244 XMLUtils::addChild(doc, node, "DayCounter", to_string(dayCounter_));
245 XMLUtils::addChild(doc, node, "RecoveryRate", recoveryRateQuote_);
246 XMLNode* quotesNode = XMLUtils::addChild(doc, node, "Quotes");
247 for (auto q : cdsQuotes_) {
248 XMLNode* qNode = doc.allocNode("Quote", q.first);
249 if (q.second)
250 XMLUtils::addAttribute(doc, qNode, "optional", "true");
251 XMLUtils::appendNode(quotesNode, qNode);
252 }
253 } else if (type_ == Type::Benchmark) {
254 XMLUtils::addChild(doc, node, "Type", "Benchmark");
255 XMLUtils::addChild(doc, node, "DayCounter", to_string(dayCounter_));
256 XMLUtils::addChild(doc, node, "RecoveryRate", recoveryRateQuote_);
257 XMLUtils::addChild(doc, node, "BenchmarkCurve", benchmarkCurveID_);
258 XMLUtils::addChild(doc, node, "SourceCurve", sourceCurveID_);
259 XMLUtils::addGenericChildAsList(doc, node, "Pillars", pillars_);
260 XMLUtils::addChild(doc, node, "SpotLag", (int)spotLag_);
261 XMLUtils::addChild(doc, node, "Calendar", calendar_.name());
262 } else if (type_ == Type::MultiSection) {
263 XMLUtils::addChild(doc, node, "RecoveryRate", recoveryRateQuote_);
264 XMLUtils::addChildren(doc, node, "SourceCurves", "SourceCurve", multiSectionSourceCurveIds_);
265 XMLUtils::addChildren(doc, node, "SwitchDates", "SwitchDate", multiSectionSwitchDates_);
266 } else if ( type_ == Type::TransitionMatrix) {
267 XMLUtils::addChild(doc, node, "InitialState", initialState_);
268 XMLUtils::addChild(doc, node, "States", boost::algorithm::join(states_, ","));
269 } else if (type_ == Type::Null) {
270 XMLUtils::addChild(doc, node, "Type", "Null");
271 XMLUtils::addChild(doc, node, "DayCounter", to_string(dayCounter_));
272 XMLUtils::addChild(doc, node, "DiscountCurve", discountCurveID_);
273 } else {
274 QL_FAIL("Unknown type in DefaultCurveConfig::toXML()");
275 }
276 XMLUtils::addChild(doc, node, "Conventions", conventionID_);
277 XMLUtils::addChild(doc, node, "Extrapolation", extrapolation_);
278 if (startDate_ != Date())
279 XMLUtils::addChild(doc, node, "StartDate", to_string(startDate_));
280 if (runningSpread_ != QuantLib::Null<Real>())
281 XMLUtils::addChild(doc, node, "RunningSpread", to_string(runningSpread_));
282 if (indexTerm_ != 0 * Days) {
283 XMLUtils::addChild(doc, node, "IndexTerm", indexTerm_);
284 }
285 if (implyDefaultFromMarket_)
286 XMLUtils::addChild(doc, node, "ImplyDefaultFromMarket", *implyDefaultFromMarket_);
287 XMLUtils::appendNode(node, bootstrapConfig_.toXML(doc));
288 XMLUtils::addChild(doc, node, "AllowNegativeRates", allowNegativeRates_);
289 return node;
290}
291
292} // namespace data
293} // namespace ore
void fromXML(ore::data::XMLNode *node) override
Base curve configuration.
Definition: curveconfig.hpp:41
vector< string > quotes_
Definition: curveconfig.hpp:74
map< CurveSpec::CurveType, set< string > > requiredCurveIds_
Definition: curveconfig.hpp:75
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
boost::optional< bool > implyDefaultFromMarket_
std::vector< std::pair< std::string, bool > > cdsQuotes_
Quote and optional flag pair.
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
const std::map< int, Config > & configs() const
std::map< int, Config > configs_
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 addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
Definition: xmlutils.cpp:412
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
Definition: xmlutils.cpp:502
static string getAttribute(XMLNode *node, const string &attrName)
Definition: xmlutils.cpp:419
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 vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
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 vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:306
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.
Default curve configuration classes.
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
bool tryParseReal(const string &s, QuantLib::Real &result)
Attempt to convert text to Real.
Definition: parsers.cpp:126
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
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
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Calendar calendar
Definition: utilities.cpp:441
std::vector< string > parseListOfValues(string s, const char escape, const char delim, const char quote)
Definition: parsers.cpp:639
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
string conversion utilities