00001 #include ".\yieldCurve.h"
00002
00003
00004
00005
00006
00007 yieldPoint::yieldPoint(void) {
00008 _rate = 0.0;
00009 _maturity = 0.0;
00010 _type = Cash;
00011 _dayCount = ACT_360;
00012 }
00013
00014 yieldPoint::yieldPoint(Real r,Real T,TypeOfRate type,DayCountConvention dayCount)
00015 {
00016 _rate = r;
00017 _maturity = T;
00018 _type = type;
00019 _dayCount = dayCount;
00020 }
00021
00022
00023 char *yieldPoint::TypeAsString(TypeOfRate t)
00024 {
00025 switch (t) {
00026 case Cash:
00027 return "Cash";
00028 case Swap:
00029 return "Swap";
00030 default:
00031 return "No rate type has been defined";
00032 }
00033 }
00034
00035 yieldPoint::~yieldPoint(void)
00036 {
00037 };
00038
00039
00040
00041
00042 yieldCurve::yieldCurve(void)
00043 :_marketRates(YC_MAX_NUMBER_POINTS),
00044 _zcbRates(YC_MAX_NUMBER_POINTS)
00045 {
00046 sprintf(_name, "unamed");
00048 assignFlatRate();
00049 computeZCBRatesBootstrap();
00050 }
00051
00052
00053 void yieldCurve::assignFlatRate(Real r)
00054 {
00055 Natural size = _marketRates.size();
00056 for(Natural i=0;i<size;i++){
00057 _marketRates[i].setRate(r);
00058 _marketRates[i].setDayCount(ACT_360);
00059 _marketRates[i].setType(Cash);
00060 _marketRates[i].setMaturity(i);
00061 }
00062 }
00063
00064 yieldCurve::yieldCurve(Real flatRate)
00065 :_marketRates(YC_MAX_NUMBER_POINTS),
00066 _zcbRates(YC_MAX_NUMBER_POINTS)
00067 {
00068 sprintf(_name, "unamed");
00070 assignFlatRate(flatRate);
00071 computeZCBRatesBootstrap();
00072 }
00073
00074 yieldCurve::yieldCurve(valarray<yieldPoint> yieldPoints,char *name)
00075 :_marketRates(yieldPoints),
00076 _zcbRates(yieldPoints)
00077 {
00078 strcpy(_name,name);
00079 sortMarketRatesByMaturity();
00080 sortCashSwap();
00082 computeZCBRatesBootstrap();
00083 }
00084
00085 yieldCurve::~yieldCurve(void)
00086 {
00087 }
00088
00089 yieldPoint yieldCurve::getPointAtMaturity(Real maturity)
00090 {
00091 Natural size =_marketRates.size(),i=0,indexFound=0;
00092 yieldPoint y;
00093 bool hasFound=false;
00094
00095 while (i<size && !hasFound){
00096 if(_marketRates[i].getMaturity()==maturity){
00097 hasFound=true;
00098 indexFound =i;
00099 }
00100 i++;
00101 }
00102 if(hasFound){
00103 y=_marketRates[indexFound];
00104 }
00105 else{
00106 y=yieldPoint();
00107 }
00108 return y;
00109 }
00110
00111
00112 void yieldCurve::sortMarketRatesByMaturity()
00113 {
00114 Natural size = _marketRates.size();
00115 valarray<yieldPoint> tempstorage(size);
00116 Real toSort[YC_MAX_NUMBER_POINTS];
00117 for (Natural i=0;i<size;i++)
00118 {
00119 toSort[i]=_marketRates[i].getMaturity();
00120 }
00121 sort(toSort,toSort+size);
00122
00123 for (i=0;i<size;i++)
00124 {
00125 tempstorage[i]=getPointAtMaturity(toSort[i]);
00126
00127
00128
00129 }
00130 _marketRates = tempstorage;
00131 }
00132
00133
00134 void yieldCurve::sortCashSwap()
00135 {
00136 valarray<yieldPoint> tempstorage(_marketRates.size());
00137 Natural count=0;
00138 for (Natural i=0;i<_marketRates.size();i++)
00139 {
00140 if(_marketRates[i].getType()==Cash){
00141 tempstorage[count]=_marketRates[i];
00142 count++;
00143 }
00144 }
00145 for (Natural i=0;i<_marketRates.size();i++)
00146 {
00147 if(_marketRates[i].getType()==Swap){
00148 tempstorage[count]=_marketRates[i];
00149 count++;
00150 }
00151 }
00152 _marketRates=tempstorage;
00153 }
00154
00155 valarray<yieldPoint> yieldCurve::getSwapRates()
00156 {
00157 valarray<yieldPoint> tempstorage(YC_MAX_NUMBER_POINTS);
00158 tempstorage[0]=yieldPoint(spotRate(1),1,Swap);
00159 Natural i=0,count=1;
00160 while(i<_marketRates.size() && _marketRates[i].getType()==Cash) {i++;}
00161 while(i<_marketRates.size())
00162 {
00163 tempstorage[count]=_marketRates[i];
00164 count++;
00165 i++;
00166 }
00167
00168 tempstorage.resize(count);
00169 return tempstorage;
00170 }
00171
00172 valarray<yieldPoint> yieldCurve::getSequentSwapRates()
00173 {
00175 valarray<yieldPoint> tempstorage(getSwapRates());
00176 Natural size=tempstorage.size();
00177 valarray<yieldPoint> res((Natural)tempstorage[size-1].getMaturity());
00178 Natural i=1,diff=0,j=0,nextMat=0,prevMat=0,start=0;
00181 while(i<size && tempstorage[i-1].getMaturity()==(tempstorage[i].getMaturity()-1)) {
00182 res[j]=tempstorage[i-1];
00183 i++;
00184 j++;
00185 }
00186 start=j;
00187
00188
00189 while (j<res.size() && i<size){
00190 if(tempstorage[i].getMaturity()==(Real)(j+1)){
00191 res[j]=tempstorage[i];
00192 i++;
00193 }
00194 else{
00195 res[j].setMaturity((Real)(j+1));
00196 res[j].setType(Swap);
00197 nextMat=(Natural)tempstorage[i].getMaturity();
00198 prevMat=(Natural)tempstorage[i-1].getMaturity();
00199 diff= nextMat-prevMat;
00200 res[j].setRate( (tempstorage[i-1].getRate()*(nextMat-j-1)+ tempstorage[i].getRate()*(j+1-prevMat )) /diff);
00201 }
00202 j++;
00203 }
00204 return res;
00205 }
00206
00207 Real yieldCurve::spotRate(Real maturity) const
00208 {
00209 Natural i =0;
00210 while(i<_zcbRates.size() && _zcbRates[i].getMaturity()<maturity ) {i++;}
00211 if (i==_zcbRates.size())
00212
00213 return _zcbRates[i-1].getRate();
00214 else if(i==0)
00215
00216 return _zcbRates[i].getRate();
00217 else{
00218
00219 Real rmin=_zcbRates[i-1].getRate();
00220 Real rmax=_zcbRates[i].getRate();
00221 Real tmin=_zcbRates[i-1].getMaturity();
00222 Real tmax=_zcbRates[i].getMaturity();
00223
00224
00225 return ( (tmax-maturity)*rmin + (maturity-tmin)*rmax )/(tmax-tmin);
00226 }
00227 }
00228
00229 Real yieldCurve::spotRate(Date maturityDate) const {
00230 Date today=Date();
00231 today.setDateToToday();
00232 return spotRate(today.dayCount(maturityDate,Day30_360));
00233 }
00234
00235 Real yieldCurve::discountFactor(Real maturity,interestComposition composition)
00236 {
00237 switch (composition) {
00238 case Discrete:
00239 return (Real)pow(1/(1+spotRate(maturity)),maturity);
00240 case Continuous:
00241 return (Real)exp(-maturity*spotRate(maturity));
00242 default:
00243 return (Real)exp(-maturity*spotRate(maturity));
00244 }
00245 }
00246
00247 Real yieldCurve::discountFactor(Date maturityDate,interestComposition composition){
00248 Date today=Date();
00249 today.setDateToToday();
00250 return discountFactor(today.dayCount(maturityDate,Day30_360),composition);
00251 }
00252
00253 Real yieldCurve::forwardDiscountFactor(Real forwardstart,Real lengthofcontractafterstart,interestComposition composition){
00254 switch (composition) {
00255 case Discrete:
00256 return (Real)pow(1/(1+forwardRate(forwardstart,lengthofcontractafterstart,composition)),lengthofcontractafterstart);
00257 case Continuous:
00258 return (Real)exp(-lengthofcontractafterstart*forwardRate(forwardstart,lengthofcontractafterstart,composition));
00259 default:
00260 return (Real)exp(-lengthofcontractafterstart*forwardRate(forwardstart,lengthofcontractafterstart,composition));
00261 }
00262 }
00263
00264 Real yieldCurve::forwardRate(Real forwardStart,Real effectiveLengthOfTheContractAfterStart,interestComposition composition)
00265 {
00266 switch (composition) {
00267 case Discrete:
00268 return (Real)(pow(discountFactor(forwardStart,composition)/discountFactor(forwardStart+effectiveLengthOfTheContractAfterStart,composition),1/effectiveLengthOfTheContractAfterStart)-1) ;
00269 case Continuous:
00270 return (Real) (spotRate(forwardStart+effectiveLengthOfTheContractAfterStart)*(forwardStart+effectiveLengthOfTheContractAfterStart)
00271 -spotRate(forwardStart)*forwardStart)/effectiveLengthOfTheContractAfterStart;
00272 default:
00273 return (Real) (spotRate(forwardStart+effectiveLengthOfTheContractAfterStart)*(forwardStart+effectiveLengthOfTheContractAfterStart)
00274 -spotRate(forwardStart)*forwardStart)/effectiveLengthOfTheContractAfterStart;
00275 }
00276
00277 }
00278
00279 yieldCurve yieldCurve::forwardZCBCurve(Real forwardStart){
00280 valarray<yieldPoint> fwdPts(_zcbRates);
00281 Natural i=0,size=fwdPts.size(),start;
00282 while(i<size && forwardStart>=_zcbRates[i].getRate())
00283 i++;
00284 if(i==size)
00285 return yieldCurve();
00286 else{
00287 start=i;
00288 fwdPts.resize(size-start);
00289 for (Natural i=start;i<fwdPts.size();i++){
00290 fwdPts[i-start].setRate(forwardRate(forwardStart,_zcbRates[i].getMaturity()-forwardStart));
00291 fwdPts[i-start].setMaturity(_zcbRates[i].getMaturity()-forwardStart);
00292 }
00293 return yieldCurve(fwdPts,"forwardCurve");
00294 }
00295
00296 }
00297
00298 Real yieldCurve::forwardRate(Date forwardStart,Date forwardEnd,interestComposition composition){
00299 Date today=Date();
00300 today.setDateToToday();
00301 return forwardRate(today.dayCount(forwardStart,Day30_360),forwardStart.dayCount(forwardEnd,Day30_360),composition);
00302 }
00303
00304
00305 valarray<Real> yieldCurve::SequentDiscountFactorsByInvertSwapMatrix()
00306 {
00307 valarray<yieldPoint> tempstorage(getSequentSwapRates());
00308
00309 Natural size = tempstorage.size();
00310 Matrix *M= new Matrix (0.0,size,size);
00311 for (Natural i=0; i < size; i++)
00312 {
00313 for (Natural j=0; j<size; j++)
00314 {
00315 if(i==j)
00316 M->SetValue(i,j,1+tempstorage[i].getRate());
00317 else if (i>j)
00318 M->SetValue(i,j,tempstorage[i].getRate());
00319 else
00320 M->SetValue(i,j,0);
00321 }
00322 }
00323 M->Invert();
00324 valarray<Real> res(size);
00325 for(i=0;i<size;i++){
00326 res[i]=M->SumRow (i);
00327 }
00328 delete M;
00329
00330 return res;
00331 }
00332
00333 valarray<Real> yieldCurve::getMaturitiesInTheMarketCurve() const
00334 {
00335 Natural size=_marketRates.size();
00336 valarray<Real> maturities(size);
00337 for (Natural i=0;i<size;i++){
00338 maturities[i]=_marketRates[i].getMaturity();
00339 }
00340 return maturities;
00341 }
00342
00343 valarray<Real> yieldCurve::getMaturitiesInTheZCBCurve() const
00344 {
00345 Natural size= _zcbRates.size();
00346 valarray<Real> maturities(size);
00347 for (Natural i=0;i<size;i++){
00348 maturities[i]=_zcbRates[i].getMaturity();
00349 }
00350 return maturities;
00351 }
00352
00353
00354 void yieldCurve::computeZCBRatesBootstrap()
00355 {
00356 _zcbRates=_marketRates;
00357
00358 if(_marketRates[_marketRates.size()-1].getType()!=Cash){
00359
00360 valarray<Real> DFs(SequentDiscountFactorsByInvertSwapMatrix());
00361 Natural start=0,size = DFs.size();
00362
00363 while (_zcbRates[start].getType()==Cash) {start ++;}
00364 start --;
00365 _zcbRates.resize(size+start);
00366 for (Natural i=0;i<size;i++){
00367
00368
00369
00370 _zcbRates[start+i].setRate((Real)pow(1/DFs[i],1/((Real)(i+1)))-1);
00371 _zcbRates[start+i].setMaturity((Real)i+1);
00372 _zcbRates[start+i].setType(Cash);
00373 }
00374 }
00375 }
00376
00377 void yieldCurve::assignZCBrateAtIndex(Real rate,Natural i){
00378 if (i<_zcbRates.size())
00379 _zcbRates[i].setRate(rate);
00380 }
00381
00382 yieldCurve yieldCurve::shiftZCBRateCurve(Real shift)
00383 {
00384 char * name=new char[50];
00385 sprintf (name,"%f",shift);
00386 strcat (name," shift on the current ZCB curve");
00387
00388 yieldCurve resultShifted=yieldCurve(_zcbRates,name);
00389 for (Natural i=0;i<_zcbRates.size();i++)
00390 resultShifted.assignZCBrateAtIndex(_zcbRates[i].getRate()+shift,i);
00391 return resultShifted;
00392 }
00393
00399 yieldCurve yieldCurve::rotateZCBRateCurve(Real moveInShortestRate,Real maturityOfRotation){
00400 char * name=new char[64];
00401 sprintf (name,"%f",moveInShortestRate);
00402 strcat (name," move on short rate and rotation around 7Y");
00403
00404 yieldCurve resultRotated=yieldCurve(_zcbRates,name);
00405 Real move=0.;
00406 Real difmat=_zcbRates[0].getMaturity()-min(2*maturityOfRotation,_zcbRates[_zcbRates.size()-1].getMaturity());
00407 Real summat=_zcbRates[0].getMaturity()+min(2*maturityOfRotation,_zcbRates[_zcbRates.size()-1].getMaturity());
00408 for (Natural i=0;i<_zcbRates.size();i++){
00409 move= (moveInShortestRate/difmat)*(2*_zcbRates[i].getMaturity()-summat);
00410 resultRotated.assignZCBrateAtIndex(_zcbRates[i].getRate()+move,i);
00411 }
00412 return resultRotated;
00413 }
00414
00422 bool
00423 yieldCurve::operator==(const yieldCurve& yours) {
00424 bool result = true;
00425
00426 valarray<Real> myMaturities =
00427 getMaturitiesInTheZCBCurve();
00428 valarray<Real> yourMaturities =
00429 yours.getMaturitiesInTheZCBCurve();
00430 valarray<Real> termValues =
00431 mergeunique(myMaturities, yourMaturities);
00432 Natural numTermValues = termValues.size();
00433
00434 Real m = 0;
00435 Real y = 0;
00436 for (Natural i = 0; (i < numTermValues) && result; i++) {
00437 m = spotRate(termValues[i]);
00438 y = yours.spotRate(termValues[i]);
00439
00440
00441
00442 if (fabs(m - y) > 0.00001) {
00443 cout << "mismatch m: " << m << " y: " << y << endl;
00444 result &= false;
00445 }
00446 }
00447
00448 return result;
00449 }
00450
00451 bool
00452 yieldCurve::operator!=(const yieldCurve& yours) {
00453 return !operator==(yours);
00454 }
00455
00456 ostream&
00457 operator << (ostream &os, const yieldCurve &c) {
00458 valarray<Real> myMaturities =
00459 c.getMaturitiesInTheZCBCurve();
00460 Natural numTermValues = myMaturities.size();
00461
00462 for (Natural i = 0; i < numTermValues; i++) {
00463 os << myMaturities[i] << "," << c.spotRate(myMaturities[i]) << endl;
00464 }
00465
00466 return os;
00467 }
00468
00469