Build QuantLib/QuantExt instrument, link pricing engine. If build() is called multiple times, reset() should be called between these calls.
75 {
76
77 DLOG(
"SyntheticCDO::build() called for trade " <<
id());
78
79
82 QuantLib::ext::shared_ptr<ReferenceDataManager> refData = engineFactory->referenceData();
83 if (refData && refData->hasData("CreditIndex", qualifier_)) {
84 auto refDatum = refData->getData("CreditIndex", qualifier_);
85 QuantLib::ext::shared_ptr<CreditIndexReferenceDatum> creditIndexRefDatum =
86 QuantLib::ext::dynamic_pointer_cast<CreditIndexReferenceDatum>(refDatum);
88 if (creditIndexRefDatum->indexFamily() == "") {
89 ALOG(
"IndexFamily is blank in credit index reference data for entity " << qualifier_);
90 }
91 } else {
92 ALOG(
"Credit index reference data missing for entity " << qualifier_ <<
", isdaSubProduct left blank");
93 }
94
96
100 Protection::Side side =
legData_.
isPayer() ? Protection::Buyer : Protection::Seller;
104 QL_REQUIRE(fixedLegData,
"Expected FixedLegData but got " <<
legData_.
legType());
105 Real runningRate = fixedLegData->rates().front();
109
110
111
112 Actual360 standardDayCounter;
113 DayCounter lastPeriodDayCounter = dayCounter == standardDayCounter ? Actual360(true) : dayCounter;
114
115
116
123
124
125 QL_REQUIRE(upfrontDate == Date() || upfrontFee_ != Null<Real>(),
126 "If upfront date is given (" << upfrontDate << "), upfront fee must be given.");
127 QL_REQUIRE(upfrontDate != Date() || upfrontFee_ == Null<Real>() ||
close_enough(upfrontFee_, 0.0),
128 "If no upfront date is given, no upfront fee should be given but got " << upfrontFee_ << ".");
129
130
131
132 QL_REQUIRE(attachmentPoint_ < detachmentPoint_, "Detachment point should be greater than attachment point.");
137
138 DLOG(
"Original tranche notional: " << origTrancheNtl);
139 DLOG(
"Original equity notional: " << origEquityNtl);
140 DLOG(
"Original senior notional: " << origSeniorNtl);
141 DLOG(
"Original attachment point: " << attachmentPoint_);
142 DLOG(
"Original detachment point: " << detachmentPoint_);
143 DLOG(
"Original total notional: " << origTotalNtl);
144
145
146 Real lostNotional = 0.0;
147 Real recoveredNotional = 0.0;
148
149
150 vector<Real> basketNotionals;
151
152 vector<string> creditCurves;
153
154
155
157
159 DLOG(
"Building constituents from basket data containing " << constituents.size() <<
" elements.");
160
161 Real totalRemainingNtl = 0.0;
162 Real totalPriorNtl = 0.0;
163
164 for (const auto& c : constituents) {
165 Real ntl = Null<Real>(), priorNotional = Null<Real>();
166 const auto& creditCurve = c.creditCurveId();
167 if (c.weightInsteadOfNotional()) {
168 ntl = c.weight() * origTotalNtl;
169 priorNotional = c.priorWeight();
170 if (priorNotional != Null<Real>()) {
171 priorNotional *= origTotalNtl;
172 }
173 } else {
174 ntl = c.notional();
175 priorNotional = c.priorNotional();
176 QL_REQUIRE(c.currency() == npvCurrency_, "The currency of basket constituent "
177 << creditCurve << " is " << c.currency()
178 << " and does not equal the trade leg currency "
179 << npvCurrency_);
180 }
181
182 if (!close(0.0, ntl) && ntl > 0.0) {
183 if (std::find(creditCurves.begin(), creditCurves.end(), creditCurve) == creditCurves.end()) {
184 DLOG(
"Adding underlying " << creditCurve <<
" with notional " << ntl);
185 creditCurves.push_back(creditCurve);
186 basketNotionals.push_back(ntl);
187 totalRemainingNtl += ntl;
188 } else {
189 StructuredTradeErrorMessage(id(), "Synthetic CDO", "Error building trade",
190 ("Invalid Basket: found a duplicate credit curve " + creditCurve +
191 ", skip it. Check the basket data for possible errors.")
192 .c_str())
193 .log();
194 }
195 } else {
196 DLOG(
"Underlying " << creditCurve <<
" notional is " << ntl <<
" so assuming a credit event occured.");
197 QL_REQUIRE(priorNotional != Null<Real>(),
198 "Expecting a valid prior notional for name " << creditCurve << ".");
199 auto recovery = c.recovery();
200 QL_REQUIRE(recovery != Null<Real>(), "Expecting a valid recovery for name " << creditCurve << ".");
201 validateWeightRec(recovery, creditCurve, "recovery");
202 lostNotional += (1.0 - recovery) * priorNotional;
203 recoveredNotional += recovery * priorNotional;
204 totalPriorNtl += priorNotional;
205 }
206 }
207
208 Real totalNtl = totalRemainingNtl + totalPriorNtl;
209 DLOG(
"All Underlyings added, total remaining notional = " << totalRemainingNtl);
210 DLOG(
"All Underlyings added, total prior notional = " << totalPriorNtl);
211 DLOG(
"All Underlyings added, total notional = " << totalNtl);
212
213 QL_REQUIRE(creditCurves.size() == basketNotionals.size(), "numbers of defaults curves ("
214 << creditCurves.size() << ") and notionals ("
215 << basketNotionals.size() << ") doesnt match");
216 Real notionalCorrectionFactor = origTotalNtl / totalNtl;
217
218 if (!close(totalNtl, origTotalNtl) && (
abs(notionalCorrectionFactor - 1.0) <= 1e-4)) {
219 ALOG(
"Trade " <<
id() <<
", sum of notionals(" << totalNtl <<
") is very close to total original notional ("
220 << origTotalNtl << "), will scale each notional by " << notionalCorrectionFactor
221 << ", check the basket data for possible errors.");
222 totalRemainingNtl = 0;
223 for (Size i = 0; i < basketNotionals.size(); i++) {
224 Real scaledNotional = basketNotionals[i] * notionalCorrectionFactor;
225 TLOG(
"Trade " <<
id() <<
", Issuer" << creditCurves[i] <<
" unscaled Notional: " << basketNotionals[i]
226 << ", scaled Notional: " << scaledNotional);
227 basketNotionals[i] = scaledNotional;
228 totalRemainingNtl += scaledNotional;
229 }
230 lostNotional *= notionalCorrectionFactor;
231 recoveredNotional *= notionalCorrectionFactor;
232 totalNtl *= notionalCorrectionFactor;
233 }
234
235 if (!close(totalRemainingNtl, origTotalNtl) && totalRemainingNtl > origTotalNtl) {
236 StructuredTradeErrorMessage(id(), "Synthetic CDO", "Error building trade",
237 ("Total remaining notional (" + std::to_string(totalRemainingNtl) +
238 ") is greater than total original notional (" +
239 std::to_string(origTotalNtl) +
240 "), check the basket data for possible errors.")
241 .c_str())
242 .log();
243 }
244
245 if (!close(totalNtl, origTotalNtl)) {
246 StructuredTradeErrorMessage(id(), "Synthetic CDO", "Error building trade",
247 ("Expected the total notional (" + std::to_string(totalNtl) + " = " +
248 std::to_string(totalRemainingNtl) + " + " + std::to_string(totalPriorNtl) +
249 ") to equal the total original notional (" + std::to_string(origTotalNtl) +
250 "), check the basket data for possible errors.")
251 .c_str())
252 .log();
253 }
254
255 DLOG(
"Finished building constituents using basket data.");
256
257 } else {
258
259 DLOG(
"Building constituents using CreditIndexReferenceDatum for ID " << qualifier_);
260
261 QL_REQUIRE(engineFactory->referenceData(),
262 "Trade " << id() << " has no basket data and there is no reference data manager.");
263 QL_REQUIRE(engineFactory->referenceData()->hasData(CreditIndexReferenceDatum::TYPE, qualifier_),
264 "Trade " << id() << " needs credit index reference data for ID " << qualifier_);
265 auto crd = QuantLib::ext::dynamic_pointer_cast<CreditIndexReferenceDatum>(
266 engineFactory->referenceData()->getData(CreditIndexReferenceDatum::TYPE, qualifier_));
267
268 Real totalRemainingWeight = 0.0;
269 Real totalPriorWeight = 0.0;
270 for (const auto& c : crd->constituents()) {
271
272 const auto&
name = c.name();
273 auto weight = c.weight();
274 validateWeightRec(weight,
name,
"weight");
275
276 if (!close(0.0, weight)) {
277 DLOG(
"Adding underlying " <<
name <<
" with weight " << weight);
278 creditCurves.push_back(
name);
279 basketNotionals.push_back(weight * origTotalNtl);
280 totalRemainingWeight += weight;
281 } else {
282 DLOG(
"Underlying " <<
name <<
" has weight " << weight <<
" so assuming a credit event occured.");
283 auto priorWeight = c.priorWeight();
284 QL_REQUIRE(priorWeight != Null<Real>(),
"Expecting a valid prior weight for name " <<
name <<
".");
285 validateWeightRec(priorWeight,
name,
"prior weight");
286 auto recovery = c.recovery();
287 QL_REQUIRE(recovery != Null<Real>(),
"Expecting a valid recovery for name " <<
name <<
".");
288 validateWeightRec(recovery,
name,
"recovery");
289 lostNotional += (1.0 - recovery) * priorWeight * origTotalNtl;
290 recoveredNotional += recovery * priorWeight * origTotalNtl;
291 totalPriorWeight += priorWeight;
292 }
293 }
294
295 Real totalWeight = totalRemainingWeight + totalPriorWeight;
296 DLOG(
"All Underlyings added, total remaining weight = " << totalRemainingWeight);
297 DLOG(
"All Underlyings added, total prior weight = " << totalPriorWeight);
298 DLOG(
"All Underlyings added, total weight = " << totalWeight);
299
300 if (!close(totalRemainingWeight, 1.0) && totalRemainingWeight > 1.0) {
301 ALOG(
"Total remaining weight is greater than 1, possible error in CreditIndexReferenceDatum");
302 }
303
304 if (!close(totalWeight, 1.0)) {
305 ALOG(
"Expected the total weight (" << totalWeight <<
" = " << totalRemainingWeight <<
" + "
306 << totalPriorWeight
307 << ") to equal 1, possible error in CreditIndexReferenceDatum");
308 }
309
310 DLOG(
"Finished building constituents using CreditIndexReferenceDatum for ID " << qualifier_);
311 }
312
313
314
315
316 Real currTotalNtl = accumulate(basketNotionals.begin(), basketNotionals.end(), 0.0);
317 QL_REQUIRE(!close(currTotalNtl, 0.0), "Trade " << id() << " has a current total notional of 0.0.");
318 Real currEquityNtl =
max(origEquityNtl - lostNotional, 0.0);
319 Real currSeniorNtl =
max(origSeniorNtl - recoveredNotional, 0.0);
320 Real currTrancheNtl = origTrancheNtl -
max(
min(recoveredNotional - origSeniorNtl, origTrancheNtl), 0.0) -
321 max(
min(lostNotional - origEquityNtl, origTrancheNtl), 0.0);
322 QL_REQUIRE(!close(currTrancheNtl, 0.0), "Trade " << id() << " has a current tranche notional of 0.0.");
323 Real adjAttachPoint = currEquityNtl / currTotalNtl;
324 Real adjDetachPoint = (currEquityNtl + currTrancheNtl) / currTotalNtl;
326
327 DLOG(
"Current tranche notional: " << currTrancheNtl);
328 DLOG(
"Current equity notional: " << currEquityNtl);
329 DLOG(
"Current senior notional: " << currSeniorNtl);
330 DLOG(
"Current attachment point: " << adjAttachPoint);
331 DLOG(
"Current detachment point: " << adjDetachPoint);
332 DLOG(
"Current total notional: " << currTotalNtl);
333
334
335 const auto& market = engineFactory->market();
336 auto cdoEngineBuilder = QuantLib::ext::dynamic_pointer_cast<CdoEngineBuilder>(engineFactory->builder("SyntheticCDO"));
337 QL_REQUIRE(cdoEngineBuilder, "Trade " << id() << " needs a valid CdoEngineBuilder.");
338 const string& config = cdoEngineBuilder->configuration(MarketContext::pricing);
339
340
341 std::vector<Handle<DefaultProbabilityTermStructure>> dpts;
342 vector<Real> recoveryRates;
343
344 if (fixedRecovery != Null<Real>()) {
345 LOG(
"Set all recovery rates to " << fixedRecovery);
346 }
347 for (Size i = 0; i < creditCurves.size(); ++i) {
348 const string& cc = creditCurves[i];
349 Real mktRecoveryRate = market->recoveryRate(cc, config)->value();
350 recoveryRates.push_back(fixedRecovery != Null<Real>() ? fixedRecovery : mktRecoveryRate);
351 auto originalCurve = market->defaultCurve(cc, config)->curve();
352 dpts.push_back(originalCurve);
353 }
354
355
356
357
358
359
360 QuantLib::ext::shared_ptr<SimpleQuote> calibrationFactor = QuantLib::ext::make_shared<SimpleQuote>(1.0);
361
362 bool calibrateConstiuentCurves = cdoEngineBuilder->calibrateConstituentCurve() &&
isIndexTranche();
363
364 if (calibrateConstiuentCurves) {
365
366
367
368 LOG(
"Use calibrated constiuent curves");
369 QuantLib::ext::shared_ptr<IndexCreditDefaultSwap> indexCDS;
370 Real cdsFairSpreads = 0.0;
371 Real cdsNpvs = 0.0;
372 try {
373 Handle<YieldTermStructure> yts =
374 market->discountCurve(ccy.code(), cdoEngineBuilder->configuration(MarketContext::pricing));
375
377
378 Schedule cdsSchedule(cdsStartDate, schedule.dates().back(),
379 schedule.tenor(), schedule.calendar(), Following,
380 schedule.terminationDateBusinessDayConvention(), schedule.rule(), false);
381 indexCDS = QuantLib::ext::make_shared<QuantExt::IndexCreditDefaultSwap>(
382 side, currTotalNtl, basketNotionals, 0.0, runningRate, cdsSchedule, bdc, dayCounter,
settlesAccrual_,
384 lastPeriodDayCounter, rebatesAccrual_);
385 Handle<DefaultProbabilityTermStructure> indexCreditCurve =
388 auto indexPricingEngine =
389 QuantLib::ext::make_shared<QuantExt::MidPointIndexCdsEngine>(indexCreditCurve, indexCdsRecovery->value(), yts);
390 indexCDS->setPricingEngine(indexPricingEngine);
391 } catch (const std::exception& e) {
392 indexCDS = nullptr;
393 WLOG(
"CDO constiuent calibration failed to build index cds. Got "
394 << e.what());
395 }
396 if (indexCDS) {
397 cdsFairSpreads = indexCDS->fairSpreadClean();
398 cdsNpvs = indexCDS->NPV();
399 }
400
401 auto it = engineFactory->engineData()->globalParameters().find("RunType");
402 if (it != engineFactory->engineData()->globalParameters().end() && it->second != "PortfolioAnalyser") {
403
404 Handle<YieldTermStructure> yts =
405 market->discountCurve(ccy.code(), cdoEngineBuilder->configuration(MarketContext::pricing));
406
407 std::vector<Handle<DefaultProbabilityTermStructure>> wrapperCurves;
408 DLOG(
"Building wrapper curves for calibration");
409 for (size_t i = 0; i < creditCurves.size(); ++i) {
410 try {
411 const string& cc = creditCurves[i];
412 auto originalCurve = market->defaultCurve(cc, config)->curve();
413 wrapperCurves.push_back(
415 } catch (const std::exception& e) {
416
417 WLOG(
"CDO constiuent calibration failed during building wrapper curve for "
418 << creditCurves[i] << ", skip this curve. Got "
419 << e.what());
420 }
421 }
422
423 if (wrapperCurves.size() == dpts.size() && indexCDS) {
424 LOG(
"Start bootstraping of the calibration factors");
425 dpts.swap(wrapperCurves);
426
427 auto cdsPricingEngineUnderlyingCurves =
428 QuantLib::ext::make_shared<QuantExt::MidPointIndexCdsEngine>(dpts, recoveryRates, yts);
429
430 indexCDS->setPricingEngine(cdsPricingEngineUnderlyingCurves);
431
432 try {
433 auto targetFunction = [&cdsNpvs, &calibrationFactor, &indexCDS](const double& factor) {
434 calibrationFactor->setValue(factor);
435 return cdsNpvs - indexCDS->NPV();
436 };
437
438 Brent solver;
439 double indexAdjustmentForUnderlyingCurves =
440 solver.solve(targetFunction, 1e-8, cdsFairSpreads / indexCDS->fairSpreadClean(), 0.001, 2);
441
442 DLOG(
"Calibration of indexterm " << io::iso_date(indexCDS->maturity())
443 << "successful, found solution "
444 << indexAdjustmentForUnderlyingCurves);
445 calibrationFactor->setValue(indexAdjustmentForUnderlyingCurves);
446 } catch (const std::exception& e) {
447 WLOG(
"Calibration failed, at pillar " << io::iso_date(indexCDS->maturity())
448 << ", set calibration factor to 1 (uncalibrated), got "
449 << e.what());
450 calibrationFactor->setValue(1.0);
451 }
452
454 LOG(
"Expiry \t CalibrationFactor \t NpvIntrinsic \t NpvIndexCurve \t NpvError \t "
455 "FairSpreadIntrinsic "
456 "\t FairSpreadIndexCurve \t FairSreadError");
457
458 LOG(io::iso_date(indexCDS->maturity())
459 << "\t" << calibrationFactor->value() << "\t" << indexCDS->NPV() << "\t" << cdsNpvs << "\t"
460 << indexCDS->NPV() - cdsNpvs << "\t" << indexCDS->fairSpreadClean() << "\t" << cdsFairSpreads
461 << "\t" << indexCDS->fairSpreadClean() - cdsFairSpreads);
462 }
463 }
464 }
465
466
467 auto pool = QuantLib::ext::make_shared<Pool>();
468
471 Handle<DefaultProbabilityTermStructure> clientCurve;
472 Handle<DefaultProbabilityTermStructure> baseCurve;
473 vector<Time> baseCurveTimes;
474 vector<Real> expLoss;
475
476 if (cdoEngineBuilder->optimizedSensitivityCalculation()) {
478 }
479
480 for (Size i = 0; i < creditCurves.size(); ++i) {
481 const string& cc = creditCurves[i];
482 DefaultProbKey key = NorthAmericaCorpDefaultKey(ccy, SeniorSec, Period(), 1.0);
484 auto defaultCurve = dpts[i];
485 expLoss.push_back((1 -
recoveryRate) * defaultCurve->defaultProbability(maturity_,
true) * basketNotionals[i]);
486 std::pair<DefaultProbKey, Handle<DefaultProbabilityTermStructure>> p(key, defaultCurve);
487 vector<pair<DefaultProbKey, Handle<DefaultProbabilityTermStructure>>> probabilities(1, p);
488
489 Issuer
issuer(probabilities, DefaultEventSet());
490 pool->add(cc, issuer, key);
491 DLOG(
"Issuer " << cc <<
" added to the pool.");
492 }
493
494
495
496 if (sensitivityDecomposition == CreditPortfolioSensitivityDecomposition::LossWeighted) {
498 Real totalWeight = std::accumulate(expLoss.begin(), expLoss.end(), 0.0);
499 for (Size basketIdx = 0; basketIdx < creditCurves.size(); basketIdx++) {
500 string& creditCurve = creditCurves[basketIdx];
501 Real weight = expLoss[basketIdx];
504 } else {
506 }
507 }
508 } else if (sensitivityDecomposition == CreditPortfolioSensitivityDecomposition::NotionalWeighted) {
510 Real totalWeight = std::accumulate(basketNotionals.begin(), basketNotionals.end(), 0.0);
511 for (Size basketIdx = 0; basketIdx < creditCurves.size(); basketIdx++) {
512 string& creditCurve = creditCurves[basketIdx];
513 Real weight = basketNotionals[basketIdx];
516 } else {
518 }
519 }
520 } else if (sensitivityDecomposition == CreditPortfolioSensitivityDecomposition::DeltaWeighted) {
522 Real totalWeight = 0;
523 for (Size basketIdx = 0; basketIdx < creditCurves.size(); basketIdx++) {
524 string& creditCurve = creditCurves[basketIdx];
525 Real
notional = basketNotionals[basketIdx];
526 auto defaultCurve = market->defaultCurve(creditCurve, config)->curve();
527 Real constituentSurvivalProb = defaultCurve->survivalProbability(maturity_);
528 Time t = defaultCurve->timeFromReference(maturity_);
529 Real CR01 = t * constituentSurvivalProb * notional;
532 totalWeight += CR01;
533 }
534
535 for (auto& decompWeight : basketConstituents_) {
536 decompWeight.second /= totalWeight;
537 }
538 }
539
540
541 bool homogeneous = all_of(basketNotionals.begin(), basketNotionals.end(),
542 [&basketNotionals](Real ntl) { return close_enough(ntl, basketNotionals[0]); });
543 homogeneous = homogeneous && all_of(recoveryRates.begin(), recoveryRates.end(),
544 [&recoveryRates](Real rr) { return close_enough(rr, recoveryRates[0]); });
545
546
547
548
549 QuantLib::ext::shared_ptr<Instrument> vanilla;
550
551
552
553 QuantLib::ext::shared_ptr<Instrument> cdoD;
555 DLOG(
"Building detachment tranche [0," << adjDetachPoint <<
"].");
556
558 QuantLib::ext::make_shared<QuantExt::Basket>(schedule[0], creditCurves, basketNotionals, pool, 0.0, adjDetachPoint);
560 cdoEngineBuilder->lossModel(
qualifier(), recoveryRates, adjDetachPoint,
561 maturity_, homogeneous));
562
563 auto cdoDetach =
564 QuantLib::ext::make_shared<QuantExt::SyntheticCDO>(
basket, side, schedule, 0.0, runningRate, dayCounter, bdc,
566
567 cdoDetach->setPricingEngine(
568 cdoEngineBuilder->engine(ccy, false, {}, calibrationFactor, fixedRecovery));
570 cdoD = cdoDetach;
571
572 DLOG(
"Detachment tranche [0," << adjDetachPoint <<
"] built.");
573
574 } else {
575 DLOG(
"Detachment point is 1.0 so building an index CDS for [0,1.0] 'tranche'.");
576
577
578
579
580
581 auto cds = QuantLib::ext::make_shared<QuantExt::IndexCreditDefaultSwap>(
582 side, currTotalNtl, basketNotionals, 0.0, runningRate, schedule, bdc, dayCounter,
settlesAccrual_,
584 lastPeriodDayCounter, rebatesAccrual_, protectionStartDate, 3);
585
586 cds->setPricingEngine(
587 cdoEngineBuilder->engine(ccy, true, creditCurves, calibrationFactor, fixedRecovery));
589 cdoD = cds;
590
591 DLOG(
"Index CDS for [0,1.0] 'tranche' built.");
592 }
593
594
595
596
597
599 DLOG(
"Attachment point is 0 so the instrument is built.");
600 vanilla = cdoD;
601 } else {
602 DLOG(
"Building attachment tranche [0," << adjAttachPoint <<
"].");
603
604
606 QuantLib::ext::make_shared<QuantExt::Basket>(schedule[0], creditCurves, basketNotionals, pool, 0.0, adjAttachPoint);
607 basket->setLossModel(cdoEngineBuilder->lossModel(
qualifier(), recoveryRates, adjAttachPoint,
608 maturity_, homogeneous));
609
610 auto cdoA =
613
614 cdoA->setPricingEngine(
615 cdoEngineBuilder->engine(ccy, false, {}, calibrationFactor, fixedRecovery));
617
618 DLOG(
"Attachment tranche [0," << adjAttachPoint <<
"] built.");
619
620 DLOG(
"Building attachment and detachment composite instrument.");
621
622 auto composite = QuantLib::ext::make_shared<CompositeInstrument>();
623 composite->add(cdoD);
624 composite->subtract(cdoA);
625 vanilla = composite;
626
627 DLOG(
"Attachment and detachment composite instrument built.");
628 }
629
630
631
632
633 if (upfrontDate != Date()) {
634 vector<QuantLib::ext::shared_ptr<Instrument>> insts;
635 vector<Real> mults;
637 string configuration = cdoEngineBuilder->configuration(MarketContext::pricing);
639 std::max(maturity_,
addPremiums(insts, mults, 1.0, PremiumData(upfrontAmount, ccy.code(), upfrontDate),
640 side == Protection::Buyer ? -1.0 : 1.0, ccy, engineFactory, configuration));
641
642 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(vanilla, 1.0, insts, mults);
643
644 } else {
645
646 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(vanilla);
647 }
648
651
652 DLOG(
"CDO instrument built");
653}
const boost::shared_ptr< QuantExt::Basket > & basket() const
const std::vector< BasketConstituent > & constituents() const
const string & paymentConvention() const
const string & currency() const
const ScheduleData & schedule() const
const string & legType() const
const string & dayCounter() const
QuantLib::ext::shared_ptr< LegAdditionalData > concreteLegData() const
const vector< double > & notionals() const
bool isIndexTranche() const
const string & upfrontDate() const
const LegData & leg() const
const string & qualifier() const
Inspectors.
static QuantLib::Handle< QuantLib::DefaultProbabilityTermStructure > buildCalibratedConstiuentCurve(const QuantLib::Handle< QuantLib::DefaultProbabilityTermStructure > &curve, const QuantLib::ext::shared_ptr< SimpleQuote > &calibrationFactor)
const QuantLib::Date & indexStartDateHint() const
std::map< std::string, double > basketConstituents_
std::string creditCurveIdWithTerm() const
const string & issuer() const
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
Date addPremiums(std::vector< QuantLib::ext::shared_ptr< Instrument > > &instruments, std::vector< Real > &multipliers, const Real tradeMultiplier, const PremiumData &premiumData, const Real premiumMultiplier, const Currency &tradeCurrency, const QuantLib::ext::shared_ptr< EngineFactory > &factory, const string &configuration)
void setSensitivityTemplate(const EngineBuilder &builder)
virtual QuantLib::Real notional() const
Return the current notional in npvCurrency. See individual sub-classes for the precise definition.
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
#define LOG(text)
Logging Macro (Level = Notice)
#define DLOG(text)
Logging Macro (Level = Debug)
#define ALOG(text)
Logging Macro (Level = Alert)
#define WLOG(text)
Logging Macro (Level = Warning)
#define TLOG(text)
Logging Macro (Level = Data)
RandomVariable max(RandomVariable x, const RandomVariable &y)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
RandomVariable abs(RandomVariable x)
RandomVariable min(RandomVariable x, const RandomVariable &y)
QuantLib::Handle< QuantExt::CreditCurve > indexCdsDefaultCurve(const QuantLib::ext::shared_ptr< Market > &market, const std::string &creditCurveId, const std::string &config)
std::vector< Handle< DefaultProbabilityTermStructure > > buildPerformanceOptimizedDefaultCurves(const std::vector< Handle< DefaultProbabilityTermStructure > > &curves)
CreditPortfolioSensitivityDecomposition
Enumeration CreditPortfolioSensitivityDecomposition.
Leg makeFixedLeg(const LegData &data, const QuantLib::Date &openEndDateReplacement)
Schedule makeSchedule(const ScheduleDates &data)