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

#include <qle/pricingengines/indexcdstrancheengine.hpp>

+ Inheritance diagram for IndexCdsTrancheEngine:
+ Collaboration diagram for IndexCdsTrancheEngine:

Public Member Functions

 IndexCdsTrancheEngine (const QuantLib::Handle< QuantLib::YieldTermStructure > &discountCurve, boost::optional< bool > includeSettlementDateFlows=boost::none)
 
void calculate () const override
 

Protected Attributes

QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_
 
boost::optional< boolincludeSettlementDateFlows_
 

Detailed Description

Index tranche pricing engine

The engine obtains the index CDS reference basket from its arguments and it is expecting it to have a default model assigned.

This engine prices standard index CDS tranches. The mechanics of such tranches is outlined in Markit Credit Indices A Primer, 2014 for example available on the Markit website.

Warning:
We do not cover the possibility that recovery amounts decrease the tranche notional on which the premium is paid. For tranche detachment points met in practice, it is rare that recovery amounts exceed the notional of the super-senior tranche and thus erode the notional of the other tranches. If we want to cover this possibility we would need to extend the basket loss model algorithms so that they account for losses on a tranche notional due to recovery amounts in addition to the losses due to default. In summary, do not expect this pricing engine to work well for tranches with high detachment points which are likely to be breached by the sum of recovered amounts as the premium leg will be over-estimated in those situations.

Definition at line 52 of file indexcdstrancheengine.hpp.

Constructor & Destructor Documentation

◆ IndexCdsTrancheEngine()

IndexCdsTrancheEngine ( const QuantLib::Handle< QuantLib::YieldTermStructure > &  discountCurve,
boost::optional< bool includeSettlementDateFlows = boost::none 
)

Definition at line 33 of file indexcdstrancheengine.cpp.

35 : discountCurve_(discountCurve),
36 includeSettlementDateFlows_(includeSettlementDateFlows) {
37 registerWith(discountCurve);
38}
boost::optional< bool > includeSettlementDateFlows_
QuantLib::Handle< QuantLib::YieldTermStructure > discountCurve_

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 40 of file indexcdstrancheengine.cpp.

