32#include <ql/tuple.hpp>
38 std::map<std::string, std::string>& buildErrors) {
40 LOG(
"Build dependency graph for TodaysMarket configuration " << configuration);
43 IndexMap index = QuantLib::ext::get(boost::vertex_index, g);
44 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
49 for (
auto const& o : t) {
50 auto mapping =
params_->mapping(o, configuration);
51 for (
auto const& m : mapping) {
52 Vertex v = boost::add_vertex(g);
53 QuantLib::ext::shared_ptr<CurveSpec> spec;
58 g[v] = {o, m.first, m.second, spec,
false};
59 TLOG(
"add vertex # " << index[v] <<
": " << g[v]);
69 for (std::tie(v, vend) = boost::vertices(g); v != vend; ++v) {
70 if (g[*v].curveSpec) {
72 curveConfigs_->requiredCurveIds(g[*v].curveSpec->baseType(), g[*v].curveSpec->curveConfigID())) {
73 for (
auto const& cId : r.second) {
75 if (r.first == g[*v].curveSpec->baseType() && cId == g[*v].curveSpec->curveConfigID())
78 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
79 if (*w != *v && g[*w].curveSpec && r.first == g[*w].curveSpec->baseType() &&
80 cId == g[*w].curveSpec->curveConfigID()) {
82 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
90 buildErrors[g[*v].mapping] =
"did not find required curve id " + cId +
" of type " +
93 ") in dependency graph for configuration " + configuration;
103 for (std::tie(v, vend) = boost::vertices(g); v != vend; ++v) {
108 curveConfigs_->hasCapFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())) {
109 std::set<string> indices;
110 if(!
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->index().empty())
111 indices.insert(
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->index());
112 if(!
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->proxySourceIndex().empty())
113 indices.insert(
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->proxySourceIndex());
114 if(!
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->proxyTargetIndex().empty())
115 indices.insert(
curveConfigs_->capFloorVolCurveConfig(g[*v].curveSpec->curveConfigID())->proxyTargetIndex());
116 for (
auto const& ind : indices) {
118 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
121 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
129 buildErrors[g[*v].mapping] =
"did not find required ibor index " + ind +
" (required from " +
131 ") in dependency graph for configuration " + configuration;
138 curveConfigs_->hasCorrelationCurveConfig(g[*v].curveSpec->curveConfigID())) {
139 auto config =
curveConfigs_->correlationCurveConfig(g[*v].curveSpec->curveConfigID());
142 bool found1 = config->index1().empty(), found2 = config->index2().empty();
143 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
145 if (g[*w].
name == config->index1()) {
148 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
151 if (g[*w].
name == config->index1()) {
154 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
159 if (found1 && found2)
163 buildErrors[g[*v].mapping] =
"did not find required swap index " + config->index1() +
165 ") in dependency graph for configuration " + configuration;
167 buildErrors[g[*v].mapping] =
"did not find required swap index " + config->index2() +
169 ") in dependency graph for configuration " + configuration;
176 curveConfigs_->hasSwaptionVolCurveConfig(g[*v].curveSpec->curveConfigID())) {
177 auto config =
curveConfigs_->swaptionVolCurveConfig(g[*v].curveSpec->curveConfigID());
178 std::set<std::string> indexBases;
179 if (!config->shortSwapIndexBase().empty())
180 indexBases.insert(config->shortSwapIndexBase());
181 if (!config->swapIndexBase().empty())
182 indexBases.insert(config->swapIndexBase());
183 if (!config->proxySourceShortSwapIndexBase().empty())
184 indexBases.insert(config->proxySourceShortSwapIndexBase());
185 if (!config->proxySourceSwapIndexBase().empty())
186 indexBases.insert(config->proxySourceSwapIndexBase());
187 if (!config->proxyTargetShortSwapIndexBase().empty())
188 indexBases.insert(config->proxyTargetShortSwapIndexBase());
189 if (!config->proxyTargetSwapIndexBase().empty())
190 indexBases.insert(config->proxyTargetSwapIndexBase());
191 for (
auto const& indexBase : indexBases) {
193 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
195 if (g[*w].
name == indexBase) {
198 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
207 buildErrors[g[*v].mapping] =
"did not find required swap index " + indexBase +
" (required from " +
209 ") in dependency graph for configuration " + configuration;
216 bool foundIbor =
false, foundDiscount =
false;
217 std::string swapIndex = g[*v].name;
218 auto swapCon = QuantLib::ext::dynamic_pointer_cast<data::SwapIndexConvention>(conventions->get(swapIndex));
219 QL_REQUIRE(swapCon,
"Did not find SwapIndexConvention for " << swapIndex);
220 auto con = QuantLib::ext::dynamic_pointer_cast<data::IRSwapConvention>(conventions->get(swapCon->conventions()));
222 QuantLib::ext::dynamic_pointer_cast<data::OisConvention>(conventions->get(swapCon->conventions()));
224 QuantLib::ext::dynamic_pointer_cast<data::AverageOisConvention>(conventions->get(swapCon->conventions()));
225 std::string indexName;
227 indexName = con->indexName();
229 indexName = conOisComp->indexName();
231 indexName = conOisAvg->indexName();
233 QL_FAIL(
"DependencyGraph: internal errors, expected IRSwapConvention, OisConvention, "
234 "AverageOisConvention for '"
235 << swapCon->conventions() <<
"' from conventions for swap index '" << swapIndex <<
"'");
237 std::string discountIndex = g[*v].mapping;
240 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
243 if (g[*w].
name == discountIndex) {
245 foundDiscount =
true;
246 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
249 if (g[*w].
name == indexName) {
252 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
258 if (foundDiscount && foundIbor)
262 buildErrors[g[*v].mapping] =
"did not find required ibor/ois index " + indexName +
" (required from " +
266 buildErrors[g[*v].mapping] =
"did not find required discount index " + discountIndex +
268 ") in dependency graph for configuration " + configuration;
272 if (
curveConfigs_->hasYieldCurveConfig(g[*v].curveSpec->curveConfigID())) {
273 QuantLib::ext::shared_ptr<YieldCurveConfig> config =
274 curveConfigs_->yieldCurveConfig(g[*v].curveSpec->curveConfigID());
275 vector<QuantLib::ext::shared_ptr<YieldCurveSegment>> segments = config->curveSegments();
276 for (
auto s : segments) {
277 if (
auto ccSegment = QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(s)) {
278 if (ccSegment->foreignDiscountCurveID() ==
"") {
280 std::string ccy = config->currency();
281 std::string spot = ccSegment->spotRateID();
282 std::string foreignCcy;
284 if (
auto fxq = QuantLib::ext::dynamic_pointer_cast<FXSpotQuote>(spotDatum))
285 foreignCcy = ccy == fxq->unitCcy() ? fxq->ccy() : fxq->unitCcy();
287 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
291 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #"
292 << index[*w] <<
" " << g[*w]);
305 bool foundDiscount =
false, foundEqCurve =
false;
306 std::string eqName = g[*v].name;
307 auto eqVolSpec = QuantLib::ext::dynamic_pointer_cast<EquityVolatilityCurveSpec>(g[*v].curveSpec);
308 QL_REQUIRE(eqVolSpec,
"could not cast to EquityVolatilityCurveSpec");
309 std::string ccy = eqVolSpec->ccy();
310 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
314 foundDiscount =
true;
315 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
321 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
326 if (foundDiscount && foundEqCurve)
330 buildErrors[g[*v].mapping] =
"did not find required discount curve " + ccy +
" (required from " +
334 buildErrors[g[*v].mapping] =
"did not find required equity curve " + eqName +
" (required from " +
342 bool foundDiscount =
false, foundCommCurve =
false;
343 std::string commName = g[*v].name;
344 auto commVolSpec = QuantLib::ext::dynamic_pointer_cast<CommodityVolatilityCurveSpec>(g[*v].curveSpec);
345 QL_REQUIRE(commVolSpec,
"could not cast to CommodityVolatilityCurveSpec");
346 std::string ccy = commVolSpec->currency();
347 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
351 foundDiscount =
true;
352 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
357 foundCommCurve =
true;
358 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
363 if (foundDiscount && foundCommCurve)
367 buildErrors[g[*v].mapping] =
"did not find required discount curve " + ccy +
" (required from " +
371 buildErrors[g[*v].mapping] =
"did not find required commodity curve " + commName +
" (required from " +
380 bool foundRfrIndex =
false;
381 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
386 foundRfrIndex =
true;
387 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
395 buildErrors[g[*v].mapping] =
"did not find required rfr index '" +
397 "' for replaced ibor index '" + g[*v].name +
398 "', is the rfr index configured in todays market parameters?";
405 bool foundDiscount1 =
false, foundDiscount2 =
false;
406 std::string fxName = g[*v].name;
407 auto fxSpec = QuantLib::ext::dynamic_pointer_cast<FXSpotSpec>(g[*v].curveSpec);
408 QL_REQUIRE(fxSpec,
"could not cast to FXSpotSpec");
409 std::string ccy1 = fxSpec->unitCcy();
410 std::string ccy2 = fxSpec->ccy();
411 for (std::tie(w, wend) = boost::vertices(g); w != wend; ++w) {
415 if (g[*w].
name == ccy1)
416 foundDiscount1 =
true;
417 if (g[*w].
name == ccy2)
418 foundDiscount2 =
true;
419 TLOG(
"add edge from vertex #" << index[*v] <<
" " << g[*v] <<
" to #" << index[*w] <<
" "
424 if (foundDiscount1 && foundDiscount2)
428 buildErrors[g[*v].mapping] =
"did not find required discount curve " + ccy1 +
" (required from " +
432 buildErrors[g[*v].mapping] =
"did not find required discount curve " + ccy2 +
" (required from " +
438 DLOG(
"Dependency graph built with " << boost::num_vertices(g) <<
" vertices, " << boost::num_edges(g) <<
" edges.");
void buildDependencyGraph(const std::string &configuration, std::map< std::string, std::string > &buildErrors)
boost::graph_traits< Graph >::vertex_iterator VertexIterator
const QuantLib::ext::shared_ptr< const CurveConfigurations > curveConfigs_
boost::property_map< Graph, boost::vertex_index_t >::type IndexMap
const QuantLib::ext::shared_ptr< TodaysMarketParameters > params_
boost::directed_graph< Node > Graph
std::map< std::string, Graph > dependencies_
boost::graph_traits< Graph >::vertex_descriptor Vertex
const IborFallbackConfig iborFallbackConfig_
const FallbackData & fallbackData(const string &iborIndex) const
bool isIndexReplaced(const string &iborIndex, const QuantLib::Date &asof=QuantLib::Date::maxDate()) const
DependencyGraph class to establish build order of marketObjects and its dependency.
Wrapper class for building Equity volatility structures.
QuantLib::ext::shared_ptr< CurveSpec > parseCurveSpec(const string &s)
function to convert a string into a curve spec
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
bool isGenericIborIndex(const string &indexName)
Return true if the indexName is that of a generic ibor index, otherwise false.
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
#define LOG(text)
Logging Macro (Level = Notice)
#define DLOG(text)
Logging Macro (Level = Debug)
#define TLOG(text)
Logging Macro (Level = Data)
std::string to_string(const LocationInfo &l)
std::set< MarketObject > getMarketObjectTypes()
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
string conversion utilities