Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
MonteCarloCBOEngine Class Reference

CBO engine, Monte Carlo for the sample payoff. More...

#include <qle/pricingengines/cbomcengine.hpp>

+ Inheritance diagram for MonteCarloCBOEngine:
+ Collaboration diagram for MonteCarloCBOEngine:

Public Member Functions

 MonteCarloCBOEngine (QuantLib::ext::shared_ptr< RandomDefaultModel > rdm, Size samples=1000, Size bins=20, double errorTolerance=1.0e-6, std::vector< QuantLib::Period > lossDistributionPeriods=std::vector< QuantLib::Period >())
 
void calculate () const override
 

Private Member Functions

void interestWaterfall (Size sampleIndex, Size dateIndex, const vector< Date > &dates, map< Currency, vector< Cash > > &basketFlow, map< Currency, Cash > &trancheFlow, map< Currency, vector< vector< Real > > > &balance, map< Currency, Real > &interest, map< Currency, Real > &interestAcc, Real cureAmount) const
 interest waterfall More...
 
void icocInterestWaterfall (Size i, Size j, Size k, const vector< Date > &dates, map< Currency, vector< Cash > > &iFlows, vector< map< Currency, Cash > > &tranches, vector< map< Currency, vector< vector< Real > > > > &balances, Real cureAmount) const
 icoc interest waterfall More...
 
void principalWaterfall (Size sampleIndex, Size dateIndex, const vector< Date > &dates, map< Currency, vector< Cash > > &basketFlow, map< Currency, Cash > &trancheFlow, map< Currency, vector< vector< Real > > > &balance, map< Currency, Real > &interest) const
 pricipal waterfall More...
 
Real icocCureAmount (Size sampleIndex, Size dateIndex, Size trancheNo, Real basketNotional, Real basketInterest, vector< map< Currency, vector< vector< Real > > > > &trancheBalances, vector< Real > trancheInterestRates, Real icRatios, Real ocRatios) const
 icoc cure amount More...
 
std::map< QuantLib::Date, std::string > getLossDistributionDates (const QuantLib::Date &valuationDate) const
 Return dates on the CBO schedule that are closest to the requested lossDistributionPeriods. More...
 

Private Attributes

QuantLib::ext::shared_ptr< RandomDefaultModel > rdm_
 
Size samples_
 
Size bins_
 
double errorTolerance_
 
std::vector< QuantLib::Period > lossDistributionPeriods_
 Periods from valuation date for which to return loss distributions. More...
 

Additional Inherited Members

- Protected Member Functions inherited from CBO::engine
virtual void initialize () const
 
- Protected Attributes inherited from CBO::engine
QuantLib::ext::shared_ptr< BondBasketremainingBasket_
 

Detailed Description

CBO engine, Monte Carlo for the sample payoff.

This class implements the waterfall structures and Monte Carlo pricing of the cash flow CBO.

For more information refer to the detailed QuantExt documentation.

Definition at line 48 of file cbomcengine.hpp.

Constructor & Destructor Documentation

◆ MonteCarloCBOEngine()

MonteCarloCBOEngine ( QuantLib::ext::shared_ptr< RandomDefaultModel >  rdm,
Size  samples = 1000,
Size  bins = 20,
double  errorTolerance = 1.0e-6,
std::vector< QuantLib::Period >  lossDistributionPeriods = std::vector<QuantLib::Period>() 
)
Parameters
rdmRandom default model for generating samples of default times for the portfolio of names
samplesNumber of Monte Carlo samples
binsDiscretization for resulting distributions
errorTolerancenpvError tolerance
lossDistributionPeriodsPeriods from valuation date for which to return loss distributions

Definition at line 50 of file cbomcengine.hpp.

64 : rdm_(rdm), samples_(samples), bins_(bins), errorTolerance_(errorTolerance),
65 lossDistributionPeriods_(lossDistributionPeriods) {}
QuantLib::ext::shared_ptr< RandomDefaultModel > rdm_
Definition: cbomcengine.hpp:94
std::vector< QuantLib::Period > lossDistributionPeriods_
Periods from valuation date for which to return loss distributions.

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 225 of file cbomcengine.cpp.

