Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
commoditycurveconfig.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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
21#include <limits>
22
23using std::string;
24using std::vector;
25
26namespace ore {
27namespace data {
28
30
31PriceSegment::OffPeakDaily::OffPeakDaily(const vector<string>& offPeakQuotes,
32 const vector<string>& peakQuotes) : offPeakQuotes_(offPeakQuotes), peakQuotes_(peakQuotes) {}
33
35 XMLUtils::checkNode(node, "OffPeakDaily");
36 offPeakQuotes_ = XMLUtils::getChildrenValues(node, "OffPeakQuotes", "Quote", true);
37 peakQuotes_ = XMLUtils::getChildrenValues(node, "PeakQuotes", "Quote", true);
38}
39
41
42 XMLNode* node = doc.allocNode("OffPeakDaily");
43 XMLUtils::addChildren(doc, node, "OffPeakQuotes", "Quote", offPeakQuotes_);
44 XMLUtils::addChildren(doc, node, "PeakQuotes", "Quote", peakQuotes_);
45
46 return node;
47}
48
50
51PriceSegment::PriceSegment(const string& type, const string& conventionsId, const vector<string>& quotes,
52 const boost::optional<unsigned short>& priority, const boost::optional<OffPeakDaily>& offPeakDaily,
53 const string& peakPriceCurveId, const string& peakPriceCalendar)
54 : strType_(type), conventionsId_(conventionsId), quotes_(quotes), priority_(priority),
55 offPeakDaily_(offPeakDaily), peakPriceCurveId_(peakPriceCurveId),
56 peakPriceCalendar_(peakPriceCalendar), empty_(false), type_(parsePriceSegmentType(strType_)) {
58 QL_REQUIRE(offPeakDaily_, "When price segment type is OffPeakPowerDaily, OffPeakDaily is required.");
60 }
61}
62
64 return type_;
65}
66
67const string& PriceSegment::conventionsId() const {
68 return conventionsId_;
69}
70
71const vector<string>& PriceSegment::quotes() const {
72 return quotes_;
73}
74
75const boost::optional<unsigned short>& PriceSegment::priority() const {
76 return priority_;
77}
78
79const boost::optional<PriceSegment::OffPeakDaily>& PriceSegment::offPeakDaily() const {
80 return offPeakDaily_;
81}
82
83const string& PriceSegment::peakPriceCurveId() const {
84 return peakPriceCurveId_;
85}
86
87const string& PriceSegment::peakPriceCalendar() const {
88 return peakPriceCalendar_;
89}
90
91bool PriceSegment::empty() const {
92 return empty_;
93}
94
96
97 XMLUtils::checkNode(node, "PriceSegment");
98 strType_ = XMLUtils::getChildValue(node, "Type", true);
100 conventionsId_ = XMLUtils::getChildValue(node, "Conventions", true);
101
102 if (XMLNode* n = XMLUtils::getChildNode(node, "Priority")) {
104 }
105
107 quotes_ = XMLUtils::getChildrenValues(node, "Quotes", "Quote", true);
108 peakPriceCurveId_ = XMLUtils::getChildValue(node, "PeakPriceCurveId", false);
109 peakPriceCalendar_ = XMLUtils::getChildValue(node, "PeakPriceCalendar", false);
110 } else {
111 XMLNode* n = XMLUtils::getChildNode(node, "OffPeakDaily");
112 QL_REQUIRE(n, "When price segment type is OffPeakPowerDaily, an OffPeakDaily node is required.");
114 offPeakDaily_->fromXML(n);
116 }
117
118 empty_ = false;
119}
120
122 // Populate the quotes_ with the off-peak and peak quotes
123 const auto& opqs = offPeakDaily_->offPeakQuotes();
124 set<string> quotes{ opqs.begin(), opqs.end() };
125 const auto& pqs = offPeakDaily_->peakQuotes();
126 quotes.insert(pqs.begin(), pqs.end());
127 quotes_.assign(quotes.begin(), quotes.end());
128}
129
131
132 XMLNode* node = doc.allocNode("PriceSegment");
133 XMLUtils::addChild(doc, node, "Type", strType_);
134 if (priority_) {
135 XMLUtils::addChild(doc, node, "Priority", *priority_);
136 }
137 XMLUtils::addChild(doc, node, "Conventions", conventionsId_);
138
139
141 XMLUtils::addChildren(doc, node, "Quotes", "Quote", quotes_);
142 if (!peakPriceCurveId_.empty()) {
143 XMLUtils::addChild(doc, node, "PeakPriceCurveId", peakPriceCurveId_);
144 }
145 if (!peakPriceCalendar_.empty()) {
146 XMLUtils::addChild(doc, node, "PeakPriceCalendar", peakPriceCalendar_);
147 }
148 } else {
149 XMLUtils::appendNode(node, offPeakDaily_->toXML(doc));
150 }
151
152 return node;
153}
154
155CommodityCurveConfig::CommodityCurveConfig(const string& curveId, const string& curveDescription,
156 const string& currency, const vector<string>& quotes,
157 const string& commoditySpotQuote, const string& dayCountId,
158 const string& interpolationMethod, bool extrapolation,
159 const string& conventionsId)
160 : CurveConfig(curveId, curveDescription), type_(Type::Direct), fwdQuotes_(quotes), currency_(currency),
161 commoditySpotQuoteId_(commoditySpotQuote), dayCountId_(dayCountId), interpolationMethod_(interpolationMethod),
162 extrapolation_(extrapolation), conventionsId_(conventionsId), addBasis_(true), monthOffset_(0),
163 averageBase_(true) {
164
165 quotes_ = quotes;
166 if (!commoditySpotQuote.empty()) {
167 quotes_.insert(quotes_.begin(), commoditySpotQuote);
168 }
169}
170
171CommodityCurveConfig::CommodityCurveConfig(const string& curveId, const string& curveDescription,
172 const string& currency, const string& basePriceCurveId,
173 const string& baseYieldCurveId, const string& yieldCurveId,
174 bool extrapolation)
175 : CurveConfig(curveId, curveDescription), type_(Type::CrossCurrency), currency_(currency),
176 basePriceCurveId_(basePriceCurveId), baseYieldCurveId_(baseYieldCurveId), yieldCurveId_(yieldCurveId),
177 extrapolation_(extrapolation), addBasis_(true), monthOffset_(0), averageBase_(true), priceAsHistFixing_(true) {
179}
180
181CommodityCurveConfig::CommodityCurveConfig(const string& curveId, const string& curveDescription,
182 const string& currency, const string& basePriceCurveId,
183 const string& baseConventionsId, const vector<string>& basisQuotes,
184 const string& basisConventionsId, const string& dayCountId,
185 const string& interpolationMethod, bool extrapolation, bool addBasis,
186 QuantLib::Natural monthOffset, bool averageBase)
187 : CurveConfig(curveId, curveDescription), type_(Type::Basis), fwdQuotes_(basisQuotes), currency_(currency),
188 dayCountId_(dayCountId), interpolationMethod_(interpolationMethod), basePriceCurveId_(basePriceCurveId),
189 extrapolation_(extrapolation), conventionsId_(basisConventionsId), baseConventionsId_(baseConventionsId),
190 addBasis_(addBasis), monthOffset_(monthOffset), averageBase_(averageBase), priceAsHistFixing_(true) {
192}
193
194CommodityCurveConfig::CommodityCurveConfig(const string& curveId, const string& curveDescription,
195 const string& currency, const vector<PriceSegment>& priceSegments,
196 const string& dayCountId, const string& interpolationMethod,
197 bool extrapolation, const boost::optional<BootstrapConfig>& bootstrapConfig)
198 : CurveConfig(curveId, curveDescription), type_(Type::Piecewise), currency_(currency), dayCountId_(dayCountId),
199 interpolationMethod_(interpolationMethod), extrapolation_(extrapolation), addBasis_(true), monthOffset_(0),
200 averageBase_(true), priceAsHistFixing_(true), bootstrapConfig_(bootstrapConfig) {
202}
203
205
206 XMLUtils::checkNode(node, "CommodityCurve");
207
208 curveID_ = XMLUtils::getChildValue(node, "CurveId", true);
209 curveDescription_ = XMLUtils::getChildValue(node, "CurveDescription", true);
210 currency_ = XMLUtils::getChildValue(node, "Currency", true);
211
212 if (XMLNode* n = XMLUtils::getChildNode(node, "BasisConfiguration")) {
213
215 basePriceCurveId_ = XMLUtils::getChildValue(n, "BasePriceCurve", true);
216 baseConventionsId_ = XMLUtils::getChildValue(n, "BasePriceConventions", true);
217 quotes_ = fwdQuotes_ = XMLUtils::getChildrenValues(n, "BasisQuotes", "Quote");
218 conventionsId_ = XMLUtils::getChildValue(n, "BasisConventions", true);
219 dayCountId_ = XMLUtils::getChildValue(n, "DayCounter", false);
220 interpolationMethod_ = XMLUtils::getChildValue(n, "InterpolationMethod", false);
221 addBasis_ = XMLUtils::getChildValueAsBool(n, "AddBasis", false);
222 monthOffset_ = XMLUtils::getChildValueAsInt(n, "MonthOffset", false);
223 averageBase_ = XMLUtils::getChildValueAsBool(n, "AverageBase", false);
224 priceAsHistFixing_ = XMLUtils::getChildValueAsBool(n, "PriceAsHistoricalFixing", false);
225 } else if (XMLNode* n = XMLUtils::getChildNode(node, "BasePriceCurve")) {
226
229 baseYieldCurveId_ = XMLUtils::getChildValue(node, "BaseYieldCurve", true);
230 yieldCurveId_ = XMLUtils::getChildValue(node, "YieldCurve", true);
231
232 } else if (XMLNode* n = XMLUtils::getChildNode(node, "PriceSegments")) {
233
234 vector<PriceSegment> priceSegments;
237 PriceSegment ps;
238 ps.fromXML(c);
239 priceSegments.push_back(ps);
240 }
242
243 dayCountId_ = XMLUtils::getChildValue(node, "DayCounter", false);
244 interpolationMethod_ = XMLUtils::getChildValue(node, "InterpolationMethod", false);
245
246 if (XMLNode* bcn = XMLUtils::getChildNode(node, "BootstrapConfig")) {
248 bootstrapConfig_->fromXML(bcn);
249 }
250
251 } else {
252
254 dayCountId_ = XMLUtils::getChildValue(node, "DayCounter", false);
255 commoditySpotQuoteId_ = XMLUtils::getChildValue(node, "SpotQuote", false);
256 fwdQuotes_ = XMLUtils::getChildrenValues(node, "Quotes", "Quote");
258 if (commoditySpotQuoteId_ != "")
259 quotes_.insert(quotes_.begin(), commoditySpotQuoteId_);
260
261 interpolationMethod_ = XMLUtils::getChildValue(node, "InterpolationMethod", false);
262 conventionsId_ = XMLUtils::getChildValue(node, "Conventions", false);
263 }
264
265 extrapolation_ = XMLUtils::getChildValueAsBool(node, "Extrapolation");
266
268}
269
271
272 XMLNode* node = doc.allocNode("CommodityCurve");
273
274 XMLUtils::addChild(doc, node, "CurveId", curveID_);
275 XMLUtils::addChild(doc, node, "CurveDescription", curveDescription_);
276 XMLUtils::addChild(doc, node, "Currency", currency_);
277
278 if (type_ == Type::Basis) {
279 XMLNode* basisNode = XMLUtils::addChild(doc, node, "BasisConfiguration");
280 XMLUtils::addChild(doc, basisNode, "BasePriceCurve", basePriceCurveId_);
281 XMLUtils::addChild(doc, basisNode, "BasePriceConventions", baseConventionsId_);
282 XMLUtils::addChildren(doc, basisNode, "BasisQuotes", "Quote", fwdQuotes_);
283 XMLUtils::addChild(doc, basisNode, "BasisConventions", conventionsId_);
284 XMLUtils::addChild(doc, basisNode, "DayCounter", dayCountId_);
285 XMLUtils::addChild(doc, basisNode, "InterpolationMethod", interpolationMethod_);
286 XMLUtils::addChild(doc, basisNode, "AddBasis", addBasis_);
287 XMLUtils::addChild(doc, basisNode, "MonthOffset", static_cast<int>(monthOffset_));
288 XMLUtils::addChild(doc, basisNode, "AverageBase", averageBase_);
289 XMLUtils::addChild(doc, basisNode, "PriceAsHistoricalFixing", priceAsHistFixing_);
290
291 } else if (type_ == Type::CrossCurrency) {
292
293 XMLUtils::addChild(doc, node, "BasePriceCurve", basePriceCurveId_);
294 XMLUtils::addChild(doc, node, "BaseYieldCurve", baseYieldCurveId_);
295 XMLUtils::addChild(doc, node, "YieldCurve", yieldCurveId_);
296
297 } else if (type_ == Type::Piecewise) {
298
299 // Add the price segment nodes.
300 XMLNode* segmentsNode = doc.allocNode("PriceSegments");
301 for (auto& kv : priceSegments_) {
302 XMLUtils::appendNode(segmentsNode, kv.second.toXML(doc));
303 }
304 XMLUtils::appendNode(node, segmentsNode);
305
306 XMLUtils::addChild(doc, node, "DayCounter", dayCountId_);
307 XMLUtils::addChild(doc, node, "InterpolationMethod", interpolationMethod_);
308
309 } else {
310
311 if (!commoditySpotQuoteId_.empty())
312 XMLUtils::addChild(doc, node, "SpotQuote", commoditySpotQuoteId_);
313 XMLUtils::addChildren(doc, node, "Quotes", "Quote", fwdQuotes_);
314 XMLUtils::addChild(doc, node, "DayCounter", dayCountId_);
315 XMLUtils::addChild(doc, node, "InterpolationMethod", interpolationMethod_);
316 XMLUtils::addChild(doc, node, "Conventions", conventionsId_);
317 }
318
319 XMLUtils::addChild(doc, node, "Extrapolation", extrapolation_);
320
321 if (bootstrapConfig_) {
322 XMLUtils::appendNode(node, bootstrapConfig_->toXML(doc));
323 }
324
325 return node;
326}
327
329 if (!baseYieldCurveId().empty())
331 if (!yieldCurveId().empty())
333 if (!basePriceCurveId().empty())
335}
336
337void CommodityCurveConfig::processSegments(std::vector<PriceSegment> priceSegments) {
338
339 QL_REQUIRE(!priceSegments.empty(), "Need at least one price segment for a Piecewise commodity curve.");
340
341 // Populate the quotes with each segment's quotes. Remove any price segments that have a valid priority value and
342 // add to the priceSegments_ map. What remains in priceSegments are price segments without a priority.
343 auto it = priceSegments.begin();
344 while (it != priceSegments.end()) {
345
346 // If price segment is AveragingOffPeakPower, need a peak power curve Id.
348 QL_REQUIRE(!it->peakPriceCurveId().empty(), "An AveragingOffPeakPower price segment should have" <<
349 " a non empty PeakPriceCurveId");
350 requiredCurveIds_[CurveSpec::CurveType::Commodity].insert(it->peakPriceCurveId());
351 }
352
353 // Quotes
354 fwdQuotes_.insert(fwdQuotes_.end(), it->quotes().begin(), it->quotes().end());
355
356 // Price segments
357 if (it->priority()) {
358 unsigned short p = *it->priority();
359 QL_REQUIRE(priceSegments_.count(p) == 0, "CommodityCurveConfig: already configured a price segment " <<
360 "with priority " << p << " for commodity curve configuration " << curveID() << ".");
361 priceSegments_[p] = *it;
362 it = priceSegments.erase(it);
363 } else {
364 it++;
365 }
366
367 }
368
369 // Get the current largest priority.
370 unsigned short largestPriority = 0;
371 if (!priceSegments_.empty()) {
372 largestPriority = priceSegments_.rbegin()->first;
373 }
374
375 // Very unlikely but check that the priorities entered will not cause an overflow of short int.
376 QL_REQUIRE(priceSegments.size() <= static_cast<unsigned short>(std::numeric_limits<unsigned short>::max() - largestPriority),
377 "Largest price segment priority (" << largestPriority << ") and number of segments without a " <<
378 "priority (" << priceSegments.size() << ") combine to give a value too large for unsigned short.");
379
380 // Now add the price segments without a priority to the end of the map.
381 for (const auto& ps : priceSegments) {
382 priceSegments_[++largestPriority] = ps;
383 }
384
386}
387
388} // namespace data
389} // namespace ore
void populateRequiredCurveIds()
Populate any dependent curve IDs.
const std::string & baseYieldCurveId() const
const std::string & basePriceCurveId() const
const std::string & yieldCurveId() const
const std::map< unsigned short, PriceSegment > & priceSegments() const
void processSegments(std::vector< PriceSegment > priceSegments)
Process price segments when configuring a Piecewise curve.
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
std::map< unsigned short, PriceSegment > priceSegments_
boost::optional< BootstrapConfig > bootstrapConfig_
CommodityCurveConfig()
Default constructor.
Base curve configuration.
Definition: curveconfig.hpp:41
vector< string > quotes_
Definition: curveconfig.hpp:74
const string & curveID() const
Definition: curveconfig.hpp:54
virtual const vector< string > & quotes()
Return all the market quotes required for this config.
Definition: curveconfig.hpp:69
map< CurveSpec::CurveType, set< string > > requiredCurveIds_
Definition: curveconfig.hpp:75
Class to store quotes used in building daily off-peak power quotes.
XMLNode * toXML(XMLDocument &doc) const override
const boost::optional< unsigned short > & priority() const
void populateQuotes()
Populate quotes.
Type
Type of price segment being represented, i.e. type of instrument in the price segment.
const std::string & peakPriceCalendar() const
const boost::optional< OffPeakDaily > & offPeakDaily() const
boost::optional< OffPeakDaily > offPeakDaily_
const std::string & peakPriceCurveId() const
PriceSegment()
Default constructor.
std::vector< std::string > quotes_
boost::optional< unsigned short > priority_
void fromXML(XMLNode *node) override
XMLNode * toXML(XMLDocument &doc) const override
const std::string & conventionsId() const
const std::vector< std::string > & quotes() const
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 addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
Definition: xmlutils.cpp:502
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 int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
Definition: xmlutils.cpp:291
static XMLNode * getNextSibling(XMLNode *node, const string &name="")
Get a node's next sibling node.
Definition: xmlutils.cpp:484
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
Commodity curve configuration class.
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
@ data
Definition: log.hpp:77
PriceSegment::Type parsePriceSegmentType(const string &s)
Convert text to PriceSegment::Type.
Definition: parsers.cpp:1158
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.