/src/quantlib/ql/instruments/creditdefaultswap.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2008, 2009 Jose Aparicio |
5 | | Copyright (C) 2008 Roland Lichters |
6 | | Copyright (C) 2008 StatPro Italia srl |
7 | | |
8 | | This file is part of QuantLib, a free-software/open-source library |
9 | | for financial quantitative analysts and developers - http://quantlib.org/ |
10 | | |
11 | | QuantLib is free software: you can redistribute it and/or modify it |
12 | | under the terms of the QuantLib license. You should have received a |
13 | | copy of the license along with this program; if not, please email |
14 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
15 | | <https://www.quantlib.org/license.shtml>. |
16 | | |
17 | | This program is distributed in the hope that it will be useful, but WITHOUT |
18 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
19 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
20 | | */ |
21 | | |
22 | | #include <ql/cashflows/fixedratecoupon.hpp> |
23 | | #include <ql/cashflows/simplecashflow.hpp> |
24 | | #include <ql/instruments/claim.hpp> |
25 | | #include <ql/instruments/creditdefaultswap.hpp> |
26 | | #include <ql/math/solvers1d/brent.hpp> |
27 | | #include <ql/pricingengines/credit/isdacdsengine.hpp> |
28 | | #include <ql/pricingengines/credit/midpointcdsengine.hpp> |
29 | | #include <ql/quotes/simplequote.hpp> |
30 | | #include <ql/termstructures/credit/flathazardrate.hpp> |
31 | | #include <ql/termstructures/yieldtermstructure.hpp> |
32 | | #include <ql/time/calendars/weekendsonly.hpp> |
33 | | #include <ql/time/schedule.hpp> |
34 | | #include <ql/optional.hpp> |
35 | | #include <utility> |
36 | | |
37 | | namespace QuantLib { |
38 | | |
39 | | CreditDefaultSwap::CreditDefaultSwap(Protection::Side side, |
40 | | Real notional, |
41 | | Rate spread, |
42 | | const Schedule& schedule, |
43 | | BusinessDayConvention convention, |
44 | | const DayCounter& dayCounter, |
45 | | bool settlesAccrual, |
46 | | bool paysAtDefaultTime, |
47 | | const Date& protectionStart, |
48 | | ext::shared_ptr<Claim> claim, |
49 | | const DayCounter& lastPeriodDayCounter, |
50 | | const bool rebatesAccrual, |
51 | | const Date& tradeDate, |
52 | | Natural cashSettlementDays) |
53 | 0 | : side_(side), notional_(notional), upfront_(ext::nullopt), runningSpread_(spread), |
54 | 0 | settlesAccrual_(settlesAccrual), paysAtDefaultTime_(paysAtDefaultTime), |
55 | 0 | claim_(std::move(claim)), |
56 | 0 | protectionStart_(protectionStart == Date() ? schedule[0] : protectionStart), |
57 | 0 | tradeDate_(tradeDate), cashSettlementDays_(cashSettlementDays) { |
58 | |
|
59 | 0 | init(schedule, convention, dayCounter, lastPeriodDayCounter, rebatesAccrual); |
60 | 0 | } Unexecuted instantiation: QuantLib::CreditDefaultSwap::CreditDefaultSwap(QuantLib::Protection::Side, double, double, QuantLib::Schedule const&, QuantLib::BusinessDayConvention, QuantLib::DayCounter const&, bool, bool, QuantLib::Date const&, boost::shared_ptr<QuantLib::Claim>, QuantLib::DayCounter const&, bool, QuantLib::Date const&, unsigned int) Unexecuted instantiation: QuantLib::CreditDefaultSwap::CreditDefaultSwap(QuantLib::Protection::Side, double, double, QuantLib::Schedule const&, QuantLib::BusinessDayConvention, QuantLib::DayCounter const&, bool, bool, QuantLib::Date const&, boost::shared_ptr<QuantLib::Claim>, QuantLib::DayCounter const&, bool, QuantLib::Date const&, unsigned int) |
61 | | |
62 | | CreditDefaultSwap::CreditDefaultSwap(Protection::Side side, |
63 | | Real notional, |
64 | | Rate upfront, |
65 | | Rate runningSpread, |
66 | | const Schedule& schedule, |
67 | | BusinessDayConvention convention, |
68 | | const DayCounter& dayCounter, |
69 | | bool settlesAccrual, |
70 | | bool paysAtDefaultTime, |
71 | | const Date& protectionStart, |
72 | | const Date& upfrontDate, |
73 | | ext::shared_ptr<Claim> claim, |
74 | | const DayCounter& lastPeriodDayCounter, |
75 | | const bool rebatesAccrual, |
76 | | const Date& tradeDate, |
77 | | Natural cashSettlementDays) |
78 | 0 | : side_(side), notional_(notional), upfront_(upfront), runningSpread_(runningSpread), |
79 | 0 | settlesAccrual_(settlesAccrual), paysAtDefaultTime_(paysAtDefaultTime), |
80 | 0 | claim_(std::move(claim)), |
81 | 0 | protectionStart_(protectionStart == Date() ? schedule[0] : protectionStart), |
82 | 0 | tradeDate_(tradeDate), cashSettlementDays_(cashSettlementDays) { |
83 | |
|
84 | 0 | init(schedule, convention, dayCounter, lastPeriodDayCounter, rebatesAccrual, upfrontDate); |
85 | 0 | } Unexecuted instantiation: QuantLib::CreditDefaultSwap::CreditDefaultSwap(QuantLib::Protection::Side, double, double, double, QuantLib::Schedule const&, QuantLib::BusinessDayConvention, QuantLib::DayCounter const&, bool, bool, QuantLib::Date const&, QuantLib::Date const&, boost::shared_ptr<QuantLib::Claim>, QuantLib::DayCounter const&, bool, QuantLib::Date const&, unsigned int) Unexecuted instantiation: QuantLib::CreditDefaultSwap::CreditDefaultSwap(QuantLib::Protection::Side, double, double, double, QuantLib::Schedule const&, QuantLib::BusinessDayConvention, QuantLib::DayCounter const&, bool, bool, QuantLib::Date const&, QuantLib::Date const&, boost::shared_ptr<QuantLib::Claim>, QuantLib::DayCounter const&, bool, QuantLib::Date const&, unsigned int) |
86 | | |
87 | | void CreditDefaultSwap::init(const Schedule& schedule, BusinessDayConvention paymentConvention, |
88 | | const DayCounter& dayCounter, const DayCounter& lastPeriodDayCounter, |
89 | 0 | bool rebatesAccrual, const Date& upfrontDate) { |
90 | |
|
91 | 0 | QL_REQUIRE(!schedule.empty(), "CreditDefaultSwap needs a non-empty schedule."); |
92 | | |
93 | 0 | bool postBigBang = false; |
94 | 0 | if (schedule.hasRule()) { |
95 | 0 | DateGeneration::Rule rule = schedule.rule(); |
96 | 0 | postBigBang = rule == DateGeneration::CDS || rule == DateGeneration::CDS2015; |
97 | 0 | } |
98 | |
|
99 | 0 | if (!postBigBang) { |
100 | 0 | QL_REQUIRE(protectionStart_ <= schedule[0], "protection can not start after accrual"); |
101 | 0 | } |
102 | | |
103 | 0 | leg_ = FixedRateLeg(schedule) |
104 | 0 | .withNotionals(notional_) |
105 | 0 | .withCouponRates(runningSpread_, dayCounter) |
106 | 0 | .withPaymentAdjustment(paymentConvention) |
107 | 0 | .withLastPeriodDayCounter(lastPeriodDayCounter); |
108 | | |
109 | | // Deduce the trade date if not given. |
110 | 0 | if (tradeDate_ == Date()) { |
111 | 0 | if (postBigBang) { |
112 | 0 | tradeDate_ = protectionStart_; |
113 | 0 | } else { |
114 | 0 | tradeDate_ = protectionStart_ - 1; |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | | // Deduce the cash settlement date if not given. |
119 | 0 | Date effectiveUpfrontDate = upfrontDate; |
120 | 0 | if (effectiveUpfrontDate == Date()) { |
121 | 0 | effectiveUpfrontDate = schedule.calendar().advance(tradeDate_, |
122 | 0 | cashSettlementDays_, Days, paymentConvention); |
123 | 0 | } |
124 | 0 | QL_REQUIRE(effectiveUpfrontDate >= protectionStart_, |
125 | 0 | "The cash settlement date must not be before the protection start date."); |
126 | | |
127 | | // Create the upfront payment, if one is provided. |
128 | 0 | Real upfrontAmount = 0.0; |
129 | 0 | if (upfront_) // NOLINT(readability-implicit-bool-conversion) |
130 | 0 | upfrontAmount = *upfront_ * notional_; |
131 | 0 | upfrontPayment_ = ext::make_shared<SimpleCashFlow>(upfrontAmount, effectiveUpfrontDate); |
132 | | |
133 | | // Set the maturity date. |
134 | 0 | maturity_ = schedule.dates().back(); |
135 | | |
136 | | // Deal with the accrual rebate. We use the standard conventions for accrual calculation introduced with the |
137 | | // CDS Big Bang in 2009. |
138 | 0 | if (rebatesAccrual) { |
139 | |
|
140 | 0 | Real rebateAmount = 0.0; |
141 | 0 | Date refDate = tradeDate_ + 1; |
142 | |
|
143 | 0 | if (tradeDate_ >= schedule.dates().front()) { |
144 | 0 | for (Size i = 0; i < leg_.size(); ++i) { |
145 | 0 | const ext::shared_ptr<CashFlow>& cf = leg_[i]; |
146 | 0 | if (refDate > cf->date()) { |
147 | | // This coupon is in the past; check the next one |
148 | 0 | continue; |
149 | 0 | } else if (refDate == cf->date()) { |
150 | | // This coupon pays at the reference date. |
151 | | // If it's not the last coupon, the accrual is 0 so do nothing. |
152 | 0 | if (i < leg_.size() - 1) |
153 | 0 | rebateAmount = 0.0; |
154 | 0 | else { |
155 | | // On last coupon |
156 | 0 | ext::shared_ptr<FixedRateCoupon> frc = ext::dynamic_pointer_cast<FixedRateCoupon>(cf); |
157 | 0 | rebateAmount = frc->amount(); |
158 | 0 | } |
159 | 0 | break; |
160 | 0 | } else { |
161 | | // This coupon pays in the future, and is the first coupon to do so (since they're sorted). |
162 | | // Calculate the accrual and skip further coupons |
163 | 0 | ext::shared_ptr<FixedRateCoupon> frc = ext::dynamic_pointer_cast<FixedRateCoupon>(cf); |
164 | 0 | rebateAmount = frc->accruedAmount(refDate); |
165 | 0 | break; |
166 | 0 | } |
167 | 0 | } |
168 | 0 | } |
169 | |
|
170 | 0 | accrualRebate_ = ext::make_shared<SimpleCashFlow>(rebateAmount, effectiveUpfrontDate); |
171 | 0 | } |
172 | |
|
173 | 0 | if (!claim_) |
174 | 0 | claim_ = ext::make_shared<FaceValueClaim>(); |
175 | 0 | registerWith(claim_); |
176 | 0 | } |
177 | | |
178 | 0 | Protection::Side CreditDefaultSwap::side() const { |
179 | 0 | return side_; |
180 | 0 | } |
181 | | |
182 | 0 | Real CreditDefaultSwap::notional() const { |
183 | 0 | return notional_; |
184 | 0 | } |
185 | | |
186 | 0 | Rate CreditDefaultSwap::runningSpread() const { |
187 | 0 | return runningSpread_; |
188 | 0 | } |
189 | | |
190 | 0 | ext::optional<Rate> CreditDefaultSwap::upfront() const { |
191 | 0 | return upfront_; |
192 | 0 | } |
193 | | |
194 | 0 | bool CreditDefaultSwap::settlesAccrual() const { |
195 | 0 | return settlesAccrual_; |
196 | 0 | } |
197 | | |
198 | 0 | bool CreditDefaultSwap::paysAtDefaultTime() const { |
199 | 0 | return paysAtDefaultTime_; |
200 | 0 | } |
201 | | |
202 | 0 | const Leg& CreditDefaultSwap::coupons() const { |
203 | 0 | return leg_; |
204 | 0 | } |
205 | | |
206 | | |
207 | 0 | bool CreditDefaultSwap::isExpired() const { |
208 | 0 | for (auto i = leg_.rbegin(); i != leg_.rend(); ++i) { |
209 | 0 | if (!(*i)->hasOccurred()) |
210 | 0 | return false; |
211 | 0 | } |
212 | 0 | return true; |
213 | 0 | } |
214 | | |
215 | 0 | void CreditDefaultSwap::setupExpired() const { |
216 | 0 | Instrument::setupExpired(); |
217 | 0 | fairSpread_ = fairUpfront_ = 0.0; |
218 | 0 | couponLegBPS_ = upfrontBPS_ = 0.0; |
219 | 0 | couponLegNPV_ = defaultLegNPV_ = upfrontNPV_ = 0.0; |
220 | 0 | } |
221 | | |
222 | | void CreditDefaultSwap::setupArguments( |
223 | 0 | PricingEngine::arguments* args) const { |
224 | 0 | auto* arguments = dynamic_cast<CreditDefaultSwap::arguments*>(args); |
225 | 0 | QL_REQUIRE(arguments != nullptr, "wrong argument type"); |
226 | | |
227 | 0 | arguments->side = side_; |
228 | 0 | arguments->notional = notional_; |
229 | 0 | arguments->leg = leg_; |
230 | 0 | arguments->upfrontPayment = upfrontPayment_; |
231 | 0 | arguments->accrualRebate = accrualRebate_; |
232 | 0 | arguments->settlesAccrual = settlesAccrual_; |
233 | 0 | arguments->paysAtDefaultTime = paysAtDefaultTime_; |
234 | 0 | arguments->claim = claim_; |
235 | 0 | arguments->upfront = upfront_; |
236 | 0 | arguments->spread = runningSpread_; |
237 | 0 | arguments->protectionStart = protectionStart_; |
238 | 0 | arguments->maturity = maturity_; |
239 | 0 | } |
240 | | |
241 | | |
242 | | void CreditDefaultSwap::fetchResults( |
243 | 0 | const PricingEngine::results* r) const { |
244 | 0 | Instrument::fetchResults(r); |
245 | |
|
246 | 0 | const auto* results = dynamic_cast<const CreditDefaultSwap::results*>(r); |
247 | 0 | QL_REQUIRE(results != nullptr, "wrong result type"); |
248 | | |
249 | 0 | fairSpread_ = results->fairSpread; |
250 | 0 | fairUpfront_ = results->fairUpfront; |
251 | 0 | couponLegBPS_ = results->couponLegBPS; |
252 | 0 | couponLegNPV_ = results->couponLegNPV; |
253 | 0 | defaultLegNPV_ = results->defaultLegNPV; |
254 | 0 | upfrontNPV_ = results->upfrontNPV; |
255 | 0 | upfrontBPS_ = results->upfrontBPS; |
256 | 0 | accrualRebateNPV_ = results->accrualRebateNPV; |
257 | 0 | } |
258 | | |
259 | 0 | Rate CreditDefaultSwap::fairUpfront() const { |
260 | 0 | calculate(); |
261 | 0 | QL_REQUIRE(fairUpfront_ != Null<Rate>(), |
262 | 0 | "fair upfront not available"); |
263 | 0 | return fairUpfront_; |
264 | 0 | } |
265 | | |
266 | 0 | Rate CreditDefaultSwap::fairSpread() const { |
267 | 0 | calculate(); |
268 | 0 | QL_REQUIRE(fairSpread_ != Null<Rate>(), |
269 | 0 | "fair spread not available"); |
270 | 0 | return fairSpread_; |
271 | 0 | } |
272 | | |
273 | 0 | Real CreditDefaultSwap::couponLegBPS() const { |
274 | 0 | calculate(); |
275 | 0 | QL_REQUIRE(couponLegBPS_ != Null<Rate>(), |
276 | 0 | "coupon-leg BPS not available"); |
277 | 0 | return couponLegBPS_; |
278 | 0 | } |
279 | | |
280 | 0 | Real CreditDefaultSwap::couponLegNPV() const { |
281 | 0 | calculate(); |
282 | 0 | QL_REQUIRE(couponLegNPV_ != Null<Rate>(), |
283 | 0 | "coupon-leg NPV not available"); |
284 | 0 | return couponLegNPV_; |
285 | 0 | } |
286 | | |
287 | 0 | Real CreditDefaultSwap::defaultLegNPV() const { |
288 | 0 | calculate(); |
289 | 0 | QL_REQUIRE(defaultLegNPV_ != Null<Rate>(), |
290 | 0 | "default-leg NPV not available"); |
291 | 0 | return defaultLegNPV_; |
292 | 0 | } |
293 | | |
294 | 0 | Real CreditDefaultSwap::upfrontNPV() const { |
295 | 0 | calculate(); |
296 | 0 | QL_REQUIRE(upfrontNPV_ != Null<Real>(), |
297 | 0 | "upfront NPV not available"); |
298 | 0 | return upfrontNPV_; |
299 | 0 | } |
300 | | |
301 | 0 | Real CreditDefaultSwap::upfrontBPS() const { |
302 | 0 | calculate(); |
303 | 0 | QL_REQUIRE(upfrontBPS_ != Null<Real>(), |
304 | 0 | "upfront BPS not available"); |
305 | 0 | return upfrontBPS_; |
306 | 0 | } |
307 | | |
308 | 0 | Real CreditDefaultSwap::accrualRebateNPV() const { |
309 | 0 | calculate(); |
310 | 0 | QL_REQUIRE(accrualRebateNPV_ != Null<Real>(), |
311 | 0 | "accrual Rebate NPV not available"); |
312 | 0 | return accrualRebateNPV_; |
313 | 0 | } |
314 | | |
315 | | namespace { |
316 | | |
317 | | class ObjectiveFunction { |
318 | | public: |
319 | | ObjectiveFunction(Real target, |
320 | | SimpleQuote& quote, |
321 | | PricingEngine& engine, |
322 | | const CreditDefaultSwap::results* results) |
323 | 0 | : target_(target), quote_(quote), |
324 | 0 | engine_(engine), results_(results) {} |
325 | | |
326 | 0 | Real operator()(Real guess) const { |
327 | 0 | quote_.setValue(guess); |
328 | 0 | engine_.calculate(); |
329 | 0 | return results_->value - target_; |
330 | 0 | } |
331 | | private: |
332 | | Real target_; |
333 | | SimpleQuote& quote_; |
334 | | PricingEngine& engine_; |
335 | | const CreditDefaultSwap::results* results_; |
336 | | }; |
337 | | |
338 | | } |
339 | | |
340 | | Rate CreditDefaultSwap::impliedHazardRate( |
341 | | Real targetNPV, |
342 | | const Handle<YieldTermStructure>& discountCurve, |
343 | | const DayCounter& dayCounter, |
344 | | Real recoveryRate, |
345 | | Real accuracy, |
346 | 0 | PricingModel model) const { |
347 | |
|
348 | 0 | ext::shared_ptr<SimpleQuote> flatRate = ext::make_shared<SimpleQuote>(0.0); |
349 | |
|
350 | 0 | Handle<DefaultProbabilityTermStructure> probability = |
351 | 0 | Handle<DefaultProbabilityTermStructure>( |
352 | 0 | ext::make_shared<FlatHazardRate>(0, WeekendsOnly(), |
353 | 0 | Handle<Quote>(flatRate), dayCounter)); |
354 | |
|
355 | 0 | ext::shared_ptr<PricingEngine> engine; |
356 | 0 | switch (model) { |
357 | 0 | case Midpoint: |
358 | 0 | engine = ext::make_shared<MidPointCdsEngine>( |
359 | 0 | probability, recoveryRate, discountCurve); |
360 | 0 | break; |
361 | 0 | case ISDA: |
362 | 0 | engine = ext::make_shared<IsdaCdsEngine>( |
363 | 0 | probability, recoveryRate, discountCurve, |
364 | 0 | ext::nullopt, |
365 | 0 | IsdaCdsEngine::Taylor, |
366 | 0 | IsdaCdsEngine::HalfDayBias, |
367 | 0 | IsdaCdsEngine::Piecewise); |
368 | 0 | break; |
369 | 0 | default: |
370 | 0 | QL_FAIL("unknown CDS pricing model: " << model); |
371 | 0 | } |
372 | | |
373 | 0 | setupArguments(engine->getArguments()); |
374 | 0 | const auto* results = dynamic_cast<const CreditDefaultSwap::results*>(engine->getResults()); |
375 | |
|
376 | 0 | ObjectiveFunction f(targetNPV, *flatRate, *engine, results); |
377 | | //very close guess if targetNPV = 0. |
378 | 0 | Rate guess = runningSpread_ / (1 - recoveryRate) * 365./360.; |
379 | 0 | Real step = 0.1 * guess; |
380 | 0 | return Brent().solve(f, accuracy, guess, step); |
381 | 0 | } |
382 | | |
383 | | Rate CreditDefaultSwap::conventionalSpread( |
384 | | Real conventionalRecovery, |
385 | | const Handle<YieldTermStructure>& discountCurve, |
386 | | const DayCounter& dayCounter, |
387 | 0 | PricingModel model) const { |
388 | |
|
389 | 0 | ext::shared_ptr<SimpleQuote> flatRate = ext::make_shared<SimpleQuote>(0.0); |
390 | |
|
391 | 0 | Handle<DefaultProbabilityTermStructure> probability = |
392 | 0 | Handle<DefaultProbabilityTermStructure>( |
393 | 0 | ext::make_shared<FlatHazardRate>(0, WeekendsOnly(), |
394 | 0 | Handle<Quote>(flatRate), dayCounter)); |
395 | |
|
396 | 0 | ext::shared_ptr<PricingEngine> engine; |
397 | 0 | switch (model) { |
398 | 0 | case Midpoint: |
399 | 0 | engine = ext::make_shared<MidPointCdsEngine>( |
400 | 0 | probability, conventionalRecovery, discountCurve); |
401 | 0 | break; |
402 | 0 | case ISDA: |
403 | 0 | engine = ext::make_shared<IsdaCdsEngine>( |
404 | 0 | probability, conventionalRecovery, discountCurve, |
405 | 0 | ext::nullopt, |
406 | 0 | IsdaCdsEngine::Taylor, |
407 | 0 | IsdaCdsEngine::HalfDayBias, |
408 | 0 | IsdaCdsEngine::Piecewise); |
409 | 0 | break; |
410 | 0 | default: |
411 | 0 | QL_FAIL("unknown CDS pricing model: " << model); |
412 | 0 | } |
413 | | |
414 | 0 | setupArguments(engine->getArguments()); |
415 | 0 | const auto* results = dynamic_cast<const CreditDefaultSwap::results*>(engine->getResults()); |
416 | |
|
417 | 0 | ObjectiveFunction f(0., *flatRate, *engine, results); |
418 | 0 | Rate guess = runningSpread_ / (1 - conventionalRecovery) * 365./360.; |
419 | 0 | Real step = guess * 0.1; |
420 | |
|
421 | 0 | Brent().solve(f, 1e-9, guess, step); |
422 | 0 | return results->fairSpread; |
423 | 0 | } |
424 | | |
425 | | |
426 | 0 | const Date& CreditDefaultSwap::protectionStartDate() const { |
427 | 0 | return protectionStart_; |
428 | 0 | } |
429 | | |
430 | 0 | const Date& CreditDefaultSwap::protectionEndDate() const { |
431 | 0 | return ext::dynamic_pointer_cast<Coupon>(leg_.back()) |
432 | 0 | ->accrualEndDate(); |
433 | 0 | } |
434 | | |
435 | 0 | const ext::shared_ptr<SimpleCashFlow>& CreditDefaultSwap::upfrontPayment() const { |
436 | 0 | return upfrontPayment_; |
437 | 0 | } |
438 | | |
439 | 0 | const ext::shared_ptr<SimpleCashFlow>& CreditDefaultSwap::accrualRebate() const { |
440 | 0 | return accrualRebate_; |
441 | 0 | } |
442 | | |
443 | 0 | const Date& CreditDefaultSwap::tradeDate() const { |
444 | 0 | return tradeDate_; |
445 | 0 | } |
446 | | |
447 | 0 | Natural CreditDefaultSwap::cashSettlementDays() const { |
448 | 0 | return cashSettlementDays_; |
449 | 0 | } |
450 | | |
451 | | CreditDefaultSwap::arguments::arguments() |
452 | 0 | : side(Protection::Side(-1)), notional(Null<Real>()), |
453 | 0 | spread(Null<Rate>()) {}Unexecuted instantiation: QuantLib::CreditDefaultSwap::arguments::arguments() Unexecuted instantiation: QuantLib::CreditDefaultSwap::arguments::arguments() |
454 | | |
455 | 0 | void CreditDefaultSwap::arguments::validate() const { |
456 | 0 | QL_REQUIRE(side != Protection::Side(-1), "side not set"); |
457 | 0 | QL_REQUIRE(notional != Null<Real>(), "notional not set"); |
458 | 0 | QL_REQUIRE(notional != 0.0, "null notional set"); |
459 | 0 | QL_REQUIRE(spread != Null<Rate>(), "spread not set"); |
460 | 0 | QL_REQUIRE(!leg.empty(), "coupons not set"); |
461 | 0 | QL_REQUIRE(upfrontPayment, "upfront payment not set"); |
462 | 0 | QL_REQUIRE(claim, "claim not set"); |
463 | 0 | QL_REQUIRE(protectionStart != Date(), "protection start date not set"); |
464 | 0 | QL_REQUIRE(maturity != Date(), "maturity date not set"); |
465 | 0 | } |
466 | | |
467 | 0 | void CreditDefaultSwap::results::reset() { |
468 | 0 | Instrument::results::reset(); |
469 | 0 | fairSpread = Null<Rate>(); |
470 | 0 | fairUpfront = Null<Rate>(); |
471 | 0 | couponLegBPS = Null<Real>(); |
472 | 0 | couponLegNPV = Null<Real>(); |
473 | 0 | defaultLegNPV = Null<Real>(); |
474 | 0 | upfrontBPS = Null<Real>(); |
475 | 0 | upfrontNPV = Null<Real>(); |
476 | 0 | accrualRebateNPV = Null<Real>(); |
477 | 0 | } |
478 | | |
479 | 0 | Date cdsMaturity(const Date& tradeDate, const Period& tenor, DateGeneration::Rule rule) { |
480 | |
|
481 | 0 | QL_REQUIRE(rule == DateGeneration::CDS2015 || rule == DateGeneration::CDS || rule == DateGeneration::OldCDS, |
482 | 0 | "cdsMaturity should only be used with date generation rule CDS2015, CDS or OldCDS"); |
483 | | |
484 | 0 | QL_REQUIRE(tenor.units() == Years || (tenor.units() == Months && tenor.length() % 3 == 0), |
485 | 0 | "cdsMaturity expects a tenor that is a multiple of 3 months."); |
486 | | |
487 | 0 | if (rule == DateGeneration::OldCDS) { |
488 | 0 | QL_REQUIRE(tenor != 0 * Months, "A tenor of 0M is not supported for OldCDS."); |
489 | 0 | } |
490 | | |
491 | 0 | Date anchorDate = previousTwentieth(tradeDate, rule); |
492 | 0 | if (rule == DateGeneration::CDS2015 && (anchorDate == Date(20, Dec, anchorDate.year()) || |
493 | 0 | anchorDate == Date(20, Jun, anchorDate.year()))) { |
494 | 0 | if (tenor.length() == 0) { |
495 | 0 | return Date(); |
496 | 0 | } else { |
497 | 0 | anchorDate -= 3 * Months; |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | 0 | Date maturity = anchorDate + tenor + 3 * Months; |
502 | 0 | QL_REQUIRE(maturity > tradeDate, "error calculating CDS maturity. Tenor is " << tenor << ", trade date is " << |
503 | 0 | io::iso_date(tradeDate) << " generating a maturity of " << io::iso_date(maturity) << " <= trade date."); |
504 | | |
505 | 0 | return maturity; |
506 | 0 | } |
507 | | |
508 | | } |