225 {
226
227 Date today = Settings::instance().evaluationDate();
228 initialize(); //set the underlying Basket
229 rdm_->reset();
230
231 // Prepare additional results for loss distributions if they have been requested
232 map<Date, string> lossDistributionDates = getLossDistributionDates(today);
233 vector<Date> lossDistributionDatesVector;
234 map<string, QuantLib::ext::shared_ptr<BucketedDistribution> > lossDistributionMap;
235 if (!lossDistributionDates.empty()) {
236
237 // calculate max loss from the pool
238 Real maxLoss = 0.0;
239 for (auto& bonds : arguments_.basket->bonds()) {
240 string name = bonds.first;
241 maxLoss += bonds.second->notional(today) * arguments_.basket->multiplier(name) * (1.0 - arguments_.basket->recoveryRate(name));
242 }
243
244 // initialise the Loss BucketedDistribtions with the above maxLoss
245 Size numBuckets = 100;
246 for (map<Date, string>::iterator it = lossDistributionDates.begin(); it != lossDistributionDates.end(); it++) {
247 QuantLib::ext::shared_ptr<BucketedDistribution> bucketedDistribution =
248 QuantLib::ext::make_shared<BucketedDistribution> (0, maxLoss, numBuckets);
249 // Set all probabilities = 0.0;
250 for (Size i = 0; i < numBuckets; i++)
251 bucketedDistribution->probabilities()[i] = 0.0;
252 lossDistributionMap[it->second] = bucketedDistribution;
253
254 lossDistributionDatesVector.push_back(it->first);
255 }
256 }
257
258 //get date grid, dependending on tranche (to be valued)
259 vector<Date> dates = arguments_.schedule.dates();
260
261 //adjust the date grid, such that it starts with today
262 std::vector<Date>::iterator it;
263 for (it=dates.begin(); it<dates.end(); ++it)
264 if(*it > today) break;
265
266 dates.erase(dates.begin(), it);
267 dates.insert(dates.begin(), today);
268
269 Real tmax = 1.0 + ActualActual(ActualActual::ISDA).yearFraction(today, dates.back());
270
271 arguments_.basket->fillFlowMaps();
272
273 arguments_.basket->setGrid(dates);
274
275 //other requirements
276 DayCounter feeDayCount = arguments_.feeDayCounter;
277 Currency ccy = arguments_.ccy;
278
279 //asset flows
280 map<Currency, vector<Cash> > cf;
281 map<Currency, vector<Cash> > iFlows;
282 map<Currency, vector<Cash> > pFlows;
283 map<Currency, vector<Real> > basketNotional;
284
285 //liability flows
286 vector<Real> basketValue(samples_, 0.0);
287 vector<vector<Real> > trancheValue;
288 vector<Tranche> tranches = arguments_.tranches;
289 for (Size i = 0 ; i < tranches.size() ; i ++){
290 vector<Real> tempTrancheValue(samples_, 0.0);
291 trancheValue.push_back(tempTrancheValue);
292 }
293
294 vector <map<Currency, vector<vector<Real> > > > trancheBalance;
295 trancheBalance.resize(tranches.size());
296 for (Size i = 0 ; i < tranches.size() ; i ++){
297 trancheBalance[i][ccy].resize(
298 dates.size(), vector<Real>(samples_, 0.0));
299 }
300
301 vector<Real> feeValue(samples_, 0.0);
302 vector<Real> subfeeValue(samples_, 0.0);
303
304 /*
305 //prepare for convergence analysis
306 bool convergenceFlag = false;
307 std::vector<double> runningMean(tranches.size(),0.0);
308 std::vector<double> runningStdev(tranches.size(),0.0);
309 if(ore::data::Log::instance().filter(ORE_DATA)){
310 TLOG("convergence analysis - check first two moments");
311 std::ostringstream labels;
312 labels << "sample";
313 for(Size k = 0 ; k < tranches.size(); k++)
314 labels << "," << tranches[k].name << "-mean,"<< tranches[k].name << "-stdev";
315 TLOG(labels.str());
316 convergenceFlag = true;
317 }
318 */
319
320 for (Size i = 0; i < samples_; i++) {
321 rdm_->nextSequence(tmax);
322
323 for( Size k = 0 ; k < tranches.size() ; k++){
324 trancheBalance[k][ccy][0][i] = arguments_.tranches[k].faceAmount;
325 }
326
327 vector< map<Currency, Real> >trancheInterest;
328 trancheInterest.resize(tranches.size());
329 for( Size k = 0 ; k < tranches.size() ; k++){
330 trancheInterest[k][ccy] = 0.0;
331 }
332
333 //Get Collection from bondbasket and exchange into base currency...
334 cf.clear();
335 iFlows.clear();
336 pFlows.clear();
337 basketNotional.clear();
338
339 map<Currency, vector<Cash> > cf_full = arguments_.basket->scenarioCashflow(dates);
340 map<Currency, vector<Cash> > iFlows_full = arguments_.basket->scenarioInterestflow(dates);
341 map<Currency, vector<Cash> > pFlows_full = arguments_.basket->scenarioPrincipalflow(dates);
342 map<Currency, vector<Real> > basketNotional_full = arguments_.basket->scenarioRemainingNotional(dates);
343
344 set<Currency> basketCurrency = arguments_.basket->unique_currencies();
345
346 if(basketCurrency.size() > 1){
347
348 vector<Cash> cf_single;
349 vector<Cash> iFlows_single;
350 vector<Cash> pFlows_single;
351 vector<Real> basketNotional_single;
352
353 for(size_t d = 0; d < dates.size(); d++){
354
355 double cf1 = 0.0;
356 double cf2 = 0.0;
357 double if1 = 0.0;
358 double if2 = 0.0;
359 double pf1 = 0.0;
360 double pf2 = 0.0;
361 //Cash pf(0.0, 0.0);
362 double bn = 0.0;
363
364 for(auto& basketCcy : basketCurrency){
365 cf1 += arguments_.basket->convert(cf_full[basketCcy][d].flow_, basketCcy, dates[d]);
366 cf2 += arguments_.basket->convert(cf_full[basketCcy][d].discountedFlow_, basketCcy, dates[d]);
367
368 if1 += arguments_.basket->convert(iFlows_full[basketCcy][d].flow_, basketCcy, dates[d]);
369 if2 += arguments_.basket->convert(iFlows_full[basketCcy][d].discountedFlow_, basketCcy, dates[d]);
370
371 pf1 += arguments_.basket->convert(pFlows_full[basketCcy][d].flow_, basketCcy, dates[d]);
372 pf2 += arguments_.basket->convert(pFlows_full[basketCcy][d].discountedFlow_, basketCcy, dates[d]);
373
374 bn += arguments_.basket->convert(basketNotional_full[basketCcy][d], basketCcy, dates[d]);
375 }
376 cf_single.push_back(Cash(cf1, cf2));
377 iFlows_single.push_back(Cash(if1,if2));
378 pFlows_single.push_back(Cash(pf1,pf2));
379 basketNotional_single.push_back(bn);
380 }
381 cf[ccy] = cf_single;
382 iFlows[ccy] = iFlows_single;
383 pFlows[ccy] = pFlows_single;
384 basketNotional[ccy] = basketNotional_single;
385
386 }
387 else{
388 cf = cf_full;
389 iFlows = iFlows_full;
390 pFlows = pFlows_full;
391 basketNotional = basketNotional_full;
392 }
393
394 for (Size j = 1; j < dates.size(); j++) {
395
396 //Back out discountfactors
397
398 Real intCcyDis = (iFlows[ccy][j].flow_ > 0 ?
399 iFlows[ccy][j].discountedFlow_ / iFlows[ccy][j].flow_ :
400 0.0);
401
402 /**************************************************************
403 * check flows add up
404 */
405 Real tiny = 1.0e-6;
406 Real flowsCheck = fabs(cf[ccy][j].flow_
407 -iFlows[ccy][j].flow_
408 -pFlows[ccy][j].flow_);
409 QL_REQUIRE( flowsCheck < tiny,
410 "Interest and Principal Flows don't sum to Total: "
411 << flowsCheck);
412
413 Real dfFlowsCheck = fabs(cf[ccy][j].discountedFlow_
414 -iFlows[ccy][j].discountedFlow_
415 -pFlows[ccy][j].discountedFlow_);
416
417 QL_REQUIRE( dfFlowsCheck < tiny,
418 "discounted Interest and Principal Flows don't sum to Total: "
419 << dfFlowsCheck);
420
421 /**************************************************************
422 * tranche interest claim
423 */
424 vector<map<Currency, Real> >trancheIntAcc;
425 trancheIntAcc.resize(tranches.size());
426 vector<Real> trancheInterestRates;
427 // ccy
428 for (Size k = 0 ; k< tranches.size(); k++){
429 Real trancheInterestRate =
430 tranches[k].leg[j-1]->amount()/
431 tranches[k].faceAmount;
432 trancheInterestRates.push_back(trancheInterestRate);
433 //ccy
434 trancheIntAcc[k][ccy] = trancheBalance[k][ccy][j-1][i]
435 * (trancheInterestRate);
436 trancheInterest[k][ccy] += trancheIntAcc[k][ccy];
437 trancheBalance[k][ccy][j][i]
438 = trancheBalance[k][ccy][j-1][i];
439 }
440 /**************************************************************
441 * Collections
442 */
443 Real ccyDFlow = cf[ccy][j].discountedFlow_;
444 Real basketInterest = iFlows[ccy][j].flow_; //for cure amount calc
445
446 /**************************************************************
447 * Senior fees
448 */
449 Real ccyFeeClaim = basketNotional[ccy][j] * arguments_.seniorFee
450 * feeDayCount.yearFraction(dates[j-1], dates[j]);
451
452 Real ccyFeeFlow = std::min(ccyFeeClaim, iFlows[ccy][j].flow_);
453
454 iFlows[ccy][j].flow_ -= ccyFeeFlow;
455 iFlows[ccy][j].discountedFlow_ -= ccyFeeFlow * intCcyDis;
456
457 cf[ccy][j].flow_ -= ccyFeeFlow;
458 cf[ccy][j].discountedFlow_ -= ccyFeeFlow * intCcyDis;
459
460 feeValue[i] += ccyFeeFlow * intCcyDis;
461
462 QL_REQUIRE(cf[ccy][j].flow_ >= 0.0, "ccy flows < 0");
463
464
465 /**************************************************************
466 * tranche waterfall
467 */
468 vector<map<Currency, Real> > trancheAmortization;
469 vector<map<Currency, Cash> > tranche;
470 trancheAmortization.resize(tranches.size());
471 tranche.resize(tranches.size());
472
473 //Interest Waterfall incl. ICOC
474 for (Size k = 0 ; k < tranches.size() ; k++){
475
476 tranche[k][ccy].flow_ = 0.;
477 tranche[k][ccy].discountedFlow_ = 0.;
478
479 Real icRatio = arguments_.tranches[k].icRatio;
480 Real ocRatio = arguments_.tranches[k].ocRatio;
481
482 //IC and OC Target Balances
483 Real cureAmount = icocCureAmount(i,j,k,
484 basketNotional[ccy][j],
485 basketInterest,
486 trancheBalance,
487 trancheInterestRates,
488 icRatio,
489 ocRatio);
490
491 interestWaterfall(i, j, dates, iFlows,
492 tranche[k], trancheBalance[k],
493 trancheInterest[k],
494 trancheIntAcc[k], cureAmount);
495
496 icocInterestWaterfall(i, j, k, dates, iFlows,
497 tranche, trancheBalance,
498 cureAmount);
499
500 }
501
502 //Principal Waterfall
503 for (Size k = 0 ; k < tranches.size() ; k++){
504
505 principalWaterfall(i, j, dates, pFlows,
506 tranche[k], trancheBalance[k],
507 trancheInterest[k]);
508
509 cf[ccy][j].flow_ -= tranche[k][ccy].flow_;
510 cf[ccy][j].discountedFlow_ -= tranche[k][ccy].discountedFlow_;
511
512 }
513
514 /**************************************************************
515 * Subordinated Fee
516 */
517
518 Real ccysubFeeClaim = basketNotional[ccy][j] * arguments_.subordinatedFee
519 * feeDayCount.yearFraction(dates[j-1], dates[j]);
520
521 Real ccysubFeeFlow = std::min(ccysubFeeClaim, iFlows[ccy][j].flow_);
522
523 iFlows[ccy][j].flow_ -= ccysubFeeFlow;
524 iFlows[ccy][j].discountedFlow_ -= ccysubFeeFlow * intCcyDis;
525
526 cf[ccy][j].flow_ -= ccysubFeeFlow;
527 cf[ccy][j].discountedFlow_ -= ccysubFeeFlow * intCcyDis;
528
529 subfeeValue[i] += ccysubFeeFlow * intCcyDis;
530 QL_REQUIRE(cf[ccy][j].flow_ >= -1.0E-5, "ccy flows < 0");
531
532 /**************************************************************
533 * Kicker:
534 * Split excess flows between equity tranche (1-x) and senior fee (x)
535 */
536 Real x = arguments_.equityKicker;
537
538 Cash residual(0.0, 0.0);
539 residual.discountedFlow_ = pFlows[ccy][j].discountedFlow_ + iFlows[ccy][j].discountedFlow_;
540 residual.flow_ = pFlows[ccy][j].flow_ + iFlows[ccy][j].flow_;
541
542 tranche.back()[ccy].flow_ += residual.flow_ * (1 - x);
543 tranche.back()[ccy].discountedFlow_ += residual.discountedFlow_ * (1 - x);
544
545 feeValue[i] += residual.discountedFlow_ * x;
546
547 cf[ccy][j].flow_ -= residual.flow_;
548 cf[ccy][j].discountedFlow_ -= residual.discountedFlow_;
549
550
551 /**************************************************************
552 * Consistency checks
553 */
554 QL_REQUIRE(cf[ccy][j].flow_ >= -1.e-5, "residual ccy flow < 0: "<<
555 cf[ccy][j].flow_);
556
557 QL_REQUIRE(ccyFeeFlow >= -1.e-5, "ccy fee flow < 0");
558
559 for(Size k = 0; k < tranches.size() ; k++){
560 QL_REQUIRE(tranche[k][ccy].flow_ >= -1.e-5, "ccy "<<
561 tranches[k].name <<" flow < 0: "
562 <<tranche[k][ccy].flow_);
563 }
564
565
566 basketValue[i] += ccyDFlow;
567 for(Size k = 0 ; k < tranches.size() ; k ++){
568 trancheValue[k][i] += tranche[k][ccy].discountedFlow_;
569 }
570 Real tranchenpvError(0.);
571 for(Size k = 0 ; k < tranches.size() ; k ++){
572 tranchenpvError +=trancheValue[k][i];
573 }
574 Real npvError(0.);
575 if(basketValue[i] > 0.){
576 npvError = (feeValue[i] + subfeeValue[i] + tranchenpvError) / basketValue[i] - 1.0;
577 if(fabs(npvError) > errorTolerance_)
578 //ALOG("NPVs do not add up, rel. error " << npvError);
579 QL_FAIL("NPVs do not add up, rel. error " << npvError);
580 }
581
582 QL_REQUIRE(basketValue[i] >= 0.0,
583 "negative basket value " << basketValue[i]);
584
585 } // end dates
586
587 /**************************************************************
588 * Loss Distribution
589 */
590 if (!lossDistributionDates.empty()) {
591 // get the losses on this sample for each date
592 map<Currency, vector<Cash> >
593 lossDist = arguments_.basket->scenarioLossflow(lossDistributionDatesVector);
594
595 // foreach date, we see what bucket our loss falls into and we increase the probability for
596 // that bucket by 1/samples
597 for (Size k = 0; k < lossDistributionDatesVector.size(); k++) {
598 Real loss = lossDist[ccy][k].flow_;
599 Date d = lossDistributionDatesVector[k];
600 string dateString = lossDistributionDates[d];
601
602 QuantLib::ext::shared_ptr<BucketedDistribution> bd = lossDistributionMap[dateString];
603 Size index = bd->bucket(loss); // find the bucket we need to update
604 bd->probabilities()[index] += 1.0 / samples_;
605 }
606 }
607
608 /*
609 //convergence
610 if(convergenceFlag){
611 std::ostringstream meanStev;
612 meanStev << i << fixed << setprecision(2);
613 for(Size k = 0 ; k < tranches.size(); k++){
614 runningMean[k] += trancheValue[k][i];
615 double mean = runningMean[k] / (i + 1);
616 meanStev << "," << mean;
617 runningStdev[k] += trancheValue[k][i]*trancheValue[k][i];
618 double stdev = sqrt(runningStdev[k] / (i + 1) - mean * mean);
619 meanStev << "," << stdev;
620 }
621 TLOG(meanStev.str());
622 }
623 */
624 } // end samples
625
626 //handle results...
627 Stats basketStats(basketValue);
628 vector<Stats> trancheStats;
629
630 for(Size i = 0 ; i < tranches.size(); i++){
631 Stats trancheStat(trancheValue[i]);
632 trancheStats.push_back(trancheStat);
633 }
634 Stats feeStats(feeValue);
635 Stats subfeeStats(subfeeValue);
636
637 results_.basketValue = basketStats.mean();
638 for(Size i = 0 ;i < tranches.size(); i ++){
639 results_.trancheValue.push_back(trancheStats[i].mean());
640 }
641 results_.feeValue = feeStats.mean();
642 results_.subfeeValue = subfeeStats.mean();
643
644 results_.basketValueStd = basketStats.std();
645 for(Size i = 0 ;i < tranches.size(); i ++){
646 results_.trancheValueStd.push_back( trancheStats[i].std());
647 }
648 results_.feeValueStd = feeStats.std();
649 results_.subfeeValueStd = subfeeStats.std();
650
651 //distribution output
652 Distribution basketDist = basketStats.histogram(bins_);
653 results_.additionalResults["BasketDistribution"] = basketDist;
654 Distribution feeDist = feeStats.histogram(bins_);
655 results_.additionalResults["SeniorFeeDistribution"] = feeDist;
656 Distribution subfeeDist = subfeeStats.histogram(bins_);
657 results_.additionalResults["SubFeeDistribution"] = subfeeDist;
658 std::vector<Distribution> trancheDistResults;
659 for(Size i = 0 ;i < tranches.size(); i ++){
660 Distribution trancheDist = trancheStats[i].histogram(bins_);
661 trancheDistResults.push_back(trancheDist);
662 }
663 results_.additionalResults["TrancheValueDistribution"] = trancheDistResults;
664
665 if (!lossDistributionDates.empty())
666 results_.additionalResults["LossDistribution"] = lossDistributionMap;
667
668 //define which tranche is in the npv-file and scale by investment amount
669 for (Size i = 0; i < tranches.size(); i++) {
670 if(tranches[i].name == arguments_.investedTrancheName){
671 results_.value = trancheStats[i].mean();
672 results_.errorEstimate = trancheStats[i].std();
673 }
674 }
675 QL_REQUIRE(results_.value != Null<Real>(), "CBO Investment " << arguments_.investedTrancheName << " could not be assigned : no NPV");
676
677 /*
678 //results of all components in logFile
679 LOG ("-----------------------------------");
680 LOG ("CBO valuation results:");
681 double liab = 0.0;
682 for(Size i = 0 ; i < tranches.size(); i++){
683 LOG( tranches[i].name << " - value " << fixed << setprecision(2) << trancheStats[i].mean() << " - stdev: " << trancheStats[i].std() << " - face amount " << tranches[i].faceAmount );
684 liab += trancheStats[i].mean();
685 }
686 LOG ( "senior fee - value " << fixed << setprecision(2) << feeStats.mean() << " - stdev " << feeStats.std());
687 LOG ( "sub fee - value " << fixed << setprecision(2) << subfeeStats.mean() << " - stdev " << subfeeStats.std());
688 LOG ( "portfolio - value " << fixed << setprecision(2) << basketStats.mean() << " - stdev " << basketStats.std());
689 liab += feeStats.mean() + subfeeStats.mean();
690 LOG ( "total: assets " << fixed << setprecision(2) << basketStats.mean() << " vs. liabilities " << liab );
691 LOG ( "check total :" << fixed << setprecision(10) << basketStats.mean() - liab);
692 LOG ("-----------------------------------");
693 */
694
695 }// calculate
const Instrument::results * results_
Definition: cdsoption.cpp:81
virtual void initialize() const
Definition: cboengine.hpp:39
std::map< QuantLib::Date, std::string > getLossDistributionDates(const QuantLib::Date &valuationDate) const
Return dates on the CBO schedule that are closest to the requested lossDistributionPeriods.
void interestWaterfall(Size sampleIndex, Size dateIndex, const vector< Date > &dates, map< Currency, vector< Cash > > &basketFlow, map< Currency, Cash > &trancheFlow, map< Currency, vector< vector< Real > > > &balance, map< Currency, Real > &interest, map< Currency, Real > &interestAcc, Real cureAmount) const
interest waterfall
Definition: cbomcengine.cpp:30
void principalWaterfall(Size sampleIndex, Size dateIndex, const vector< Date > &dates, map< Currency, vector< Cash > > &basketFlow, map< Currency, Cash > &trancheFlow, map< Currency, vector< vector< Real > > > &balance, map< Currency, Real > &interest) const
pricipal waterfall
Real icocCureAmount(Size sampleIndex, Size dateIndex, Size trancheNo, Real basketNotional, Real basketInterest, vector< map< Currency, vector< vector< Real > > > > &trancheBalances, vector< Real > trancheInterestRates, Real icRatios, Real ocRatios) const
icoc cure amount
void icocInterestWaterfall(Size i, Size j, Size k, const vector< Date > &dates, map< Currency, vector< Cash > > &iFlows, vector< map< Currency, Cash > > &tranches, vector< map< Currency, vector< vector< Real > > > > &balances, Real cureAmount) const
icoc interest waterfall
Definition: cbomcengine.cpp:72
Swap::arguments * arguments_
+ Here is the call graph for this function:

