Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

creditCurve.cpp

Go to the documentation of this file.
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         // make a local copy of the underlying yieldcurve - its ours now!
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         // make a local copy of the underlying yieldcurve - its ours now!
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         // cout << _underlying->getName() << ": " << _underlying << endl;
00122         // cout << spreadCurve->getName() << ": " << spreadCurve << endl;
00123         // cout << _combined->getName() << ": " << _combined << endl;
00124         // cout << "end." << endl;
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         // convert all credit spreads to relative, and use this to create a
00156         //  temporary yieldcurve object (so we can use the interpolation
00157         //  functionality)
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         // cout << result->getName() << ": " << result << endl;
00175         // cout << "end." << endl;
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         // create a curve combining the underlying points and the credit spreads
00191 
00192         // 1. first get a merged unique list of maturities from the yieldcurve and
00193         //  the spreads
00194         valarray<Real> termValues = 
00195                 mergeunique(underlyingMaturities, spreadMaturities);
00196         numTermValues = termValues.size();
00197 
00198         // 2. then iterate through all known term values adding the spotrate 
00199         //  of the underlying to the credit spread "spotrate" to create
00200         //  the combined yieldcurve
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         // linear search through the array...  performance optimization
00259         while (i < _spreads.size() &&  _spreads[i].getMaturity() < maturity) {
00260                 i++;
00261         }
00262 
00263         // if index is past the end of _spreads, take last point, 
00264         //  otherwise take the point we have (first point equal to or 
00265         //  after specified maturity)
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         // now go back one index
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         // cout << "survivalProbability(" << maturity << ")" << endl;
00298         if (maturity == 0) {
00299                 // no time has passed so survivalProbability is 100%
00300                 result = 1;
00301         } else {
00302                 Natural i = indexOfCurrentSpread(maturity);
00303                 // if this value is not cached, calculate and cache it
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         // cout << "swapFees(" << maturity << ")" << endl;
00322         Real result = 0;
00323 
00324         if (maturity == 0) {
00325                 result = 0;
00326         } else {
00327                 Natural i = indexOfCurrentSpread(maturity);
00328 
00329                 // if this value is not cached, calculate and cache it
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         // cout << "defaultProbability(" << maturity << ")" << endl;
00359         Real result = 0;
00360 
00361         if (maturity == 0) {
00362                 result = 0;
00363         } else {
00364                 Natural i = indexOfCurrentSpread(maturity);
00365 
00366                 // if this value is not cached, calculate and cache it
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                         // cout << "DFd: " << DFd << endl;
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 }

Note: Generated nightly - reload for latest version
Generated on Thu Dec 22 23:12:35 2005 for terreneuve by doxygen 1.3.6