| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2014 Jose Aparicio |
| 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 | #ifndef quantlib_base_correl_structure_hpp |
| 21 | #define quantlib_base_correl_structure_hpp |
| 22 | |
| 23 | #include <ql/quote.hpp> |
| 24 | #include <ql/utilities/dataformatters.hpp> |
| 25 | #include <ql/math/interpolations/bilinearinterpolation.hpp> |
| 26 | #include <ql/math/interpolations/bicubicsplineinterpolation.hpp> |
| 27 | |
| 28 | #include <ql/experimental/credit/correlationstructure.hpp> |
| 29 | |
| 30 | namespace QuantLib { |
| 31 | |
| 32 | |
| 33 | /*! Matrix based Base Correlation Term Structure\par |
| 34 | Loss level versus time interpolated scalar copula type parametric |
| 35 | correlation term structure. Represents the correlation for the credit loss |
| 36 | level of a given portfolio at a given loss level and time. |
| 37 | |
| 38 | \todo The relation to a given basket is to be made explicit for bespoke |
| 39 | models to be implemented. |
| 40 | \todo Consider moving to a matrix data structure. A matrix might make some |
| 41 | computations heavy, template specialization on the dimension might be an |
| 42 | alternative to having two classes, one for scalars and another for matrices. |
| 43 | \todo Rethink all the data structure with a basket where current losses are |
| 44 | not zero. |
| 45 | \todo In principle the 2D interpolator is left optional since there are |
| 46 | arbitrage issues on the interpolator type to be used. However one has to be |
| 47 | careful when using non local interpolators like CubicSplines which have an |
| 48 | effect on the past (calibrated) coupons of previous tenors. |
| 49 | */ |
| 50 | template<class Interpolator2D_T> |
| 51 | class BaseCorrelationTermStructure : public CorrelationTermStructure { |
| 52 | public: |
| 53 | /* |
| 54 | @param correls Corresponds to: correls[iYear][iLoss] |
| 55 | |
| 56 | The Settlement date should in an ideal world coincide with the |
| 57 | (implicit) basket inception date and its default term structures |
| 58 | settlement dates. |
| 59 | */ |
| 60 | BaseCorrelationTermStructure( |
| 61 | Natural settlementDays, |
| 62 | const Calendar& cal, |
| 63 | BusinessDayConvention bdc, |
| 64 | const std::vector<Period>& tenors,// sorted |
| 65 | const std::vector<Real>& lossLevel,//sorted |
| 66 | const std::vector<std::vector<Handle<Quote> > >& correls, |
| 67 | const DayCounter& dc = DayCounter() |
| 68 | ) |
| 69 | : CorrelationTermStructure(settlementDays, cal, bdc, dc), |
| 70 | correlHandles_(correls), |
| 71 | correlations_(correls.size(), correls.front().size()), |
| 72 | nTrancheTenors_(tenors.size()), |
| 73 | nLosses_(lossLevel.size()), |
| 74 | tenors_(tenors), |
| 75 | lossLevel_(lossLevel), |
| 76 | trancheTimes_(tenors.size(), 0.) { |
| 77 | checkTrancheTenors(); |
| 78 | |
| 79 | for (auto& tenor : tenors_) |
| 80 | trancheDates_.push_back( |
| 81 | calendar().advance(referenceDate(), tenor, businessDayConvention())); |
| 82 | |
| 83 | initializeTrancheTimes(); |
| 84 | checkInputs(volRows: correlations_.rows(), volsColumns: correlations_.columns()); |
| 85 | updateMatrix(); |
| 86 | registerWithMarketData(); |
| 87 | // call factory |
| 88 | setupInterpolation(); |
| 89 | } |
| 90 | private: |
| 91 | virtual void setupInterpolation() ; |
| 92 | public: |
| 93 | Size correlationSize() const override { return 1; } |
| 94 | //! Implicit correlation for the given loss interval. |
| 95 | Real ImplicitCorrelation(Real, Real); |
| 96 | |
| 97 | void checkTrancheTenors() const; |
| 98 | void checkLosses() const; |
| 99 | void initializeTrancheTimes() const; |
| 100 | void checkInputs(Size volRows, Size volsColumns) const; |
| 101 | void registerWithMarketData(); |
| 102 | |
| 103 | void update() override; |
| 104 | void updateMatrix() const; |
| 105 | |
| 106 | // TermStructure interface |
| 107 | Date maxDate() const override { return trancheDates_.back(); } |
| 108 | Real correlation(const Date& d, Real lossLevel, bool = false) const { |
| 109 | return correlation(timeFromReference(d), lossLevel, extrapolate); |
| 110 | } |
| 111 | Real correlation(Time t, Real lossLevel, |
| 112 | bool = false) const |
| 113 | { |
| 114 | return interpolation_(t, lossLevel, true); |
| 115 | } |
| 116 | private: |
| 117 | std::vector<std::vector<Handle<Quote> > > correlHandles_; |
| 118 | mutable Matrix correlations_; |
| 119 | Interpolation2D interpolation_; |
| 120 | Size nTrancheTenors_, |
| 121 | nLosses_; |
| 122 | std::vector<Period> tenors_; |
| 123 | mutable std::vector<Real> lossLevel_; |
| 124 | mutable std::vector<Date> trancheDates_; |
| 125 | mutable std::vector<Time> trancheTimes_; |
| 126 | }; |
| 127 | |
| 128 | // ---------------------------------------------------------------------- |
| 129 | |
| 130 | template <class I2D_T> |
| 131 | void BaseCorrelationTermStructure<I2D_T>::checkTrancheTenors() const { |
| 132 | QL_REQUIRE(tenors_[0]>0*Days, |
| 133 | "first tranche tenor is negative (" << |
| 134 | tenors_[0] << ")" ); |
| 135 | for (Size i=1; i<nTrancheTenors_; ++i) |
| 136 | QL_REQUIRE(tenors_[i]>tenors_[i-1], |
| 137 | "non increasing tranche tenor: " << io::ordinal(i) << |
| 138 | " is " << tenors_[i-1] << ", " << io::ordinal(i+1) << |
| 139 | " is " << tenors_[i]); |
| 140 | } |
| 141 | |
| 142 | template <class I2D_T> |
| 143 | void BaseCorrelationTermStructure<I2D_T>::checkLosses() const { |
| 144 | QL_REQUIRE(lossLevel_[0]>0., |
| 145 | "first loss level is negative (" << |
| 146 | lossLevel_[0] << ")" ); |
| 147 | QL_REQUIRE(lossLevel_[0] <= 1., |
| 148 | "First loss level larger than 100% (" << lossLevel_[0] <<")" ); |
| 149 | for (Size i=1; i<nLosses_; ++i) { |
| 150 | QL_REQUIRE(lossLevel_[i]>lossLevel_[i-1], |
| 151 | "non increasing losses: " << io::ordinal(i) << |
| 152 | " is " << lossLevel_[i-1] << ", " << io::ordinal(i+1) << |
| 153 | " is " << lossLevel_[i]); |
| 154 | QL_REQUIRE(lossLevel_[i] <= 1., |
| 155 | "Loss level " << i << " larger than 100% (" << lossLevel_[i] <<")" ); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | template <class I2D_T> |
| 160 | void BaseCorrelationTermStructure<I2D_T>::initializeTrancheTimes() const { |
| 161 | for (Size i=0; i<nTrancheTenors_; ++i) |
| 162 | trancheTimes_[i] = timeFromReference(d: trancheDates_[i]); |
| 163 | } |
| 164 | |
| 165 | template <class I2D_T> |
| 166 | void BaseCorrelationTermStructure<I2D_T>::checkInputs(Size volRows, |
| 167 | Size volsColumns) const { |
| 168 | QL_REQUIRE(nLosses_==volRows, |
| 169 | "mismatch between number of loss levels (" << |
| 170 | nLosses_ << ") and number of rows (" << volRows << |
| 171 | ") in the correl matrix" ); |
| 172 | QL_REQUIRE(nTrancheTenors_==volsColumns, |
| 173 | "mismatch between number of tranche tenors (" << |
| 174 | nTrancheTenors_ << ") and number of columns (" << |
| 175 | volsColumns << ") in the correl matrix" ); |
| 176 | } |
| 177 | |
| 178 | template <class I2D_T> |
| 179 | void BaseCorrelationTermStructure<I2D_T>::registerWithMarketData() |
| 180 | { |
| 181 | for (Size i=0; i<correlHandles_.size(); ++i) |
| 182 | for (Size j=0; j<correlHandles_.front().size(); ++j) |
| 183 | registerWith(h: correlHandles_[i][j]); |
| 184 | } |
| 185 | |
| 186 | template <class I2D_T> |
| 187 | void BaseCorrelationTermStructure<I2D_T>::update() { |
| 188 | updateMatrix(); |
| 189 | TermStructure::update(); |
| 190 | } |
| 191 | |
| 192 | template <class I2D_T> |
| 193 | void BaseCorrelationTermStructure<I2D_T>::updateMatrix() const { |
| 194 | for (Size i=0; i<correlHandles_.size(); ++i) |
| 195 | for (Size j=0; j<correlHandles_.front().size(); ++j) |
| 196 | correlations_[i][j] = correlHandles_[i][j]->value(); |
| 197 | |
| 198 | } |
| 199 | |
| 200 | } |
| 201 | |
| 202 | #endif |
| 203 | |