Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossassetmodeldata.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
28
35
36#include <ql/math/optimization/levenbergmarquardt.hpp>
37#include <ql/models/shortrate/calibrationhelpers/swaptionhelper.hpp>
38#include <ql/quotes/simplequote.hpp>
39#include <ql/utilities/dataformatters.hpp>
40
41#include <boost/algorithm/string/case_conv.hpp>
42#include <boost/lexical_cast.hpp>
43
44namespace {
45
51using std::string;
52
53CorrelationFactor fromNode(ore::data::XMLNode* node, bool firstFactor) {
54
55 string factorTag = firstFactor ? "factor1" : "factor2";
56 string idxTag = firstFactor ? "index1" : "index2";
57
58 CorrelationFactor factor = parseCorrelationFactor(XMLUtils::getAttribute(node, factorTag));
59 string strIdx = XMLUtils::getAttribute(node, idxTag);
60 if (strIdx != "") {
61 factor.index = parseInteger(strIdx);
62 }
63
64 return factor;
65}
66
67} // namespace
68
69namespace ore {
70namespace data {
71
73 // Configure correlation structure
74 LOG("CrossAssetModelData: adding correlations.");
75 XMLNode* correlationNode = XMLUtils::locateNode(node, "InstantaneousCorrelations");
77 if (correlationNode) {
78 vector<XMLNode*> nodes = XMLUtils::getChildrenNodes(correlationNode, "Correlation");
79 for (Size i = 0; i < nodes.size(); ++i) {
80 CorrelationFactor factor_1 = fromNode(nodes[i], true);
81 CorrelationFactor factor_2 = fromNode(nodes[i], false);
82 Real corr = parseReal(XMLUtils::getNodeValue(nodes[i]));
83 cmb.addCorrelation(factor_1, factor_2, corr);
84 }
85 } else {
86 QL_FAIL("No InstantaneousCorrelations found in model configuration XML");
87 }
88
90}
91
93
94 XMLNode* instantaneousCorrelationsNode = doc.allocNode("InstantaneousCorrelations");
95
96 for (auto it = correlations_.begin(); it != correlations_.end(); it++) {
97
98 XMLNode* node = doc.allocNode("Correlation", to_string(it->second->value()));
99 XMLUtils::appendNode(instantaneousCorrelationsNode, node);
100
101 CorrelationFactor f_1 = it->first.first;
102 XMLUtils::addAttribute(doc, node, "factor1", to_string(f_1.type) + ":" + f_1.name);
103 if (f_1.index != Null<Size>())
104 XMLUtils::addAttribute(doc, node, "index1", to_string(f_1.index));
105
106 CorrelationFactor f_2 = it->first.second;
107 XMLUtils::addAttribute(doc, node, "factor2", to_string(f_2.type) + ":" + f_2.name);
108 if (f_2.index != Null<Size>())
109 XMLUtils::addAttribute(doc, node, "index2", to_string(f_2.index));
110 }
111
112 return instantaneousCorrelationsNode;
113}
114
116 // compare correlations by value (not the handle links)
117 map<CorrelationKey, Handle<Quote>>::const_iterator corr1, corr2;
118 for (corr1 = correlations_.begin(), corr2 = rhs.correlations_.begin();
119 corr1 != correlations_.end() && corr2 != rhs.correlations_.end(); ++corr1, ++corr2) {
120 if (corr1->first != corr2->first || !close_enough(corr1->second->value(), corr2->second->value()))
121 return false;
122 }
123 if (corr1 != correlations_.end() || corr2 != rhs.correlations_.end())
124 return false;
125
126 return true;
127}
128
129bool InstantaneousCorrelations::operator!=(const InstantaneousCorrelations& rhs) { return !(*this == rhs); }
130
132
133 if (*correlations_ != *rhs.correlations_)
134 return false;
135
138 irConfigs_.size() != rhs.irConfigs_.size() || fxConfigs_.size() != rhs.fxConfigs_.size() ||
139 eqConfigs_.size() != rhs.eqConfigs_.size() || infConfigs_.size() != rhs.infConfigs_.size() ||
140 crLgmConfigs_.size() != rhs.crLgmConfigs_.size() || crCirConfigs_.size() != rhs.crCirConfigs_.size() ||
141 comConfigs_.size() != rhs.comConfigs_.size()) {
142 return false;
143 }
144
145 for (Size i = 0; i < irConfigs_.size(); i++) {
146 auto c1 = QuantLib::ext::dynamic_pointer_cast<LgmData>(irConfigs_[i]);
147 auto c2 = QuantLib::ext::dynamic_pointer_cast<LgmData>(irConfigs_[i]);
148 auto c3 = QuantLib::ext::dynamic_pointer_cast<HwModelData>(irConfigs_[i]);
149 auto c4 = QuantLib::ext::dynamic_pointer_cast<HwModelData>(irConfigs_[i]);
150 if (c1 != nullptr && c2 != nullptr) {
151 if (*c1 != *c2) {
152 return false;
153 }
154 } else if (c3 != nullptr && c4 != nullptr) {
155 if (*c3 != *c4) {
156 return false;
157 }
158 } else {
159 return false;
160 }
161 }
162
163 for (Size i = 0; i < fxConfigs_.size(); i++) {
164 if (*fxConfigs_[i] != *(rhs.fxConfigs_[i])) {
165 return false;
166 }
167 }
168
169 for (Size i = 0; i < eqConfigs_.size(); i++) {
170 if (*eqConfigs_[i] != *(rhs.eqConfigs_[i])) {
171 return false;
172 }
173 }
174
175 // Not checking inflation model data for equality. The equality operators were only written to support
176 // unit testing toXML and fromXML. Questionable if it should be done this way.
177
178 for (Size i = 0; i < crLgmConfigs_.size(); i++) {
179 if (*crLgmConfigs_[i] != *(rhs.crLgmConfigs_[i])) {
180 return false;
181 }
182 }
183
184 for (Size i = 0; i < crCirConfigs_.size(); i++) {
185 if (*crCirConfigs_[i] != *(rhs.crCirConfigs_[i])) {
186 return false;
187 }
188 }
189
190 for (Size i = 0; i < comConfigs_.size(); i++) {
191 if (*comConfigs_[i] != *(rhs.comConfigs_[i])) {
192 return false;
193 }
194 }
195
196 return true;
197}
198
199bool CrossAssetModelData::operator!=(const CrossAssetModelData& rhs) { return !(*this == rhs); }
200
202 currencies_.clear();
203 equities_.clear();
204 irConfigs_.clear();
205 fxConfigs_.clear();
206 eqConfigs_.clear();
207 infConfigs_.clear();
208 crLgmConfigs_.clear();
209 crCirConfigs_.clear();
210 comConfigs_.clear();
211 correlations_->clear();
212}
213
215 QL_REQUIRE(irConfigs_.size() > 0, "no IR data provided");
216 bool useHwModel = false;
217 // All IR configs need to be either HullWhite or LGM
218 if (auto hwModelData = QuantLib::ext::dynamic_pointer_cast<HwModelData>(irConfigs_.front())) {
219 useHwModel = true;
220 }
221 for (const auto& modelData : irConfigs_) {
222 if (useHwModel) {
223 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<HwModelData>(modelData),
224 "expect all ir models to be of hull white models");
225 } else {
226 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<IrLgmData>(modelData), "expect all ir models to be lgm models");
227 }
228 }
229
230 QL_REQUIRE(fxConfigs_.size() == irConfigs_.size() - 1, "inconsistent number of FX data provided");
231 for (Size i = 0; i < fxConfigs_.size(); ++i)
232 QL_REQUIRE(fxConfigs_[i]->foreignCcy() == irConfigs_[i + 1]->ccy(),
233 "currency mismatch between IR and FX config vectors");
234
235 if (measure_ == "BA" && !useHwModel) {
236 // ensure that the domestic LGM has shift = 0 and scaling = 1
237 for (Size i = 0; i < irConfigs_.size(); ++i)
238 if (irConfigs_[i]->ccy() == domesticCurrency_) {
239 auto irConfig = QuantLib::ext::dynamic_pointer_cast<IrLgmData>(irConfigs_[i]);
240 QL_REQUIRE(close_enough(irConfig->scaling(), 1.0),
241 "scaling for the domestic LGM must be 1 for BA measure simulations");
242 QL_REQUIRE(close_enough(irConfig->shiftHorizon(), 0.0),
243 "shift horizon for the domestic LGM must be 0 for BA measure simulations");
244 }
245 }
246}
247
248std::vector<std::string> pairToStrings(std::pair<std::string, std::string> p) {
249 std::vector<std::string> pair = {p.first, p.second};
250 return pair;
251}
252
254 clear();
255
256 // we can read from the subnode "CrossAssetModel" of the root node "Simulation" or
257 // directly from root = CrossAssetModel. This way fromXML(toXML()) works as expected.
258 XMLNode* modelNode;
259 if (XMLUtils::getNodeName(root) == "CrossAssetModel") {
260 modelNode = root;
261 } else {
262 XMLNode* sim = XMLUtils::locateNode(root, "Simulation");
263 modelNode = XMLUtils::getChildNode(sim, "CrossAssetModel");
264 QL_REQUIRE(modelNode, "Simulation / CrossAssetModel not found, can not read cross asset model data");
265 }
266
267 std::string discString = XMLUtils::getChildValue(modelNode, "Discretization", false);
268
269 // check deprecated way of providing Discretization under Simulation/Parameters
270 if (discString.empty()) {
271 if (XMLNode* node = XMLUtils::getChildNode(root, "Parameters")) {
272 discString = XMLUtils::getChildValue(node, "Discretization", false);
273 WLOG("Simulation/Parameters/Discretization is deprecated, use Simulation/CrossAssetModel/Discretization "
274 "instead.");
275 }
276 }
277
278 // default discString to Exact if not found
279 if(discString.empty()) {
280 discString = "Exact";
281 WLOG("CrossAssetModelData: Discretization is not given. Expected this in Simulation/CrossAssetModel or in "
282 "Simulation/Parameters/Discretization (deprecated). Fall back to Exact.");
283 }
284
286
287 domesticCurrency_ = XMLUtils::getChildValue(modelNode, "DomesticCcy", true); // mandatory
288 LOG("CrossAssetModelData: domesticCcy " << domesticCurrency_);
289
290 currencies_ = XMLUtils::getChildrenValues(modelNode, "Currencies", "Currency", true);
291 for (auto ccy : currencies_) {
292 LOG("CrossAssetModelData: ccy " << ccy);
293 }
294
295 equities_ = XMLUtils::getChildrenValues(modelNode, "Equities", "Equity");
296 for (auto eq : equities_) {
297 LOG("CrossAssetModelData equity " << eq);
298 }
299
300 infindices_ = XMLUtils::getChildrenValues(modelNode, "InflationIndices", "InflationIndex");
301 for (auto inf : infindices_) {
302 LOG("CrossAssetModelData inflation index " << inf);
303 }
304
305 creditNames_ = XMLUtils::getChildrenValues(modelNode, "CreditNames", "CreditName");
306 for (auto cr : creditNames_) {
307 LOG("CrossAssetModelData credit name " << cr);
308 }
309
310 commodities_ = XMLUtils::getChildrenValues(modelNode, "Commodities", "Commodity");
311 for (auto com : commodities_) {
312 LOG("CrossAssetModelData commodity " << com);
313 }
314
315 bootstrapTolerance_ = XMLUtils::getChildValueAsDouble(modelNode, "BootstrapTolerance", true);
316 LOG("CrossAssetModelData: bootstrap tolerance = " << bootstrapTolerance_);
317
318 measure_ = XMLUtils::getChildValue(modelNode, "Measure", false);
319 LOG("CrossAssetModelData: measure = '" << measure_ << "'");
320
321 // Configure IR model components
322
323 std::map<std::string, QuantLib::ext::shared_ptr<IrModelData>> irDataMap;
324 XMLNode* irNode = XMLUtils::getChildNode(modelNode, "InterestRateModels");
325 if (irNode) {
326
327 bool hasLgmAndHwModels = XMLUtils::getChildNode(irNode, "LGM") && XMLUtils::getChildNode(irNode, "HWModel");
328
329 QL_REQUIRE(!hasLgmAndHwModels, "CrossAssetModelData: Found configuration for HullWhiteModel and LGM model, use "
330 "only one. Please check your simulation.xml");
331
332 for (XMLNode* child = XMLUtils::getChildNode(irNode, "LGM"); child;
333 child = XMLUtils::getNextSibling(child, "LGM")) {
334
335 QuantLib::ext::shared_ptr<IrLgmData> config(new IrLgmData());
336 config->fromXML(child);
337
338 for (Size i = 0; i < config->optionExpiries().size(); i++) {
339 LOG("LGM calibration swaption " << config->optionExpiries()[i] << " x " << config->optionTerms()[i]
340 << " " << config->optionStrikes()[i]);
341 }
342
343 irDataMap[config->qualifier()] = config;
344
345 LOG("CrossAssetModelData: IR config built for key " << config->qualifier());
346
347 } // end of for (XMLNode* child = XMLUtils::getChildNode(irNode, "LGM"); child;
348
349
350 for (XMLNode* child = XMLUtils::getChildNode(irNode, "HWModel"); child;
351 child = XMLUtils::getNextSibling(child, "HWModel")) {
352
353 QuantLib::ext::shared_ptr<HwModelData> config(new HwModelData());
354 config->fromXML(child);
355
356 for (Size i = 0; i < config->optionExpiries().size(); i++) {
357 LOG("LGM calibration swaption " << config->optionExpiries()[i] << " x " << config->optionTerms()[i]
358 << " " << config->optionStrikes()[i]);
359 }
360
361 irDataMap[config->qualifier()] = config;
362
363 LOG("CrossAssetModelData: HullWhite IR config built for key " << config->qualifier());
364
365 } // end of for (XMLNode* child = XMLUtils::getChildNode(irNode, "LGM"); child;
366
367 } // end of if (irNode)
368 else {
369 LOG("No IR model section found");
370 }
371
372 buildIrConfigs(irDataMap);
373
374 for (Size i = 0; i < irConfigs_.size(); i++)
375 LOG("CrossAssetModelData: IR config currency " << i << " = " << irConfigs_[i]->ccy());
376
377 // Configure FX model components
378
379 std::map<std::string, QuantLib::ext::shared_ptr<FxBsData>> fxDataMap;
380 XMLNode* fxNode = XMLUtils::getChildNode(modelNode, "ForeignExchangeModels");
381 if (fxNode) {
382 for (XMLNode* child = XMLUtils::getChildNode(fxNode, "CrossCcyLGM"); child;
383 child = XMLUtils::getNextSibling(child, "CrossCcyLGM")) {
384
385 QuantLib::ext::shared_ptr<FxBsData> config(new FxBsData());
386 config->fromXML(child);
387
388 for (Size i = 0; i < config->optionExpiries().size(); i++) {
389 LOG("CC-LGM calibration option " << config->optionExpiries()[i] << " " << config->optionStrikes()[i]);
390 }
391
392 fxDataMap[config->foreignCcy()] = config;
393
394 LOG("CrossAssetModelData: FX config built with key (foreign ccy) " << config->foreignCcy());
395 }
396 } else {
397 LOG("No FX Models section found");
398 }
399
400 buildFxConfigs(fxDataMap);
401
402 for (Size i = 0; i < fxConfigs_.size(); i++)
403 LOG("CrossAssetModelData: FX config currency " << i << " = " << fxConfigs_[i]->foreignCcy());
404
405 // Configure EQ model components
406
407 std::map<std::string, QuantLib::ext::shared_ptr<EqBsData>> eqDataMap;
408 XMLNode* eqNode = XMLUtils::getChildNode(modelNode, "EquityModels");
409 if (eqNode) {
410 for (XMLNode* child = XMLUtils::getChildNode(eqNode, "CrossAssetLGM"); child;
411 child = XMLUtils::getNextSibling(child, "CrossAssetLGM")) {
412
413 QuantLib::ext::shared_ptr<EqBsData> config(new EqBsData());
414 config->fromXML(child);
415
416 for (Size i = 0; i < config->optionExpiries().size(); i++) {
417 LOG("Cross-Asset Equity calibration option " << config->optionExpiries()[i] << " "
418 << config->optionStrikes()[i]);
419 }
420
421 eqDataMap[config->eqName()] = config;
422
423 LOG("CrossAssetModelData: Equity config built with key " << config->eqName());
424 }
425 } else {
426 LOG("No Equity Models section found");
427 }
428
429 buildEqConfigs(eqDataMap);
430
431 for (Size i = 0; i < eqConfigs_.size(); i++)
432 LOG("CrossAssetModelData: EQ config name " << i << " = " << eqConfigs_[i]->eqName());
433
434 // Read the inflation model data.
435 if (XMLNode* n = XMLUtils::getChildNode(modelNode, "InflationIndexModels")) {
436
437 map<string, QuantLib::ext::shared_ptr<InflationModelData>> mp;
438
439 // Loop over nodes and pick out any with name: LGM, DodgsonKainth or JarrowYildirim.
440 for (XMLNode* cn = XMLUtils::getChildNode(n); cn; cn = XMLUtils::getNextSibling(cn)) {
441
442 QuantLib::ext::shared_ptr<InflationModelData> imData;
443
444 string nodeName = XMLUtils::getNodeName(cn);
445 if (nodeName == "LGM" || nodeName == "DodgsonKainth") {
446 imData = QuantLib::ext::make_shared<InfDkData>();
447 } else if (nodeName == "JarrowYildirim") {
448 imData = QuantLib::ext::make_shared<InfJyData>();
449 } else {
450 WLOG("Did not recognise InflationIndexModels node with name "
451 << nodeName << " as a valid inflation index model so skipping it.");
452 continue;
453 }
454
455 const string& indexName = imData->index();
456 imData->fromXML(cn);
457 mp[indexName] = imData;
458
459 LOG("CrossAssetModelData: inflation index model data built with key " << indexName);
460 }
461
462 // Align the inflation model data with the infindices_ read in above and handle defaults
463 buildInfConfigs(mp);
464
465 // Log the index number and inflation index name for each inflation index model.
466 for (Size i = 0; i < infConfigs_.size(); i++)
467 LOG("CrossAssetModelData: INF config name " << i << " = " << infConfigs_[i]->index());
468
469 } else {
470 LOG("No InflationIndexModels node found so no inflation models configured.");
471 }
472
473 // Configure CR model components
474
475 std::map<std::string, QuantLib::ext::shared_ptr<CrLgmData>> crLgmDataMap;
476 std::map<std::string, QuantLib::ext::shared_ptr<CrCirData>> crCirDataMap;
477 XMLNode* crNode = XMLUtils::getChildNode(modelNode, "CreditModels");
478 if (crNode) {
479 for (XMLNode* child = XMLUtils::getChildNode(crNode, "LGM"); child;
480 child = XMLUtils::getNextSibling(child, "LGM")) {
481
482 QuantLib::ext::shared_ptr<CrLgmData> config(new CrLgmData());
483 config->fromXML(child);
484
485 for (Size i = 0; i < config->optionExpiries().size(); i++) {
486 LOG("LGM calibration cds option " << config->optionExpiries()[i] << " x " << config->optionTerms()[i]
487 << " " << config->optionStrikes()[i]);
488 }
489
490 crLgmDataMap[config->name()] = config;
491
492 LOG("CrossAssetModelData: CR LGM config built for key " << config->name());
493
494 } // end of for (XMLNode* child = XMLUtils::getChildNode(irNode, "LGM"); child;
495 for (XMLNode* child = XMLUtils::getChildNode(crNode, "CIR"); child;
496 child = XMLUtils::getNextSibling(child, "CIR")) {
497
498 QuantLib::ext::shared_ptr<CrCirData> config(new CrCirData());
499 config->fromXML(child);
500
501 for (Size i = 0; i < config->optionExpiries().size(); i++) {
502 LOG("CIR calibration cds option " << config->optionExpiries()[i] << " x " << config->optionTerms()[i]
503 << " " << config->optionStrikes()[i]);
504 }
505
506 crCirDataMap[config->name()] = config;
507
508 LOG("CrossAssetModelData: CR CIR config built for key " << config->name());
509
510 } // end of for (XMLNode* child = XMLUtils::getChildNode(irNode, "CIR"); child;
511 } // end of if (irNode)
512 else {
513 LOG("No CR model section found");
514 }
515
516 buildCrConfigs(crLgmDataMap, crCirDataMap);
517
518 for (Size i = 0; i < crLgmConfigs_.size(); i++)
519 LOG("CrossAssetModelData: CR LGM config name " << i << " = " << crLgmConfigs_[i]->name());
520 for (Size i = 0; i < crCirConfigs_.size(); i++)
521 LOG("CrossAssetModelData: CR CIR config name " << i << " = " << crCirConfigs_[i]->name());
522
523 // Configure COM model components
524
525 std::map<std::string, QuantLib::ext::shared_ptr<CommoditySchwartzData>> comDataMap;
526 XMLNode* comNode = XMLUtils::getChildNode(modelNode, "CommodityModels");
527 if (comNode) {
528 for (XMLNode* child = XMLUtils::getChildNode(comNode, "CommoditySchwartz"); child;
529 child = XMLUtils::getNextSibling(child, "CommoditySchwartz")) {
530
531 QuantLib::ext::shared_ptr<CommoditySchwartzData> config(new CommoditySchwartzData());
532 config->fromXML(child);
533
534 for (Size i = 0; i < config->optionExpiries().size(); i++) {
535 LOG("Cross-Asset Commodity calibration option " << config->optionExpiries()[i] << " "
536 << config->optionStrikes()[i]);
537 }
538
539 comDataMap[config->name()] = config;
540
541 LOG("CrossAssetModelData: Commodity config built with key " << config->name());
542 }
543 } else {
544 LOG("No Commodity Models section found");
545 }
546
547 buildComConfigs(comDataMap);
548
549 for (Size i = 0; i < comConfigs_.size(); i++)
550 LOG("CrossAssetModelData: COM config name " << i << " = " << comConfigs_[i]->name());
551
552 // Configure credit states
553
555 XMLNode* crStateNode = XMLUtils::getChildNode(modelNode, "CreditStates");
556 if(crStateNode) {
557 numberOfCreditStates_ = XMLUtils::getChildValueAsInt(crStateNode, "NumberOfFactors", true);
558 LOG("Set up " << numberOfCreditStates_ << " credit states.");
559 }
560 else {
561 LOG("No credit states section found");
562 }
563
564 // Configure correlation structure
565 LOG("CrossAssetModelData: adding correlations.");
566 correlations_ = QuantLib::ext::make_shared<InstantaneousCorrelations>();
567 correlations_->fromXML(modelNode);
568
569 validate();
570
571 LOG("CrossAssetModelData loading from XML done");
572}
573
574void CrossAssetModelData::buildIrConfigs(std::map<std::string, QuantLib::ext::shared_ptr<IrModelData>>& irDataMap) {
575 // Append IR configurations into the irConfigs vector in the order of the currencies
576 // in the currencies vector.
577 // If there is an IR configuration for any of the currencies missing, then we will
578 // look up the configuration with key "default" and use this instead. If this is
579 // not provided either we will throw an exception.
580 irConfigs_.resize(currencies_.size());
581 for (Size i = 0; i < currencies_.size(); i++) {
582 string ccy = currencies_[i];
583 std::string ccyKey;
584 for (auto const& d : irDataMap) {
585 if (d.second->ccy() == ccy) {
586 QL_REQUIRE(ccyKey.empty(), "CrossAssetModelData: duplicate ir config for ccy " << ccy);
587 ccyKey = d.first;
588 }
589 }
590 if (!ccyKey.empty())
591 irConfigs_[i] = irDataMap.at(ccyKey);
592 else { // copy from default
593 LOG("IR configuration missing for currency " << ccy << ", using default");
594 if (irDataMap.find("default") == irDataMap.end()) {
595 ALOG("Both default IR and " << ccy << " IR configuration missing");
596 QL_FAIL("Both default IR and " << ccy << " IR configuration missing");
597 }
598 if (auto def = QuantLib::ext::dynamic_pointer_cast<HwModelData>(irDataMap["default"])) {
599 irConfigs_[i] = QuantLib::ext::make_shared<HwModelData>(
600 ccy, // overwrite this and keep the others
601 def->calibrationType(), def->calibrateKappa(),
602 def->kappaType(), def->kappaTimes(), def->kappaValues(), def->calibrateSigma(), def->sigmaType(),
603 def->sigmaTimes(), def->sigmaValues(), def->optionExpiries(),
604 def->optionTerms(), def->optionStrikes());
605
606 } else if (auto def = QuantLib::ext::dynamic_pointer_cast<IrLgmData>(irDataMap["default"])) {
607 irConfigs_[i] = QuantLib::ext::make_shared<IrLgmData>(
608 ccy, // overwrite this and keep the others
609 def->calibrationType(), def->reversionType(), def->volatilityType(), def->calibrateH(),
610 def->hParamType(), def->hTimes(), def->hValues(), def->calibrateA(), def->aParamType(),
611 def->aTimes(), def->aValues(), def->shiftHorizon(), def->scaling(), def->optionExpiries(),
612 def->optionTerms(), def->optionStrikes());
613 } else {
614 QL_FAIL("Unexpected model data type,expect either HwModelData or IrLgmData");
615 }
616 }
617 LOG("CrossAssetModelData: IR config added for ccy " << irConfigs_[i]->ccy());
618 }
619}
620
621void CrossAssetModelData::buildFxConfigs(std::map<std::string, QuantLib::ext::shared_ptr<FxBsData>>& fxDataMap) {
622 // Append FX configurations into the fxConfigs vector in the order of the foreign
623 // currencies in the currencies vector.
624 // If there is an FX configuration for any of the foreign currencies missing,
625 // then we will look up the configuration with key "default" and use this instead.
626 // If this is not provided either we will throw an exception.
627 for (Size i = 0; i < currencies_.size(); i++) {
628 string ccy = currencies_[i];
629 if (ccy == domesticCurrency_)
630 continue;
631 if (fxDataMap.find(ccy) != fxDataMap.end())
632 fxConfigs_.push_back(fxDataMap[ccy]);
633 else { // copy from default
634 LOG("FX configuration missing for foreign currency " << ccy << ", using default");
635 if (fxDataMap.find("default") == fxDataMap.end()) {
636 ALOG("Both default FX and " << ccy << " FX configuration missing");
637 QL_FAIL("Both default FX and " << ccy << " FX configuration missing");
638 }
639 QuantLib::ext::shared_ptr<FxBsData> def = fxDataMap["default"];
640 QuantLib::ext::shared_ptr<FxBsData> fxData = QuantLib::ext::make_shared<FxBsData>(
641 ccy, def->domesticCcy(), def->calibrationType(), def->calibrateSigma(), def->sigmaParamType(),
642 def->sigmaTimes(), def->sigmaValues(), def->optionExpiries(), def->optionStrikes());
643
644 fxConfigs_.push_back(fxData);
645 }
646 LOG("CrossAssetModelData: FX config added for foreign ccy " << ccy);
647 }
648}
649
650void CrossAssetModelData::buildEqConfigs(std::map<std::string, QuantLib::ext::shared_ptr<EqBsData>>& eqDataMap) {
651 // Append Eq configurations into the eqConfigs vector in the order of the equity
652 // names in the equities) vector.
653 // If there is an Eq configuration for any of the names missing,
654 // then we will look up the configuration with key "default" and use this instead.
655 // If this is not provided either we will throw an exception.
656 for (Size i = 0; i < equities_.size(); i++) {
657 string name = equities_[i];
658 if (eqDataMap.find(name) != eqDataMap.end())
659 eqConfigs_.push_back(eqDataMap[name]);
660 else { // copy from default
661 LOG("Equity configuration missing for name " << name << ", using default");
662 if (eqDataMap.find("default") == eqDataMap.end()) {
663 ALOG("Both default EQ and " << name << " EQ configuration missing");
664 QL_FAIL("Both default EQ and " << name << " EQ configuration missing");
665 }
666 QuantLib::ext::shared_ptr<EqBsData> def = eqDataMap["default"];
667 QuantLib::ext::shared_ptr<EqBsData> eqData = QuantLib::ext::make_shared<EqBsData>(
668 name, def->currency(), def->calibrationType(), def->calibrateSigma(), def->sigmaParamType(),
669 def->sigmaTimes(), def->sigmaValues(), def->optionExpiries(), def->optionStrikes());
670
671 eqConfigs_.push_back(eqData);
672 }
673 LOG("CrossAssetModelData: EQ config added for name " << name);
674 }
675}
676
677void CrossAssetModelData::buildInfConfigs(const map<string, QuantLib::ext::shared_ptr<InflationModelData>>& mp) {
678
679 // Append inflation model data to the infConfigs_ vector in the order of the inflation indices in the infindices_
680 // vector.
681
682 // If for any of the inflation indices in the infindices_ vector, there is no inflation model data in mp then the
683 // default inflation model data is used. The default inflation model data should be in mp under the key name
684 // "default". If it is not provided either, an exception is thrown.
685
686 for (const string& indexName : infindices_) {
687
688 auto it = mp.find(indexName);
689 if (it != mp.end()) {
690 infConfigs_.push_back(it->second);
691 } else {
692
693 LOG("Inflation index model data missing for index " << indexName << " so attempt to use default");
694
695 auto itDefault = mp.find("default");
696 QL_REQUIRE(itDefault != mp.end(),
697 "Inflation index model data missing for index " << indexName << " and for default.");
698
699 // Make a copy of the model data and add to vector.
700 QuantLib::ext::shared_ptr<InflationModelData> imData = itDefault->second;
701 if (auto dk = QuantLib::ext::dynamic_pointer_cast<InfDkData>(imData)) {
702 infConfigs_.push_back(QuantLib::ext::make_shared<InfDkData>(*dk));
703 } else if (auto jy = QuantLib::ext::dynamic_pointer_cast<InfJyData>(imData)) {
704 infConfigs_.push_back(QuantLib::ext::make_shared<InfJyData>(*jy));
705 } else {
706 QL_FAIL("Expected inflation model data to be DK or JY.");
707 }
708 }
709
710 LOG("CrossAssetModelData: INF config added for name " << indexName);
711 }
712}
713
714void CrossAssetModelData::buildCrConfigs(std::map<std::string, QuantLib::ext::shared_ptr<CrLgmData>>& crLgmDataMap,
715 std::map<std::string, QuantLib::ext::shared_ptr<CrCirData>>& crCirDataMap) {
716 // Append IR configurations into the irConfigs vector in the order of the currencies
717 // in the currencies vector.
718 // If there is an IR configuration for any of the currencies missing, then we will
719 // look up the configuration with key "default" and use this instead. If this is
720 // not provided either we will throw an exception.
721 crLgmConfigs_.clear();
722 crCirConfigs_.clear();
723
724 for (Size i = 0; i < creditNames_.size(); i++) {
725 string name = creditNames_[i];
726 if (crLgmDataMap.find(name) != crLgmDataMap.end()) {
727 QL_REQUIRE(crCirDataMap.find(name) == crCirDataMap.end(), "");
728 crLgmConfigs_.push_back(crLgmDataMap[name]);
729 } else if (crCirDataMap.find(name) != crCirDataMap.end()) {
730 crCirConfigs_.push_back(crCirDataMap[name]);
731 } else { // copy from LGM default, CIR default is not used
732 LOG("CR configuration missing for name " << name << ", using default");
733 if (crLgmDataMap.find("default") == crLgmDataMap.end()) {
734 ALOG("Both default CR LGM and " << name << " CR configuration missing");
735 QL_FAIL("Both default CR and " << name << " CR configuration missing");
736 }
737 QuantLib::ext::shared_ptr<CrLgmData> def = crLgmDataMap["default"];
738 crLgmConfigs_.push_back(QuantLib::ext::make_shared<CrLgmData>(
739 name, // overwrite this and keep the others
740 def->calibrationType(), def->reversionType(), def->volatilityType(), def->calibrateH(),
741 def->hParamType(), def->hTimes(), def->hValues(), def->calibrateA(), def->aParamType(), def->aTimes(),
742 def->aValues(), def->shiftHorizon(), def->scaling(), def->optionExpiries(), def->optionTerms(),
743 def->optionStrikes()));
744 }
745 LOG("CrossAssetModelData: CR config added for name " << name << " " << name);
746 }
747}
748
749void CrossAssetModelData::buildComConfigs(std::map<std::string, QuantLib::ext::shared_ptr<CommoditySchwartzData>>& comDataMap) {
750 // Append Commodity configurations into the comConfigs vector in the order of the commodity
751 // names in the commodities vector.
752 // If there is a COM configuration for any of the names missing,
753 // then we will look up the configuration with key "default" and use this instead.
754 // If this is not provided either we will throw an exception.
755 for (Size i = 0; i < commodities_.size(); i++) {
756 string name = commodities_[i];
757 if (comDataMap.find(name) != comDataMap.end())
758 comConfigs_.push_back(comDataMap[name]);
759 else { // copy from default
760 LOG("Commodity configuration missing for name " << name << ", using default");
761 if (comDataMap.find("default") == comDataMap.end()) {
762 ALOG("Both default COM and " << name << " COM configuration missing");
763 QL_FAIL("Both default COM and " << name << " COM configuration missing");
764 }
765 QuantLib::ext::shared_ptr<CommoditySchwartzData> def = comDataMap["default"];
766 QuantLib::ext::shared_ptr<CommoditySchwartzData> comData = QuantLib::ext::make_shared<CommoditySchwartzData>(
767 name, def->currency(), def->calibrationType(), def->calibrateSigma(), def->sigmaValue(),
768 def->calibrateKappa(), def->kappaValue(), def->optionExpiries(), def->optionStrikes());
769
770 comConfigs_.push_back(comData);
771 }
772 LOG("CrossAssetModelData: COM config added for name " << name);
773 }
774}
775
777
778 XMLNode* crossAssetModelNode = doc.allocNode("CrossAssetModel");
779
780 XMLUtils::addChild(doc, crossAssetModelNode, "DomesticCcy", domesticCurrency_);
781 XMLUtils::addChildren(doc, crossAssetModelNode, "Currencies", "Currency", currencies_);
782 XMLUtils::addChildren(doc, crossAssetModelNode, "Equities", "Equity", equities_);
783 XMLUtils::addChildren(doc, crossAssetModelNode, "InflationIndices", "InflationIndex", infindices_);
784 XMLUtils::addChildren(doc, crossAssetModelNode, "CreditNames", "CreditName", creditNames_);
785 XMLUtils::addChildren(doc, crossAssetModelNode, "Commodities", "Commodity", commodities_);
786 XMLUtils::addChild(doc, crossAssetModelNode, "BootstrapTolerance", bootstrapTolerance_);
787 XMLUtils::addChild(doc, crossAssetModelNode, "Measure", measure_);
788 XMLUtils::addChild(doc, crossAssetModelNode, "Discretization",
789 discretization_ == CrossAssetModel::Discretization::Exact ? "Exact" : "Euler");
790
791 XMLNode* interestRateModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "InterestRateModels");
792 for (Size irConfigs_Iterator = 0; irConfigs_Iterator < irConfigs_.size(); irConfigs_Iterator++) {
793 XMLNode* lgmNode = irConfigs_[irConfigs_Iterator]->toXML(doc);
794 XMLUtils::appendNode(interestRateModelsNode, lgmNode);
795 }
796
797 XMLNode* foreignExchangeModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "ForeignExchangeModels");
798 for (Size fxConfigs_Iterator = 0; fxConfigs_Iterator < fxConfigs_.size(); fxConfigs_Iterator++) {
799 XMLNode* crossCcyLgmNode = fxConfigs_[fxConfigs_Iterator]->toXML(doc);
800 XMLUtils::appendNode(foreignExchangeModelsNode, crossCcyLgmNode);
801 }
802
803 XMLNode* eqModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "EquityModels");
804 for (Size eqConfigs_Iterator = 0; eqConfigs_Iterator < eqConfigs_.size(); eqConfigs_Iterator++) {
805 XMLNode* crossAssetEqNode = eqConfigs_[eqConfigs_Iterator]->toXML(doc);
806 XMLUtils::appendNode(eqModelsNode, crossAssetEqNode);
807 }
808
809 XMLNode* infModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "InflationIndexModels");
810 for (Size infConfigs_Iterator = 0; infConfigs_Iterator < infConfigs_.size(); infConfigs_Iterator++) {
811 XMLNode* crossAssetInfNode = infConfigs_[infConfigs_Iterator]->toXML(doc);
812 XMLUtils::appendNode(infModelsNode, crossAssetInfNode);
813 }
814
815 XMLNode* crModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "CreditModels");
816 for (Size crLgmConfigs_Iterator = 0; crLgmConfigs_Iterator < crLgmConfigs_.size(); crLgmConfigs_Iterator++) {
817 XMLNode* crossAssetCrLgmNode = crLgmConfigs_[crLgmConfigs_Iterator]->toXML(doc);
818 XMLUtils::appendNode(crModelsNode, crossAssetCrLgmNode);
819 }
820 for (Size crCirConfigs_Iterator = 0; crCirConfigs_Iterator < crCirConfigs_.size(); crCirConfigs_Iterator++) {
821 XMLNode* crossAssetCrCirNode = crCirConfigs_[crCirConfigs_Iterator]->toXML(doc);
822 XMLUtils::appendNode(crModelsNode, crossAssetCrCirNode);
823 }
824
825 XMLNode* comModelsNode = XMLUtils::addChild(doc, crossAssetModelNode, "CommodityModels");
826 for (Size comConfigs_Iterator = 0; comConfigs_Iterator < comConfigs_.size(); comConfigs_Iterator++) {
827 XMLNode* crossAssetComNode = comConfigs_[comConfigs_Iterator]->toXML(doc);
828 XMLUtils::appendNode(comModelsNode, crossAssetComNode);
829 }
830
831 XMLNode* creditStateNode = XMLUtils::addChild(doc, crossAssetModelNode, "CreditStates");
832 XMLUtils::addChild(doc, creditStateNode, "NumberOfFactors", static_cast<int>(numberOfCreditStates_));
833
834 XMLNode* instantaneousCorrelationsNode = correlations_->toXML(doc);
835 XMLUtils::appendNode(crossAssetModelNode, instantaneousCorrelationsNode);
836
837 return crossAssetModelNode;
838}
839
841 static std::map<string, QuantExt::CrossAssetModel::Discretization> m = {
842 {"Exact", QuantExt::CrossAssetModel::Discretization::Exact},
843 {"Euler", QuantExt::CrossAssetModel::Discretization::Euler}};
844
845 auto it = m.find(s);
846 if (it != m.end()) {
847 return it->second;
848 } else {
849 QL_FAIL("Cannot convert \"" << s << "\" to QuantExt::CrossAssetStateProcess::discretization");
850 }
851}
852
853} // namespace data
854} // namespace ore
void addCorrelation(const std::string &factor1, const std::string &factor2, QuantLib::Real correlation)
const std::map< CorrelationKey, QuantLib::Handle< QuantLib::Quote > > & correlations()
Get the raw correlation data.
CR LGM Model Parameters.
Definition: crlgmdata.hpp:48
Cross Asset Model Parameters.
QuantLib::ext::shared_ptr< InstantaneousCorrelations > correlations_
vector< QuantLib::ext::shared_ptr< IrModelData > > irConfigs_
void validate()
Check consistency of config vectors.
void buildCrConfigs(std::map< std::string, QuantLib::ext::shared_ptr< CrLgmData > > &crLgmMap, std::map< std::string, QuantLib::ext::shared_ptr< CrCirData > > &crCirMap)
helper to convert CR LGM data, possibly including defaults, into CR config vectors
void buildFxConfigs(std::map< std::string, QuantLib::ext::shared_ptr< FxBsData > > &fxMap)
helper to convert FX data, possibly including defaults, into an FX config vector
void buildComConfigs(std::map< std::string, QuantLib::ext::shared_ptr< CommoditySchwartzData > > &comMap)
helper to convert COM data, possibly including defaulta, into a COM config vector
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
void buildInfConfigs(const std::map< std::string, QuantLib::ext::shared_ptr< InflationModelData > > &mp)
helper to convert INF data, possibly including defaults, into an INF config vector
void buildIrConfigs(map< string, QuantLib::ext::shared_ptr< IrModelData > > &irMap)
helper to convert LGM data, possibly including defaults, into an IR config vector
bool operator==(const CrossAssetModelData &rhs)
vector< QuantLib::ext::shared_ptr< EqBsData > > eqConfigs_
bool operator!=(const CrossAssetModelData &rhs)
vector< QuantLib::ext::shared_ptr< CommoditySchwartzData > > comConfigs_
void clear()
Clear all vectors and maps.
vector< QuantLib::ext::shared_ptr< CrLgmData > > crLgmConfigs_
vector< QuantLib::ext::shared_ptr< CrCirData > > crCirConfigs_
vector< QuantLib::ext::shared_ptr< FxBsData > > fxConfigs_
vector< QuantLib::ext::shared_ptr< InflationModelData > > infConfigs_
CrossAssetModel::Discretization discretization_
void buildEqConfigs(std::map< std::string, QuantLib::ext::shared_ptr< EqBsData > > &eqMap)
helper to convert EQ data, possibly including defaults, into an EQ config vector
EQ Model Parameters.
Definition: eqbsdata.hpp:50
FX Model Parameters.
Definition: fxbsdata.hpp:50
Hull White Model Parameters.
virtual void fromXML(XMLNode *node) override
Populate members from XML.
virtual XMLNode * toXML(XMLDocument &doc) const override
Write class members to XML.
std::map< CorrelationKey, QuantLib::Handle< QuantLib::Quote > > correlations_
bool operator==(const InstantaneousCorrelations &rhs)
bool operator!=(const InstantaneousCorrelations &rhs)
INF Model Parameters.
Definition: irlgmdata.hpp:51
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
XML Utilities Class.
Definition: xmlutils.hpp:119
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 vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
static XMLNode * locateNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:393
static string getNodeName(XMLNode *n)
Get and set a node's name.
Definition: xmlutils.cpp:473
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 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
configuration class for building correlation matrices
Cross asset model data.
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
Dodgson Kainth inflation model component data for the cross asset model.
Jarrow Yildirim inflation model component data for the cross asset model.
Hull White model data.
IR component data for the cross asset model.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
QuantExt::CrossAssetModel::Discretization parseDiscretization(const string &s)
CorrelationFactor parseCorrelationFactor(const string &name, const char separator)
Size size(const ValueType &v)
Definition: value.cpp:145
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
std::vector< std::string > pairToStrings(std::pair< std::string, std::string > p)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
QuantExt::CrossAssetModel::AssetType type
string conversion utilities
string name