◆ interestWaterfall()

void interestWaterfall ( Size  sampleIndex,
Size  dateIndex,
const vector< Date > &  dates,
map< Currency, vector< Cash > > &  basketFlow,
map< Currency, Cash > &  trancheFlow,
map< Currency, vector< vector< Real > > > &  balance,
map< Currency, Real > &  interest,
map< Currency, Real > &  interestAcc,
Real  cureAmount 
) const
private

interest waterfall

Definition at line 30 of file cbomcengine.cpp.

38 {
39 Currency ccy = arguments_.ccy;
40
41 Real tiny = 1e-9;
42 if (balance[ccy][j][i] < tiny) {
43 tranche[ccy].flow_ = 0.0;
44 tranche[ccy].discountedFlow_ = 0.0;
45 return;
46 }
47
48 Real ccyDis = (iFlows[ccy][j].flow_ > 0 ?
49 iFlows[ccy][j].discountedFlow_ / iFlows[ccy][j].flow_:
50 0.0);
51
52 // Accrued Interest
53
54 Real amount = std::min(iFlows[ccy][j].flow_, interestAcc[ccy]);
55
56 tranche[ccy].flow_ += amount;
57 tranche[ccy].discountedFlow_ += amount * ccyDis;
58
59 iFlows[ccy][j].flow_ -= amount;
60 iFlows[ccy][j].discountedFlow_ -= amount * ccyDis;
61
62 interest[ccy] -= amount;
63
64 // Truncate rounding errors
65 balance[ccy][j][i] = std::max(balance[ccy][j][i], 0.0);
66 iFlows[ccy][j].flow_ = std::max(iFlows[ccy][j].flow_, 0.0);
67 iFlows[ccy][j].discountedFlow_ = std::max(iFlows[ccy][j].discountedFlow_, 0.0);
68 tranche[ccy].discountedFlow_ = std::max(tranche[ccy].discountedFlow_, 0.0);
69 }
+ Here is the caller graph for this function:

