00001 #include ".\creditCurve.h"
00002 #include "..\common\utils.h"
00003 #include <cmath>
00004
00005 CreditSpreadPoint::CreditSpreadPoint(void) :
00006 _rate(0), _maturity(0), _spreadtype(Relative) { }
00007 CreditSpreadPoint::CreditSpreadPoint(Real r, Real T, CreditSpreadType t) :
00008 _rate(r), _maturity(T), _spreadtype(t) { }
00009 CreditSpreadPoint::~CreditSpreadPoint(void) { }
00010
00011 char *CreditSpreadPoint::TypeAsString(CreditSpreadType t)
00012 {
00013 switch (t) {
00014 case Absolute:
00015 return "Abs";
00016 case Relative:
00017 return "Rel";
00018 default:
00019 return "No spread type has been defined";
00020 }
00021 }
00022
00023
00024 creditCurve::creditCurve(void) :
00025 yieldCurve(),
00026 _spreads(CC_MAX_NUM_SPREADS),
00027 _survivalProbability(CC_MAX_NUM_SPREADS),
00028 _defaultProbability(CC_MAX_NUM_SPREADS),
00029 _swapFees(CC_MAX_NUM_SPREADS) {
00030 }
00031
00032 creditCurve::creditCurve(yieldCurve &yc,
00033 valarray<CreditSpreadPoint> &cp,
00034 char *name,
00035 Real recoveryRate,
00036 Currency currency,
00037 Frequency frequency) :
00038 _spreads(CC_MAX_NUM_SPREADS),
00039 _survivalProbability(CC_MAX_NUM_SPREADS),
00040 _defaultProbability(CC_MAX_NUM_SPREADS),
00041 _swapFees(CC_MAX_NUM_SPREADS),
00042 _recoveryRate(recoveryRate),
00043 _currency(currency),
00044 _frequency(frequency) {
00045
00046
00047 _underlying = new yieldCurve(yc);
00048 yieldCurve *spreadCurve = createSpreadCurve(*_underlying, cp);
00049 _combined = combineUnderlyingAndSpreads(*_underlying, *spreadCurve);
00050 resampleSpread();
00051
00052 delete spreadCurve;
00053 }
00054
00055 creditCurve::creditCurve(Real flatRate,
00056 Real flatSpread,
00057 char *name,
00058 Real recoveryRate,
00059 Currency currency,
00060 Frequency frequency) :
00061 _spreads(CC_MAX_NUM_SPREADS),
00062 _survivalProbability(CC_MAX_NUM_SPREADS),
00063 _defaultProbability(CC_MAX_NUM_SPREADS),
00064 _swapFees(CC_MAX_NUM_SPREADS),
00065 _recoveryRate(recoveryRate),
00066 _currency(currency),
00067 _frequency(frequency) {
00068
00069 _underlying = new yieldCurve(flatRate);
00070 yieldCurve *spreadCurve = new yieldCurve(flatSpread);
00071 _combined = combineUnderlyingAndSpreads(*_underlying, *spreadCurve);
00072 assignFlatSpread(flatSpread);
00073
00074 delete spreadCurve;
00075 }
00076
00077 creditCurve::creditCurve(yieldCurve &yc,
00078 Real flatSpread,
00079 char *name,
00080 Real recoveryRate,
00081 Currency currency,
00082 Frequency frequency) :
00083 _spreads(CC_MAX_NUM_SPREADS),
00084 _survivalProbability(CC_MAX_NUM_SPREADS),
00085 _defaultProbability(CC_MAX_NUM_SPREADS),
00086 _swapFees(CC_MAX_NUM_SPREADS),
00087 _recoveryRate(recoveryRate),
00088 _currency(currency),
00089 _frequency(frequency) {
00090
00091
00092 _underlying = new yieldCurve(yc);
00093 yieldCurve *spreadCurve = new yieldCurve(flatSpread);
00094 _combined = combineUnderlyingAndSpreads(*_underlying, *spreadCurve);
00095 assignFlatSpread(flatSpread);
00096
00097 delete spreadCurve;
00098 }
00099
00100 creditCurve::creditCurve(valarray<yieldPoint> &yp,
00101 valarray<CreditSpreadPoint> &cp,
00102 char *name,
00103 Real recoveryRate,
00104 Currency currency,
00105 Frequency frequency) :
00106 _spreads(CC_MAX_NUM_SPREADS),
00107 _survivalProbability(CC_MAX_NUM_SPREADS),
00108 _defaultProbability(CC_MAX_NUM_SPREADS),
00109 _swapFees(CC_MAX_NUM_SPREADS),
00110 _recoveryRate(recoveryRate),
00111 _currency(currency),
00112 _frequency(frequency) {
00113
00114 _underlying = new yieldCurve(yp, name);
00115 yieldCurve *spreadCurve =
00116 createSpreadCurve(*_underlying, cp);
00117 _combined =
00118 combineUnderlyingAndSpreads(*_underlying, *spreadCurve);
00119 resampleSpread();
00120
00121
00122
00123
00124
00125
00126 delete spreadCurve;
00127 }
00128
00129 creditCurve::creditCurve(const creditCurve &rhs) {
00130 copyObj(rhs);
00131 }
00132
00133 creditCurve &
00134 creditCurve::operator=(const creditCurve &rhs) {
00135 copyObj(rhs);
00136 return *this;
00137 }
00138
00139 void
00140 creditCurve::copyObj(const creditCurve &rhs) {
00141 _underlying = new yieldCurve(*(rhs.getUnderlying()));
00142 _combined = new yieldCurve(*(rhs.getCombined()));
00143 _spreads = rhs.getSpreads();
00144 _survivalProbability = rhs.getSurvivalProbability();
00145 _defaultProbability = rhs.getDefaultProbability();
00146 _swapFees = rhs.getSwapFees();
00147 _recoveryRate = rhs.getRecoveryRate();
00148 _frequency = rhs.getFrequency();
00149 _currency = rhs.getCurrency();
00150 }
00151
00152 yieldCurve *
00153 creditCurve::createSpreadCurve(yieldCurve &underlying,
00154 valarray<CreditSpreadPoint> &spreads) {
00155
00156
00157
00158 valarray<yieldPoint> _tempspreads(spreads.size());
00159 for (Natural i = 0; i < spreads.size(); i++) {
00160 if (spreads[i].getSpreadType() == Absolute) {
00161 _tempspreads[i].setRate(
00162 spreads[i].getRate() -
00163 underlying.spotRate(spreads[i].getMaturity())
00164 );
00165 } else {
00166 _tempspreads[i].setRate(spreads[i].getRate());
00167 }
00168 _tempspreads[i].setMaturity(spreads[i].getMaturity());
00169 _tempspreads[i].setType(Cash);
00170 }
00171
00172 yieldCurve *result = new yieldCurve(_tempspreads, "tempspreads");
00173
00174
00175
00176
00177 return result;
00178 }
00179
00180 yieldCurve *
00181 creditCurve::combineUnderlyingAndSpreads(yieldCurve &underlying,
00182 yieldCurve &spreadcurve) {
00183 Natural numTermValues = 0;
00184 valarray<Real> underlyingMaturities =
00185 underlying.getMaturitiesInTheZCBCurve();
00186
00187 valarray<Real> spreadMaturities =
00188 spreadcurve.getMaturitiesInTheZCBCurve();
00189
00190
00191
00192
00193
00194 valarray<Real> termValues =
00195 mergeunique(underlyingMaturities, spreadMaturities);
00196 numTermValues = termValues.size();
00197
00198
00199
00200
00201 valarray<yieldPoint> combinedyp(numTermValues);
00202 for (Natural i = 0; i < numTermValues; i++) {
00203 combinedyp[i].setRate(
00204 underlying.spotRate(termValues[i]) +
00205 spreadcurve.spotRate(termValues[i]));
00206 combinedyp[i].setMaturity(termValues[i]);
00207 combinedyp[i].setType(Cash);
00208 }
00209
00210 return new yieldCurve(combinedyp, "combined");
00211 }
00212
00213 void
00214 creditCurve::assignFlatSpread(Real r) {
00215 Natural size = _spreads.size();
00216 for(Natural i=0;i<size;i++){
00217 _spreads[i].setRate(r);
00218 _spreads[i].setMaturity(i);
00219 _spreads[i].setType(Relative);
00220
00221 _survivalProbability[i].isCached =
00222 _defaultProbability[i].isCached =
00223 _swapFees[i].isCached = false;
00224 }
00225 }
00226
00227 void
00228 creditCurve::resampleSpread() {
00229 Natural size = _spreads.size();
00230 for (Natural i = 0; i < size; i++) {
00231 _spreads[i].setRate(_combined->spotRate(i) -
00232 _underlying->spotRate(i));
00233 _spreads[i].setMaturity(i);
00234 _spreads[i].setType(Relative);
00235
00236 _survivalProbability[i].isCached =
00237 _defaultProbability[i].isCached =
00238 _swapFees[i].isCached = false;
00239 }
00240 }
00241
00242
00243 creditCurve::~creditCurve(void) {
00244 delete _underlying;
00245 delete _combined;
00246 }
00247
00248 Real
00249 creditCurve::timeOfCurrentSpread(Real maturity) const {
00250 return _spreads[indexOfCurrentSpread(maturity)].getMaturity();
00251 }
00252
00253 Natural
00254 creditCurve::indexOfCurrentSpread(Real maturity) const {
00255 Natural i = 0;
00256 Natural result = 0;
00257
00258
00259 while (i < _spreads.size() && _spreads[i].getMaturity() < maturity) {
00260 i++;
00261 }
00262
00263
00264
00265
00266 result = (i == _spreads.size() ? i - 1 : i);
00267
00268 return result;
00269 }
00270
00271 Natural
00272 creditCurve::indexOfPreviousSpread(Real maturity) const {
00273 Natural i = 0;
00274
00275 while (i < _spreads.size() && _spreads[i].getMaturity() < maturity) {
00276 i++;
00277 }
00278
00279 i = (i - 1 < 0 ? 0 : i - 1);
00280
00281 return i;
00282 }
00283
00284 Real
00285 creditCurve::timeOfPreviousSpread(Real maturity) const {
00286 return _spreads[indexOfPreviousSpread(maturity)].getMaturity();
00287 }
00288
00289 Real
00290 creditCurve::cumulativeDefaultProbability(Real maturity) const {
00291 return (1 - survivalProbability(maturity));
00292 }
00293
00294 Real
00295 creditCurve::survivalProbability(Real maturity) const {
00296 Real result = 0;
00297
00298 if (maturity == 0) {
00299
00300 result = 1;
00301 } else {
00302 Natural i = indexOfCurrentSpread(maturity);
00303
00304 if (!_survivalProbability[i].isCached) {
00305 Real T = timeOfCurrentSpread(maturity);
00306 Real Tminus = timeOfPreviousSpread(maturity);
00307 Real Sminus = survivalProbability(Tminus);
00308 Real qminus = defaultProbability(T);
00309
00310 _survivalProbability[i].value = Sminus * (1 - qminus);
00311 _survivalProbability[i].isCached = true;
00312 }
00313 result = _survivalProbability[i].value;
00314 }
00315
00316 return result;
00317 }
00318
00319 Real
00320 creditCurve::swapFees(Real maturity) const {
00321
00322 Real result = 0;
00323
00324 if (maturity == 0) {
00325 result = 0;
00326 } else {
00327 Natural i = indexOfCurrentSpread(maturity);
00328
00329
00330 if (!_swapFees[i].isCached) {
00331 Real T = timeOfCurrentSpread(maturity);
00332 Real Tminus = timeOfPreviousSpread(maturity);
00333 Real Fminus = swapFees(Tminus);
00334 Real Sminus = survivalProbability(Tminus);
00335 Real qminus = defaultProbability(T);
00336 Real DF = _underlying->discountFactor(T);
00337 Real CS = creditSpread(T);
00338 Real CSminus = creditSpread(Tminus);
00339
00340 _swapFees[i].isCached = true;
00341 _swapFees[i].value =
00342 Fminus * CS/CSminus + DF * CS * Sminus * (1 - qminus);
00343 }
00344 result = _swapFees[i].value;
00345 }
00346
00347 return result;
00348 }
00349
00356 Real
00357 creditCurve::defaultProbability(Real maturity) const {
00358
00359 Real result = 0;
00360
00361 if (maturity == 0) {
00362 result = 0;
00363 } else {
00364 Natural i = indexOfCurrentSpread(maturity);
00365
00366
00367 if (!_defaultProbability[i].isCached) {
00368 Real T = timeOfCurrentSpread(maturity);
00369 Real Tminus = timeOfPreviousSpread(maturity);
00370 Real Sminus = survivalProbability(Tminus);
00371 Real Fminus = swapFees(Tminus);
00372 Real DF = _underlying->discountFactor(T);
00373
00374 Real Tdefault = T - (T - Tminus)/2;
00375 Real DFd = _underlying->discountFactor(Tdefault);
00376 Real CS = creditSpread(T);
00377 Real CSminus = creditSpread(Tminus);
00378
00379
00380 Real num = Fminus * (CS/CSminus - 1) + DF * CS * Sminus;
00381 Real denom = Sminus * (DFd * (1 - _recoveryRate) + DF * CS);
00382
00383 _defaultProbability[i].isCached = true;
00384 _defaultProbability[i].value = num/denom;
00385 }
00386
00387 result = _defaultProbability[i].value;
00388 }
00389
00390 return result;
00391 }
00392
00393 Real
00394 creditCurve::riskyDiscountFactor(Real maturity,
00395 interestComposition composition) {
00416 Real DF = _underlying->discountFactor(maturity, composition);
00417 Real RDF = DF * survivalProbability(maturity);
00418
00419 return RDF;
00420 }
00421
00422 ostream&
00423 operator << (ostream &os, const creditCurve &c) {
00424 os << c._combined;
00425 return os;
00426 }