| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2009 StatPro Italia srl |
| 5 | Copyright (C) 2009 Jose Aparicio |
| 6 | |
| 7 | This file is part of QuantLib, a free-software/open-source library |
| 8 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 9 | |
| 10 | QuantLib is free software: you can redistribute it and/or modify it |
| 11 | under the terms of the QuantLib license. You should have received a |
| 12 | copy of the license along with this program; if not, please email |
| 13 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 14 | <http://quantlib.org/license.shtml>. |
| 15 | |
| 16 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 18 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 19 | */ |
| 20 | |
| 21 | #include <ql/experimental/credit/defaultevent.hpp> |
| 22 | #include <ql/experimental/credit/recoveryratequote.hpp> |
| 23 | #include <ql/patterns/visitor.hpp> |
| 24 | #include <ql/settings.hpp> |
| 25 | #include <utility> |
| 26 | |
| 27 | namespace QuantLib { |
| 28 | |
| 29 | Date DefaultEvent::date() const { |
| 30 | return defaultDate_; |
| 31 | } |
| 32 | |
| 33 | void DefaultEvent::accept(AcyclicVisitor& v) { |
| 34 | auto* v1 = dynamic_cast<Visitor<DefaultEvent>*>(&v); |
| 35 | if (v1 != nullptr) |
| 36 | v1->visit(*this); |
| 37 | else |
| 38 | Event::accept(v); |
| 39 | } |
| 40 | |
| 41 | // They will be sorted by settlement date |
| 42 | Date DefaultEvent::DefaultSettlement::date() const { |
| 43 | return settlementDate_; |
| 44 | } |
| 45 | |
| 46 | void DefaultEvent::DefaultSettlement::accept(AcyclicVisitor& v) { |
| 47 | auto* v1 = dynamic_cast<Visitor<DefaultEvent::DefaultSettlement>*>(&v); |
| 48 | if (v1 != nullptr) |
| 49 | v1->visit(*this); |
| 50 | else |
| 51 | Event::accept(v); |
| 52 | } |
| 53 | |
| 54 | DefaultEvent::DefaultSettlement::DefaultSettlement( |
| 55 | const Date& date, |
| 56 | const std::map<Seniority, Real>& recoveryRates ) |
| 57 | : settlementDate_(date), recoveryRates_(recoveryRates) { |
| 58 | QL_REQUIRE(recoveryRates.find(NoSeniority) == |
| 59 | recoveryRates.end(), |
| 60 | "NoSeniority is not a valid realized seniority." ); |
| 61 | } |
| 62 | |
| 63 | DefaultEvent::DefaultSettlement::DefaultSettlement( |
| 64 | const Date& date, |
| 65 | Seniority seniority, |
| 66 | const Real recoveryRate) |
| 67 | : settlementDate_(date), recoveryRates_(makeIsdaConvMap()) { |
| 68 | if (seniority == NoSeniority) { |
| 69 | for (auto& i : recoveryRates_) { |
| 70 | i.second = recoveryRate; |
| 71 | } |
| 72 | } else { |
| 73 | recoveryRates_[seniority] = recoveryRate; |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | Real DefaultEvent::DefaultSettlement::recoveryRate( |
| 78 | Seniority sen) const { |
| 79 | // expensive require cause called often...... fix me |
| 80 | QL_REQUIRE(sen != NoSeniority, |
| 81 | "NoSeniority is not valid for recovery rate request." ); |
| 82 | auto itmatch = recoveryRates_.find(x: sen); |
| 83 | if(itmatch != recoveryRates_.end()) { |
| 84 | return itmatch->second; |
| 85 | }else{ |
| 86 | return Null<Real>(); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | DefaultEvent::DefaultEvent(const Date& creditEventDate, |
| 91 | const DefaultType& atomicEvType, |
| 92 | Currency curr, |
| 93 | Seniority bondsSen, |
| 94 | // Settlement information: |
| 95 | const Date& settleDate, |
| 96 | const std::map<Seniority, Real>& recoveryRates) |
| 97 | : bondsCurrency_(std::move(curr)), defaultDate_(creditEventDate), eventType_(atomicEvType), |
| 98 | bondsSeniority_(bondsSen), |
| 99 | defSettlement_(settleDate, recoveryRates.empty() ? makeIsdaConvMap() : recoveryRates) { |
| 100 | if(settleDate != Null<Date>()) {// has settled |
| 101 | QL_REQUIRE(settleDate >= creditEventDate, |
| 102 | "Settlement date should be after default date." ); |
| 103 | QL_REQUIRE(recoveryRates.find(bondsSen) != recoveryRates.end(), |
| 104 | "Settled events must contain the seniority of the default" ); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | DefaultEvent::DefaultEvent(const Date& creditEventDate, |
| 109 | const DefaultType& atomicEvType, |
| 110 | Currency curr, |
| 111 | Seniority bondsSen, |
| 112 | // Settlement information: |
| 113 | const Date& settleDate, |
| 114 | Real recoveryRate) |
| 115 | : bondsCurrency_(std::move(curr)), defaultDate_(creditEventDate), eventType_(atomicEvType), |
| 116 | bondsSeniority_(bondsSen), defSettlement_(settleDate, bondsSen, recoveryRate) { |
| 117 | if(settleDate != Null<Date>()) { |
| 118 | QL_REQUIRE(settleDate >= creditEventDate, |
| 119 | "Settlement date should be after default date." ); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | bool DefaultEvent::matchesDefaultKey( |
| 124 | const DefaultProbKey& contractKey) const { |
| 125 | if(bondsCurrency_ != contractKey.currency()) return false; |
| 126 | // a contract with NoSeniority matches all events |
| 127 | if((bondsSeniority_ != contractKey.seniority()) |
| 128 | && (contractKey.seniority() != NoSeniority)) |
| 129 | return false; |
| 130 | // loop on all event types in the contract and chek if we match any, |
| 131 | // calls derived types |
| 132 | for(Size i=0; i<contractKey.size(); i++) { |
| 133 | if(this->matchesEventType(contractEvType: contractKey.eventTypes()[i])) return true; |
| 134 | } |
| 135 | return false; |
| 136 | } |
| 137 | |
| 138 | |
| 139 | |
| 140 | bool operator==(const DefaultEvent& lhs, const DefaultEvent& rhs) { |
| 141 | return (lhs.currency() == rhs.currency()) && |
| 142 | (lhs.defaultType() == rhs.defaultType()) && |
| 143 | (lhs.date() == rhs.date()) && |
| 144 | (lhs.eventSeniority() == rhs.eventSeniority()); |
| 145 | } |
| 146 | |
| 147 | |
| 148 | bool FailureToPayEvent::matchesEventType( |
| 149 | const ext::shared_ptr<DefaultType>& contractEvType) const { |
| 150 | ext::shared_ptr<FailureToPay> eveType = |
| 151 | ext::dynamic_pointer_cast<FailureToPay>(r: contractEvType); |
| 152 | // this chekcs the atomic types, no need to call parents method |
| 153 | if(!eveType) return false; |
| 154 | if(defaultedAmount_ < eveType->amountRequired()) return false; |
| 155 | Date today = Settings::instance().evaluationDate(); |
| 156 | return this->hasOccurred(refDate: today - eveType->gracePeriod(), includeRefDate: true); |
| 157 | } |
| 158 | |
| 159 | |
| 160 | |
| 161 | FailureToPayEvent::FailureToPayEvent(const Date& creditEventDate, |
| 162 | const Currency& curr, |
| 163 | Seniority bondsSen, |
| 164 | Real defaultedAmount, |
| 165 | // Settlement information: |
| 166 | const Date& settleDate, |
| 167 | const std::map<Seniority, Real>& |
| 168 | recoveryRates) |
| 169 | : DefaultEvent(creditEventDate, |
| 170 | DefaultType(AtomicDefault::FailureToPay, |
| 171 | Restructuring::XR), |
| 172 | curr, |
| 173 | bondsSen, |
| 174 | settleDate, |
| 175 | recoveryRates), |
| 176 | defaultedAmount_(defaultedAmount) { } |
| 177 | |
| 178 | FailureToPayEvent::FailureToPayEvent(const Date& creditEventDate, |
| 179 | const Currency& curr, |
| 180 | Seniority bondsSen, |
| 181 | Real defaultedAmount, |
| 182 | // Settlement information: |
| 183 | const Date& settleDate, |
| 184 | Real recoveryRates) |
| 185 | : DefaultEvent(creditEventDate, |
| 186 | DefaultType(AtomicDefault::FailureToPay, |
| 187 | Restructuring::XR), |
| 188 | curr, |
| 189 | bondsSen, |
| 190 | settleDate, |
| 191 | recoveryRates), |
| 192 | defaultedAmount_(defaultedAmount) { } |
| 193 | |
| 194 | |
| 195 | |
| 196 | BankruptcyEvent::BankruptcyEvent(const Date& creditEventDate, |
| 197 | const Currency& curr, |
| 198 | Seniority bondsSen, |
| 199 | // Settlement information: |
| 200 | const Date& settleDate, |
| 201 | const std::map<Seniority, Real>& |
| 202 | recoveryRates) |
| 203 | : DefaultEvent(creditEventDate, |
| 204 | DefaultType(AtomicDefault::Bankruptcy, |
| 205 | Restructuring::XR), |
| 206 | curr, |
| 207 | bondsSen, |
| 208 | settleDate, |
| 209 | recoveryRates) { |
| 210 | if(hasSettled()) { |
| 211 | QL_REQUIRE(recoveryRates.size() == makeIsdaConvMap().size(), |
| 212 | "Bankruptcy event should have settled for all seniorities." ); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | BankruptcyEvent::BankruptcyEvent(const Date& creditEventDate, |
| 217 | const Currency& curr, |
| 218 | Seniority bondsSen, |
| 219 | // Settlement information: |
| 220 | const Date& settleDate, |
| 221 | // means same for all |
| 222 | Real recoveryRates) |
| 223 | : DefaultEvent(creditEventDate, |
| 224 | DefaultType(AtomicDefault::Bankruptcy, |
| 225 | Restructuring::XR), |
| 226 | curr, |
| 227 | bondsSen, |
| 228 | settleDate, |
| 229 | recoveryRates) { } |
| 230 | |
| 231 | } |
| 232 | |