◆ icocInterestWaterfall()

void icocInterestWaterfall ( Size  i,
Size  j,
Size  k,
const vector< Date > &  dates,
map< Currency, vector< Cash > > &  iFlows,
vector< map< Currency, Cash > > &  tranches,
vector< map< Currency, vector< vector< Real > > > > &  balances,
Real  cureAmount 
) const
private

icoc interest waterfall

Definition at line 72 of file cbomcengine.cpp.

79 {
80 Currency ccy = arguments_.ccy;
81
82 Real ccyDis = (iFlows[ccy][j].flow_ > 0 ?
83 iFlows[ccy][j].discountedFlow_ / iFlows[ccy][j].flow_:
84 0.0);
85
86 //IC and OC
87
88 Real cureAvailable = min(iFlows[ccy][j].flow_, cureAmount);
89
90 for(Size k = 0; k <= l; k++){
91
92 Real amount = std::min(balances[k][ccy][j][i], cureAvailable);
93
94 tranches[k][ccy].flow_ += amount;
95 tranches[k][ccy].discountedFlow_ += amount * ccyDis;
96
97 iFlows[ccy][j].flow_ -= amount;
98 iFlows[ccy][j].discountedFlow_ -= amount * ccyDis;
99
100 balances[k][ccy][j][i] -= amount;
101
102 cureAvailable -= amount;
103
104 // truncate rounding errors
105 balances[k][ccy][j][i] = std::max(balances[k][ccy][j][i], 0.0);
106 iFlows[ccy][j].flow_ = std::max(iFlows[ccy][j].flow_, 0.0);
107 iFlows[ccy][j].discountedFlow_ = std::max(iFlows[ccy][j].discountedFlow_, 0.0);
108 tranches[k][ccy].discountedFlow_ = std::max(tranches[k][ccy].discountedFlow_, 0.0);
109 }
110 }
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ principalWaterfall()

