Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
midpointcdoengine.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#ifndef QL_PATCH_SOLARIS
22
23#include <ql/cashflows/fixedratecoupon.hpp>
24#include <ql/termstructures/yieldtermstructure.hpp>
25#include <boost/timer/timer.hpp>
26
27using boost::timer::cpu_timer;
28
29namespace QuantExt {
30
32
33 cpu_timer timer;
34 timer.start();
35
36 Date today = Settings::instance().evaluationDate();
37
38 results_.premiumValue = 0.0;
39 results_.protectionValue = 0.0;
40 results_.upfrontPremiumValue = 0.0;
41 results_.error = 0;
42 results_.expectedTrancheLoss.clear();
43 // todo Should be remaining when considering realized loses
44 results_.xMin = arguments_.basket->attachmentAmount();
45 results_.xMax = arguments_.basket->detachmentAmount();
46 results_.remainingNotional = results_.xMax - results_.xMin;
47 const Real inceptionTrancheNotional = arguments_.basket->trancheNotional();
48
49 // Upfront Flow NPV and accrual rebate NPV. Either we are on-the-run (no flow)
50 // or we are forward start
51
52 // date determining the probability survival so we have to pay
53 // the upfront flows (did not knock out)
54 Date refDate = discountCurve_->referenceDate();
55 // Date effectiveProtectionStart = arguments_.protectionStart > refDate ? arguments_.protectionStart : refDate ;
56 Probability nonKnockOut = 1.0; // FIXME
57
58 Real upfPVO1 = 0.0;
59 results_.upfrontPremiumValue = 0.0;
60 if (arguments_.upfrontPayment && !arguments_.upfrontPayment->hasOccurred(refDate, includeSettlementDateFlows_)) {
61 upfPVO1 = nonKnockOut * discountCurve_->discount(arguments_.upfrontPayment->date());
62 results_.upfrontPremiumValue = upfPVO1 * arguments_.upfrontPayment->amount();
63 }
64
65 results_.accrualRebateValue = 0.;
66 if (arguments_.accrualRebate && !arguments_.accrualRebate->hasOccurred(refDate, includeSettlementDateFlows_)) {
67 results_.accrualRebateValue = nonKnockOut * discountCurve_->discount(arguments_.accrualRebate->date()) *
68 arguments_.accrualRebate->amount();
69 }
70
71 // compute expected loss at the beginning of first relevant period
72 Real zeroRecovery_e1 = 0, recovery_e1 = 0;
73 // todo add includeSettlement date flows variable to engine.
74 // RL: comment the following out, thows a negative time error
75 // if (!arguments_.normalizedLeg[0]->hasOccurred(today))
76 // // Notice that since there might be a gap between the end of
77 // // acrrual and payment dates and today be in between
78 // // the tranche loss on that date might not be contingent but
79 // // realized:
80 // e1 = arguments_.basket->expectedTrancheLoss(
81 // QuantLib::ext::dynamic_pointer_cast<Coupon>(
82 // arguments_.normalizedLeg[0])->accrualStartDate());
83 results_.expectedTrancheLoss.push_back(recovery_e1);
84 //'e1' should contain the existing loses.....? use remaining amounts?
85 for (Size i = 0; i < arguments_.normalizedLeg.size(); i++) {
86 if (arguments_.normalizedLeg[i]->hasOccurred(today)) {
87 results_.expectedTrancheLoss.push_back(0.);
88 continue;
89 }
90 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(arguments_.normalizedLeg[i]);
91 Date paymentDate = coupon->date();
92 Date startDate = std::max(coupon->accrualStartDate(), discountCurve_->referenceDate());
93 Date endDate = coupon->accrualEndDate();
94 // we assume the loss within the period took place on this date:
95 Date defaultDate = startDate + (endDate - startDate) / 2;
96
97 Real zeroRecovery_e2 =
98 arguments_.basket->expectedTrancheLoss(endDate, true); // zero recoveries for the coupon leg
99
100 Real recovery_e2 =
101 arguments_.basket->expectedTrancheLoss(endDate, false); // non-zero recovery for the default leg
102
103 results_.expectedTrancheLoss.push_back(recovery_e2);
104 results_.premiumValue += ((inceptionTrancheNotional - zeroRecovery_e2) / inceptionTrancheNotional) *
105 coupon->amount() * discountCurve_->discount(paymentDate);
106
107 // default flows:
108 Date protectionPaymentDate;
109 if (arguments_.protectionPaymentTime == CreditDefaultSwap::ProtectionPaymentTime::atDefault) {
110 protectionPaymentDate = defaultDate;
111 } else if (arguments_.protectionPaymentTime == CreditDefaultSwap::ProtectionPaymentTime::atPeriodEnd) {
112 protectionPaymentDate = paymentDate;
113 } else if (arguments_.protectionPaymentTime == CreditDefaultSwap::ProtectionPaymentTime::atMaturity) {
114 protectionPaymentDate = arguments_.maturity;
115 } else {
116 QL_FAIL("protectionPaymentTime not handled");
117 }
118 const Real discount = discountCurve_->discount(protectionPaymentDate);
119
120 // Accrual removed till the argument flag is implemented
121 // pays accrued on defaults' date
122 if (arguments_.settlesAccrual)
123 results_.premiumValue += coupon->accruedAmount(defaultDate) * discount *
124 (zeroRecovery_e2 - zeroRecovery_e1) / inceptionTrancheNotional;
125
126 results_.protectionValue += discount * (recovery_e2 - recovery_e1);
127 /* use it in a future version for coherence with the integral engine
128 * arguments_.leverageFactor;
129 */
130 recovery_e1 = recovery_e2;
131 zeroRecovery_e1 = zeroRecovery_e2;
132 }
133
134 /* use it in a future version for coherence with the integral engine
135 arguments_.leverageFactor * ;
136 */
137 if (arguments_.side == Protection::Buyer) {
138 results_.premiumValue *= -1;
139 results_.upfrontPremiumValue *= -1;
140 } else {
141 results_.protectionValue *= -1;
142 results_.accrualRebateValue *= -1;
143 }
144 results_.value =
145 results_.premiumValue + results_.protectionValue + results_.upfrontPremiumValue + results_.accrualRebateValue;
146 results_.errorEstimate = Null<Real>();
147 // Fair spread GIVEN the upfront
148 Real fairSpread = 0.;
149 if (results_.premiumValue != 0.0) {
150 fairSpread = -(results_.protectionValue + results_.upfrontPremiumValue + results_.accrualRebateValue) *
151 arguments_.runningRate / results_.premiumValue;
152 }
153
154 timer.stop();
155
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"] = arguments_.upfrontPayment->amount();
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["protectionLegNPV"] = results_.protectionValue;
168 results_.additionalResults["calculationTime"] = timer.elapsed().wall * 1e-9;
169}
170
171} // namespace QuantExt
172
173#endif
const Instrument::results * results_
Definition: cdsoption.cpp:81
Handle< YieldTermStructure > discountCurve_
boost::optional< bool > includeSettlementDateFlows_
void calculate() const override
Swap::arguments * arguments_