40 {
41
42 cpu_timer timer;
43 timer.start();
44
45 // Upfront premium
46 results_.upfrontPremiumValue = 0.0;
47 Real upfrontPremiumAmount = arguments_.upfrontPayment->amount();
48 if (arguments_.upfrontPayment && !arguments_.upfrontPayment->hasOccurred(
50 results_.upfrontPremiumValue = upfrontPremiumAmount *
51 discountCurve_->discount(arguments_.upfrontPayment->date());
52 }
53
54 // Accrual rebate
55 results_.accrualRebateValue = 0.0;
56 if (arguments_.accrualRebate && !arguments_.accrualRebate->hasOccurred(
58 results_.accrualRebateValue = arguments_.accrualRebate->amount() *
59 discountCurve_->discount(arguments_.accrualRebate->date());
60 }
61
62 // Accrual rebate current
63 results_.accrualRebateCurrentValue = 0.0;
64 if (arguments_.accrualRebateCurrent &&
65 !arguments_.accrualRebateCurrent->hasOccurred(discountCurve_->referenceDate(), includeSettlementDateFlows_)) {
66 results_.accrualRebateCurrentValue =
67 discountCurve_->discount(arguments_.accrualRebateCurrent->date()) * arguments_.accrualRebateCurrent->amount();
68 }
69
70 // Final results, not updated below.
71 // FD TODO: check again when testing tranches with existing losses.
72 const auto& basket = arguments_.basket;
73 QL_REQUIRE(basket, "IndexCdsTrancheEngine expects a non-null basket.");
74 results_.xMin = basket->attachmentAmount();
75 results_.xMax = basket->detachmentAmount();
76 results_.remainingNotional = results_.xMax - results_.xMin;
77
78 // Record the expected tranche loss up to inception and up to the end of each coupon period.
79 // FD TODO: Recheck 0's for past coupons when testing tranches with existing losses. The loss model gives
80 // accumulated losses so we should in theory be able to use these.
81 vector<Real>& etls = results_.expectedTrancheLoss;
82 etls.push_back(0.0);
83
84 // Variables used in the loop below.
85 Date today = Settings::instance().evaluationDate();
86 results_.premiumValue = 0.0;
87 results_.protectionValue = 0.0;
88 Real inceptionTrancheNotional = arguments_.basket->trancheNotional();
89
90 // Value the premium and protection leg.
91 for (Size i = 0; i < arguments_.normalizedLeg.size(); i++) {
92
93 // Zero expected loss on coupon end dates that have already occured.
94 // FD TODO: check again when testing tranches with existing losses.
95 if (arguments_.normalizedLeg[i]->hasOccurred(today)) {
96 etls.push_back(0.0);
97 continue;
98 }
99
100 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(arguments_.normalizedLeg[i]);
101 QL_REQUIRE(coupon, "IndexCdsTrancheEngine expects leg to have Coupon cashflow type.");
102
103 // Relevant dates with assumption that future defaults occur at midpoint of (remaining) coupon period.
104 Date paymentDate = coupon->date();
105 Date startDate = std::max(coupon->accrualStartDate(), today);
106 Date endDate = coupon->accrualEndDate();
107 Date defaultDate = startDate + (endDate - startDate) / 2;
108
109 // Expected loss on the tranche up to the end of the current period.
110 Real etl = basket->expectedTrancheLoss(endDate, arguments_.recoveryRate);
111
112 // Update protection leg value
113 results_.protectionValue += discountCurve_->discount(defaultDate) * (etl - etls.back());
114
115 // Update the premium leg value. If settling accruals, which is standard, assume that losses are evenly
116 // distributed over the coupon period, as per Andersen, Sidenius, Basu Nov 2003 paper for example. If not
117 // settling accruals, just use the tranche notional at period end.
118 Real effNtl = 0.0;
119 if (arguments_.settlesAccrual) {
120 effNtl = inceptionTrancheNotional - (etl + etls.back()) / 2.0;
121 } else {
122 effNtl = inceptionTrancheNotional - etl;
123 }
124 results_.premiumValue += (coupon->amount() / inceptionTrancheNotional) *
125 effNtl * discountCurve_->discount(paymentDate);
126
127 // Update the expected tranche loss results vector.
128 etls.push_back(etl);
129 }
130
131 // Apply correct sign to each PV'ed quantity depending on whether buying or selling protection on the tranche.
132 if (arguments_.side == Protection::Buyer) {
133 results_.premiumValue *= -1;
134 results_.upfrontPremiumValue *= -1;
135 upfrontPremiumAmount *= -1;
136 } else {
137 results_.protectionValue *= -1;
138 results_.accrualRebateValue *= -1;
139 results_.accrualRebateCurrentValue *= -1;
140 }
141
142 // Final tranche NPV.
143 results_.value = results_.premiumValue + results_.protectionValue +
144 results_.upfrontPremiumValue + results_.accrualRebateValue;
145
146 // Fair tranche spread.
147 Real fairSpread = 0.0;
148 if (results_.premiumValue != 0.0) {
149 fairSpread = -(results_.protectionValue + results_.upfrontPremiumValue) *
150 arguments_.runningRate / (results_.premiumValue + results_.accrualRebateValue);
151 }
152
153 timer.stop();
154
155 // Populate the additional results.
156 results_.additionalResults["attachment"] = arguments_.basket->attachmentRatio();
157 results_.additionalResults["detachment"] = arguments_.basket->detachmentRatio();
158 results_.additionalResults["fixedRate"] = arguments_.runningRate;
159 results_.additionalResults["fairSpread"] = fairSpread;
160 results_.additionalResults["upfrontPremium"] = upfrontPremiumAmount;
161 Real correlation = arguments_.basket->correlation();
162 if (correlation != Null<Real>())
163 results_.additionalResults["correlation"] = correlation;
164 results_.additionalResults["upfrontPremiumNPV"] = results_.upfrontPremiumValue;
165 results_.additionalResults["premiumLegNPV"] = results_.premiumValue;
166 results_.additionalResults["accrualRebateNPV"] = results_.accrualRebateValue;
167 results_.additionalResults["accrualRebateCurrentNPV"] = results_.accrualRebateCurrentValue;
168
169 results_.additionalResults["protectionLegNPV"] = results_.protectionValue;
170 results_.additionalResults["calculationTime"] = timer.elapsed().wall * 1e-9;
171}
const Instrument::results * results_
Definition: cdsoption.cpp:81
Swap::arguments * arguments_

Member Data Documentation

◆ discountCurve_

QuantLib::Handle<QuantLib::YieldTermStructure> discountCurve_
protected

Definition at line 60 of file indexcdstrancheengine.hpp.

◆ includeSettlementDateFlows_

boost::optional<bool> includeSettlementDateFlows_
protected

Definition at line 61 of file indexcdstrancheengine.hpp.