void principalWaterfall ( Size  sampleIndex,
Size  dateIndex,
const vector< Date > &  dates,
map< Currency, vector< Cash > > &  basketFlow,
map< Currency, Cash > &  trancheFlow,
map< Currency, vector< vector< Real > > > &  balance,
map< Currency, Real > &  interest 
) const
private

pricipal waterfall

Definition at line 113 of file cbomcengine.cpp.

119 {
120 Currency ccy = arguments_.ccy;
121
122 Real ccyDis = (pFlows[ccy][j].flow_ > 0 ?
123 pFlows[ccy][j].discountedFlow_ / pFlows[ccy][j].flow_:
124 0.0);
125
126 //Principal Waterfall
127
128 Real amount = std::min(pFlows[ccy][j].flow_, balance[ccy][j][i]);
129
130 tranche[ccy].flow_ += amount;
131 tranche[ccy].discountedFlow_ += amount * ccyDis;
132
133 pFlows[ccy][j].flow_ -= amount;
134 pFlows[ccy][j].discountedFlow_ -= amount * ccyDis;
135
136 balance[ccy][j][i] -= amount;
137
138 // truncate rounding errors
139 balance[ccy][j][i] = std::max(balance[ccy][j][i], 0.0);
140 pFlows[ccy][j].flow_ = std::max(pFlows[ccy][j].flow_, 0.0);
141 pFlows[ccy][j].discountedFlow_ = std::max(pFlows[ccy][j].discountedFlow_, 0.0);
142 tranche[ccy].discountedFlow_ = std::max(tranche[ccy].discountedFlow_, 0.0);
143
144 interest[ccy] -= std::min(interest[ccy], amount);
145 }
+ Here is the caller graph for this function:

