1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Roland Lichters
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/experimental/credit/integralntdengine.hpp>
21#include <ql/cashflows/fixedratecoupon.hpp>
22#include <ql/termstructures/yieldtermstructure.hpp>
23#include <ql/experimental/credit/basket.hpp>
24#include <numeric>
25
26namespace QuantLib {
27
28 void IntegralNtdEngine::calculate() const {
29 Date today = Settings::instance().evaluationDate();
30
31 results_.errorEstimate = Null<Real>();
32 results_.value = 0.0;
33 results_.premiumValue = 0.0;
34 results_.upfrontPremiumValue = 0.;
35 Real accrualValue = 0.0;
36 Real claimValue = 0.0;
37 Date d0;
38 /* Given the expense of probsBeingNthEvent both in integrable and
39 monte carlo algorithms this engine tests who to call.
40 Warning: This is not entirely a basket property but of the model too.
41 The basket has to have all notionals equal but it is the model which
42 determines the recovery; having all the market recoveries equal is not
43 enough since we might be using a loss model which is stochastic in the
44 recovery rates.
45 */
46 bool basketIsHomogeneous = true;// hardcoded by now
47
48 for (auto& i : arguments_.premiumLeg) {
49 ext::shared_ptr<FixedRateCoupon> coupon = ext::dynamic_pointer_cast<FixedRateCoupon>(r: i);
50 Date d = i->date();
51 if (d > discountCurve_->referenceDate()) {
52 /*
53 std::vector<Probability> probsTriggering =
54 arguments_.basket->probsBeingNthEvent(arguments_.ntdOrder,
55 d);
56 Probability defaultProb =
57 std::accumulate(probsTriggering.begin(),
58 probsTriggering.end(), Real(0.));
59 // OVERKILL???? 1-probAtLeastNEvents is enough
60
61*/
62 // prob of contract not having been triggered by date of payment
63 Probability probNonTriggered =
64 1. - arguments_.basket->probAtLeastNEvents(
65 n: arguments_.ntdOrder, d);
66
67 results_.premiumValue +=
68 i->amount() * discountCurve_->discount(d) * probNonTriggered;
69 //// * (1.0 - defaultProb);
70
71 if (coupon->accrualStartDate() >=
72 discountCurve_->referenceDate())
73 d = coupon->accrualStartDate();
74 else
75 d = discountCurve_->referenceDate();
76
77 // do steps of specified size
78 d0 = d;
79 Period stepSize = integrationStepSize_;
80/*
81 probsTriggering =
82 arguments_.basket->probsBeingNthEvent(arguments_.ntdOrder,
83 ///////REDUNDANT?
84 d0);
85 Probability defProb0 = std::accumulate(probsTriggering.begin(),
86 ///OVERKILL????
87 probsTriggering.end(), Real(0.));
88*/
89 Probability defProb0 = arguments_.basket->probAtLeastNEvents(
90 n: arguments_.ntdOrder, d: d0);
91 std::vector<Probability> probsTriggering, probsTriggering1;
92 do {
93 DiscountFactor disc = discountCurve_->discount(d);
94
95 Probability defProb1;
96 if(basketIsHomogeneous) {//take test out of the while loop
97 defProb1 = arguments_.basket->probAtLeastNEvents(
98 n: arguments_.ntdOrder, d);
99 claimValue -= (defProb1-defProb0)
100 * arguments_.basket->claim()->amount(defaultDate: d,
101 notional: arguments_.notional,
102 recoveryRate: arguments_.basket->recoveryRate(d, iName: 0))
103 * disc;
104
105 }else{
106 probsTriggering1 =
107 arguments_.basket->probsBeingNthEvent(
108 n: arguments_.ntdOrder, d);
109 defProb1 = std::accumulate(first: probsTriggering1.begin(),
110 last: probsTriggering1.end(), init: Real(0.));
111 /*Recoveries might differ along names, depending on
112 which name is triggering the contract the loss will be
113 different
114 There is an issue here; MC engines can still be used
115 since the prob of triggering the contract can be
116 extracted from the simulation from the
117 probsBeingNthEvent statistic. Yet, when the RR is
118 stochastic the realized value of the RR is the expected
119 one subject/conditional to the contract being triggered;
120 not simply the expected value. For this reason the MC
121 can not be used through the statistic but has to consume
122 the simulations directly.
123 */
124 for(Size iName=0;
125 iName<arguments_.basket->remainingSize();
126 iName++)
127 {
128 claimValue -= (probsTriggering1[iName]-
129 probsTriggering[iName])
130 * arguments_.basket->claim()->amount(defaultDate: d,
131 notional: arguments_.notional,// [iName]!
132 recoveryRate: arguments_.basket->recoveryRate(d, iName))
133 * disc;
134 }
135 probsTriggering = probsTriggering1;
136 }
137
138 Probability dcfdd = defProb1 - defProb0;
139 defProb0 = defProb1;
140
141 if (arguments_.settlePremiumAccrual)
142 accrualValue += coupon->accruedAmount(d)*disc*dcfdd;
143
144 d0 = d;
145 d = d0 + stepSize;
146 // reduce step size ?
147 if (stepSize != 1*Days && d > coupon->accrualEndDate()) {
148 stepSize = 1*Days;
149 d = d0 + stepSize;
150 }
151 }
152 while (d <= coupon->accrualEndDate());
153 }
154 }
155
156 // The upfront might be due before the curve ref date...
157 if (!arguments_.premiumLeg[0]->hasOccurred(refDate: today))
158 results_.upfrontPremiumValue =
159 arguments_.basket->remainingNotional()
160 * arguments_.upfrontRate
161 * discountCurve_->discount(
162 d: ext::dynamic_pointer_cast<FixedRateCoupon>(
163 r: arguments_.premiumLeg[0])->accrualStartDate());
164 if (arguments_.side == Protection::Buyer) {
165 results_.premiumValue *= -1;
166 accrualValue *= -1;
167 claimValue *= -1;
168 results_.upfrontPremiumValue *= -1;
169 }
170
171 results_.value = results_.premiumValue + accrualValue + claimValue +
172 results_.upfrontPremiumValue;
173
174 results_.fairPremium = -arguments_.premiumRate * claimValue
175 / (results_.premiumValue + accrualValue);
176 // alternatively use results buffers and omit locals.
177 results_.protectionValue = claimValue;
178
179 results_.additionalResults["fairPremium"] = results_.fairPremium;
180 results_.additionalResults["premiumLegNPV"] =
181 Real(results_.premiumValue + results_.upfrontPremiumValue);
182 results_.additionalResults["protectionLegNPV"] =
183 results_.protectionValue;
184 }
185
186}
187

source code of quantlib/ql/experimental/credit/integralntdengine.cpp