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>
41#include <boost/algorithm/string/case_conv.hpp>
42#include <boost/lexical_cast.hpp>
55 string factorTag = firstFactor ?
"factor1" :
"factor2";
56 string idxTag = firstFactor ?
"index1" :
"index2";
59 string strIdx = XMLUtils::getAttribute(node, idxTag);
74 LOG(
"CrossAssetModelData: adding correlations.");
77 if (correlationNode) {
79 for (Size i = 0; i < nodes.size(); ++i) {
86 QL_FAIL(
"No InstantaneousCorrelations found in model configuration XML");
94 XMLNode* instantaneousCorrelationsNode = doc.
allocNode(
"InstantaneousCorrelations");
103 if (f_1.
index != Null<Size>())
108 if (f_2.
index != Null<Size>())
112 return instantaneousCorrelationsNode;
117 map<CorrelationKey, Handle<Quote>>::const_iterator corr1, corr2;
120 if (corr1->first != corr2->first || !
close_enough(corr1->second->value(), corr2->second->value()))
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) {
154 }
else if (c3 !=
nullptr && c4 !=
nullptr) {
163 for (Size i = 0; i <
fxConfigs_.size(); i++) {
169 for (Size i = 0; i <
eqConfigs_.size(); i++) {
215 QL_REQUIRE(
irConfigs_.size() > 0,
"no IR data provided");
216 bool useHwModel =
false;
218 if (
auto hwModelData = QuantLib::ext::dynamic_pointer_cast<HwModelData>(
irConfigs_.front())) {
223 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<HwModelData>(modelData),
224 "expect all ir models to be of hull white models");
226 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<IrLgmData>(modelData),
"expect all ir models to be lgm models");
230 QL_REQUIRE(
fxConfigs_.size() ==
irConfigs_.size() - 1,
"inconsistent number of FX data provided");
233 "currency mismatch between IR and FX config vectors");
235 if (
measure_ ==
"BA" && !useHwModel) {
239 auto irConfig = QuantLib::ext::dynamic_pointer_cast<IrLgmData>(
irConfigs_[i]);
241 "scaling for the domestic LGM must be 1 for BA measure simulations");
243 "shift horizon for the domestic LGM must be 0 for BA measure simulations");
248std::vector<std::string>
pairToStrings(std::pair<std::string, std::string> p) {
249 std::vector<std::string> pair = {p.first, p.second};
264 QL_REQUIRE(modelNode,
"Simulation / CrossAssetModel not found, can not read cross asset model data");
270 if (discString.empty()) {
273 WLOG(
"Simulation/Parameters/Discretization is deprecated, use Simulation/CrossAssetModel/Discretization "
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.");
292 LOG(
"CrossAssetModelData: ccy " << ccy);
297 LOG(
"CrossAssetModelData equity " << eq);
302 LOG(
"CrossAssetModelData inflation index " << inf);
307 LOG(
"CrossAssetModelData credit name " << cr);
312 LOG(
"CrossAssetModelData commodity " << com);
319 LOG(
"CrossAssetModelData: measure = '" <<
measure_ <<
"'");
323 std::map<std::string, QuantLib::ext::shared_ptr<IrModelData>> irDataMap;
329 QL_REQUIRE(!hasLgmAndHwModels,
"CrossAssetModelData: Found configuration for HullWhiteModel and LGM model, use "
330 "only one. Please check your simulation.xml");
335 QuantLib::ext::shared_ptr<IrLgmData> config(
new IrLgmData());
336 config->fromXML(child);
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]);
343 irDataMap[config->qualifier()] = config;
345 LOG(
"CrossAssetModelData: IR config built for key " << config->qualifier());
353 QuantLib::ext::shared_ptr<HwModelData> config(
new HwModelData());
354 config->fromXML(child);
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]);
361 irDataMap[config->qualifier()] = config;
363 LOG(
"CrossAssetModelData: HullWhite IR config built for key " << config->qualifier());
369 LOG(
"No IR model section found");
375 LOG(
"CrossAssetModelData: IR config currency " << i <<
" = " <<
irConfigs_[i]->ccy());
379 std::map<std::string, QuantLib::ext::shared_ptr<FxBsData>> fxDataMap;
385 QuantLib::ext::shared_ptr<FxBsData> config(
new FxBsData());
386 config->fromXML(child);
388 for (Size i = 0; i < config->optionExpiries().
size(); i++) {
389 LOG(
"CC-LGM calibration option " << config->optionExpiries()[i] <<
" " << config->optionStrikes()[i]);
392 fxDataMap[config->foreignCcy()] = config;
394 LOG(
"CrossAssetModelData: FX config built with key (foreign ccy) " << config->foreignCcy());
397 LOG(
"No FX Models section found");
403 LOG(
"CrossAssetModelData: FX config currency " << i <<
" = " <<
fxConfigs_[i]->foreignCcy());
407 std::map<std::string, QuantLib::ext::shared_ptr<EqBsData>> eqDataMap;
413 QuantLib::ext::shared_ptr<EqBsData> config(
new EqBsData());
414 config->fromXML(child);
416 for (Size i = 0; i < config->optionExpiries().
size(); i++) {
417 LOG(
"Cross-Asset Equity calibration option " << config->optionExpiries()[i] <<
" "
418 << config->optionStrikes()[i]);
421 eqDataMap[config->eqName()] = config;
423 LOG(
"CrossAssetModelData: Equity config built with key " << config->eqName());
426 LOG(
"No Equity Models section found");
432 LOG(
"CrossAssetModelData: EQ config name " << i <<
" = " <<
eqConfigs_[i]->eqName());
437 map<string, QuantLib::ext::shared_ptr<InflationModelData>> mp;
442 QuantLib::ext::shared_ptr<InflationModelData> imData;
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>();
450 WLOG(
"Did not recognise InflationIndexModels node with name "
451 << nodeName <<
" as a valid inflation index model so skipping it.");
455 const string& indexName = imData->index();
457 mp[indexName] = imData;
459 LOG(
"CrossAssetModelData: inflation index model data built with key " << indexName);
467 LOG(
"CrossAssetModelData: INF config name " << i <<
" = " <<
infConfigs_[i]->index());
470 LOG(
"No InflationIndexModels node found so no inflation models configured.");
475 std::map<std::string, QuantLib::ext::shared_ptr<CrLgmData>> crLgmDataMap;
476 std::map<std::string, QuantLib::ext::shared_ptr<CrCirData>> crCirDataMap;
482 QuantLib::ext::shared_ptr<CrLgmData> config(
new CrLgmData());
483 config->fromXML(child);
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]);
490 crLgmDataMap[config->name()] = config;
492 LOG(
"CrossAssetModelData: CR LGM config built for key " << config->name());
498 QuantLib::ext::shared_ptr<CrCirData> config(
new CrCirData());
499 config->fromXML(child);
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]);
506 crCirDataMap[config->name()] = config;
508 LOG(
"CrossAssetModelData: CR CIR config built for key " << config->name());
513 LOG(
"No CR model section found");
525 std::map<std::string, QuantLib::ext::shared_ptr<CommoditySchwartzData>> comDataMap;
532 config->fromXML(child);
534 for (Size i = 0; i < config->optionExpiries().
size(); i++) {
535 LOG(
"Cross-Asset Commodity calibration option " << config->optionExpiries()[i] <<
" "
536 << config->optionStrikes()[i]);
539 comDataMap[config->name()] = config;
541 LOG(
"CrossAssetModelData: Commodity config built with key " << config->name());
544 LOG(
"No Commodity Models section found");
561 LOG(
"No credit states section found");
565 LOG(
"CrossAssetModelData: adding correlations.");
566 correlations_ = QuantLib::ext::make_shared<InstantaneousCorrelations>();
571 LOG(
"CrossAssetModelData loading from XML done");
584 for (
auto const& d : irDataMap) {
585 if (d.second->ccy() == ccy) {
586 QL_REQUIRE(ccyKey.empty(),
"CrossAssetModelData: duplicate ir config for ccy " << ccy);
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");
598 if (
auto def = QuantLib::ext::dynamic_pointer_cast<HwModelData>(irDataMap[
"default"])) {
599 irConfigs_[i] = QuantLib::ext::make_shared<HwModelData>(
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());
606 }
else if (
auto def = QuantLib::ext::dynamic_pointer_cast<IrLgmData>(irDataMap[
"default"])) {
607 irConfigs_[i] = QuantLib::ext::make_shared<IrLgmData>(
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());
614 QL_FAIL(
"Unexpected model data type,expect either HwModelData or IrLgmData");
617 LOG(
"CrossAssetModelData: IR config added for ccy " <<
irConfigs_[i]->ccy());
631 if (fxDataMap.find(ccy) != fxDataMap.end())
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");
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());
646 LOG(
"CrossAssetModelData: FX config added for foreign ccy " << ccy);
656 for (Size i = 0; i <
equities_.size(); i++) {
658 if (eqDataMap.find(
name) != eqDataMap.end())
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");
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());
673 LOG(
"CrossAssetModelData: EQ config added for name " <<
name);
688 auto it = mp.find(indexName);
689 if (it != mp.end()) {
693 LOG(
"Inflation index model data missing for index " << indexName <<
" so attempt to use default");
695 auto itDefault = mp.find(
"default");
696 QL_REQUIRE(itDefault != mp.end(),
697 "Inflation index model data missing for index " << indexName <<
" and for default.");
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));
706 QL_FAIL(
"Expected inflation model data to be DK or JY.");
710 LOG(
"CrossAssetModelData: INF config added for name " << indexName);
715 std::map<std::string, QuantLib::ext::shared_ptr<CrCirData>>& crCirDataMap) {
726 if (crLgmDataMap.find(
name) != crLgmDataMap.end()) {
727 QL_REQUIRE(crCirDataMap.find(
name) == crCirDataMap.end(),
"");
729 }
else if (crCirDataMap.find(
name) != crCirDataMap.end()) {
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");
737 QuantLib::ext::shared_ptr<CrLgmData> def = crLgmDataMap[
"default"];
738 crLgmConfigs_.push_back(QuantLib::ext::make_shared<CrLgmData>(
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()));
745 LOG(
"CrossAssetModelData: CR config added for name " <<
name <<
" " <<
name);
757 if (comDataMap.find(
name) != comDataMap.end())
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");
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());
772 LOG(
"CrossAssetModelData: COM config added for name " <<
name);
789 discretization_ == CrossAssetModel::Discretization::Exact ?
"Exact" :
"Euler");
792 for (Size irConfigs_Iterator = 0; irConfigs_Iterator <
irConfigs_.size(); irConfigs_Iterator++) {
798 for (Size fxConfigs_Iterator = 0; fxConfigs_Iterator <
fxConfigs_.size(); fxConfigs_Iterator++) {
804 for (Size eqConfigs_Iterator = 0; eqConfigs_Iterator <
eqConfigs_.size(); eqConfigs_Iterator++) {
810 for (Size infConfigs_Iterator = 0; infConfigs_Iterator <
infConfigs_.size(); infConfigs_Iterator++) {
816 for (Size crLgmConfigs_Iterator = 0; crLgmConfigs_Iterator <
crLgmConfigs_.size(); crLgmConfigs_Iterator++) {
820 for (Size crCirConfigs_Iterator = 0; crCirConfigs_Iterator <
crCirConfigs_.size(); crCirConfigs_Iterator++) {
826 for (Size comConfigs_Iterator = 0; comConfigs_Iterator <
comConfigs_.size(); comConfigs_Iterator++) {
837 return crossAssetModelNode;
841 static std::map<string, QuantExt::CrossAssetModel::Discretization> m = {
842 {
"Exact", QuantExt::CrossAssetModel::Discretization::Exact},
843 {
"Euler", QuantExt::CrossAssetModel::Discretization::Euler}};
849 QL_FAIL(
"Cannot convert \"" << s <<
"\" to QuantExt::CrossAssetStateProcess::discretization");
COM Schwartz Model Parameters.
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.
Cross Asset Model Parameters.
vector< std::string > equities_
QuantLib::ext::shared_ptr< InstantaneousCorrelations > correlations_
vector< QuantLib::ext::shared_ptr< IrModelData > > irConfigs_
vector< std::string > commodities_
vector< std::string > creditNames_
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
Size numberOfCreditStates_
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< std::string > infindices_
vector< QuantLib::ext::shared_ptr< CrLgmData > > crLgmConfigs_
vector< std::string > currencies_
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
Hull White Model Parameters.
InstantaneousCorrelations.
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)
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
static XMLNode * locateNode(XMLNode *n, const string &name="")
static string getNodeName(XMLNode *n)
Get and set a node's name.
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static string getNodeValue(XMLNode *node)
Get a node's value.
static int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
static XMLNode * getNextSibling(XMLNode *node, const string &name="")
Get a node's next sibling node.
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static void appendNode(XMLNode *parent, XMLNode *child)
configuration class for building correlation matrices
Real parseReal(const string &s)
Convert text to Real.
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Dodgson Kainth inflation model component data for the cross asset model.
Jarrow Yildirim inflation model component data for the cross asset model.
IR component data for the cross asset model.
Classes and functions for log message handling.
#define LOG(text)
Logging Macro (Level = Notice)
#define ALOG(text)
Logging Macro (Level = Alert)
#define WLOG(text)
Logging Macro (Level = Warning)
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)
std::string to_string(const LocationInfo &l)
std::vector< std::string > pairToStrings(std::pair< std::string, std::string > p)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
QuantExt::CrossAssetModel::AssetType type
string conversion utilities