◆ icocCureAmount()

Real icocCureAmount ( Size  sampleIndex,
Size  dateIndex,
Size  trancheNo,
Real  basketNotional,
Real  basketInterest,
vector< map< Currency, vector< vector< Real > > > > &  trancheBalances,
vector< Real >  trancheInterestRates,
Real  icRatios,
Real  ocRatios 
) const
private

icoc cure amount

Definition at line 148 of file cbomcengine.cpp.

156 {
157 Currency ccy = arguments_.ccy;
158
159 Real cureAmount;
160
161 if((icRatio < 0.) && (ocRatio < 0.)){
162 cureAmount = 0.;
163 }
164 else{
165 Real poC = 0.;
166 Real piC = 0.;
167
168 for(Size l = 0; l < k; l++){
169 poC-= trancheBalances[l][ccy][j][i];
170 piC-= trancheBalances[l][ccy][j][i]*trancheInterestRates[l];
171 }
172
173 poC+= basketNotional/ocRatio;
174 if(trancheInterestRates[k] <= 0.){
175 piC=poC;
176 }
177 else {
178 piC+= basketInterest/icRatio;
179 piC/= trancheInterestRates[k];
180 }
181 piC = std::max(piC, 0.);
182 poC = std::max(poC, 0.);
183 Real pTarget = std::min(poC, piC);
184
185 cureAmount = max(trancheBalances[k][ccy][j][i] - pTarget, 0.) ;
186 }
187 return cureAmount;
188 }
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getLossDistributionDates()

map< Date, string > getLossDistributionDates ( const QuantLib::Date &  valuationDate) const
private

Return dates on the CBO schedule that are closest to the requested lossDistributionPeriods.

Definition at line 192 of file cbomcengine.cpp.

192 {
193 if (lossDistributionPeriods_.size() == 0)
194 return map<Date, string>();
195
196 // For each period, return first date in CBO schedule greater than or equal to it
197 map<Date, string> lossDistributionDates;
198 const vector<Date>& cboDates = arguments_.schedule.dates();
199 Date date;
200 vector<Date>::const_iterator it;
201 ostringstream oss;
202 for (Size i = 0; i < lossDistributionPeriods_.size(); i++) {
203 date = valuationDate + lossDistributionPeriods_[i];
204 oss << io::short_period(lossDistributionPeriods_[i]);
205 it = lower_bound(cboDates.begin(), cboDates.end(), date);
206 if (it == cboDates.begin()) {
207 continue;
208 } else if (it == cboDates.end()) {
209 lossDistributionDates[cboDates.back()] = oss.str();
210 break;
211 } else {
212 lossDistributionDates[*it] = oss.str();
213 }
214 oss.str("");
215 }
216
217 // Add the maturity date of the note also with a special string
218 // This overwrites any entry for the last date above
219 lossDistributionDates[cboDates.back()] = "Maturity";
220
221 return lossDistributionDates;
222 }
+ Here is the caller graph for this function:

Member Data Documentation

◆ rdm_

QuantLib::ext::shared_ptr<RandomDefaultModel> rdm_
private

Definition at line 94 of file cbomcengine.hpp.

◆ samples_

Size samples_
private

Definition at line 95 of file cbomcengine.hpp.

◆ bins_

Size bins_
private

Definition at line 96 of file cbomcengine.hpp.

◆ errorTolerance_

double errorTolerance_
private

Definition at line 97 of file cbomcengine.hpp.

◆ lossDistributionPeriods_

std::vector<QuantLib::Period> lossDistributionPeriods_
private

Periods from valuation date for which to return loss distributions.

Definition at line 100 of file cbomcengine.hpp.