kspread

helper.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2007 Sascha Pfau <MrPeacock@gmail.com>
00003    Copyright (C) 1998-2002 The KSpread Team <koffice-devel@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; only
00008    version 2 of the License.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 // Local
00022 #include "helper.h"
00023 
00024 #include <kdebug.h>
00025 
00026 #include <QDate>
00027 
00028 #include <math.h>
00029 
00030 /*  DISABLED - we use KCalendarSystem instead
00031 void addMonths( QDate & date, int months )
00032 {
00033   int d = date.day();
00034   int m = date.month() + months;
00035   int y = date.year();
00036 
00037   if ( m > 12 )
00038   {
00039     y += (int) ( m / 12 );
00040     m %= 12;
00041   }
00042 
00043   // e.g. 31 Feb: decrease day...
00044   while ( !QDate::isValid( y, m, d ) && d > 0 )
00045     --d;
00046 
00047   date.setYMD( y, m, d );
00048 }
00049 
00050 void subMonths( QDate & date, int months )
00051 {
00052   int d = date.day();
00053   int m = date.month() - months;
00054   int y = date.year();
00055 
00056   while ( m < 1 )
00057   {
00058     m += 12;
00059     y -= 1;
00060   }
00061 
00062   // e.g. 31 Feb: decrease day
00063   while ( !QDate::isValid( y, m, d ) && d > 0 )
00064     --d;
00065 
00066   date.setYMD( y, m, d );
00067 }
00068 
00069 */
00070 
00071 int KSpread::daysPerYear(QDate const & date, int basis)
00072 {
00073   switch( basis )
00074   {
00075    case 0:
00076     return 360;
00077 
00078    case 1:
00079     if ( QDate::isLeapYear( date.year() ) )
00080       return 366;
00081     return 365;
00082 
00083    case 2:
00084     return 360;
00085    case 3:
00086     return 365;
00087    case 4:
00088     return 360;
00089   }
00090 
00091   return -1;
00092 }
00093 
00094 int KSpread::daysBetweenDates(QDate const & date1, QDate const & date2, int basis)
00095 {
00096   int day1, day2, month1, month2, year1, year2;
00097   bool isLeapYear = false;
00098   int days, months, years;
00099 
00100   day1   = date1.day();
00101   month1 = date1.month();
00102   year1  = date1.year();
00103   day2   = date2.day();
00104   month2 = date2.month();
00105   year2  = date2.year();
00106 
00107   years  = year2  - year1;
00108   months = month2 - month1 + years * 12;
00109   days   = day2   - day1;
00110 
00111   isLeapYear = QDate::isLeapYear( year1 );
00112 
00113   switch (basis)
00114   {
00115    case 0:
00116     if ( month1 == 2 && month2 != 2 && year1 == year2 )
00117     {
00118       if ( isLeapYear )
00119         return months * 30 + days - 1;
00120       else
00121         return months * 30 + days - 2;
00122     }
00123     return months * 30 + days;
00124 
00125    case 1: // TODO: real days for difference between months!
00126     //    return ( month2 - month1 ) * 30 + years * 360 + days;
00127 
00128    case 2: // TODO: real days for difference between months!
00129     //    return ( month2 - month1 ) * 30 + years * 365 + days;
00130 
00131    case 3:
00132     return date1.daysTo( date2 );
00133 
00134    case 4:
00135     return months * 30 + days;
00136   }
00137 
00138   return -1;
00139 }
00140 
00141 int KSpread::days360( int day1, int month1, int year1, bool leapYear1,
00142              int day2, int month2, int year2,
00143              bool usaMethod )
00144 {
00145   if ( day1 == 31 )
00146     day1--;
00147   else if ( usaMethod && ( month1 == 2 && ( day1 == 29 || ( day1 == 28 && ! leapYear1 ) ) ) )
00148     day1 = 30;
00149 
00150   if ( day2 == 31)
00151   {
00152     if ( usaMethod && day1 != 30 )
00153     {
00154        // date2 += 1
00155        day2 = 1;
00156        if ( month2 == 12 )
00157        {
00158          year2++;
00159          month2 = 1;
00160        }
00161        else
00162          month2++;
00163     }
00164     else
00165       day2 = 30;
00166   }
00167   return day2 + month2 * 30 + year2 * 360 - day1 - month1 * 30 - year1 * 360;
00168 }
00169 
00170 
00171 // days360
00172 int KSpread::days360( const QDate& _date1, const QDate& _date2, bool european )
00173 {
00174   int day1, month1, year1, day2, month2, year2;
00175   
00176   day1=_date1.day();
00177   month1=_date1.month();
00178   year1=_date1.year();
00179 
00180   day2=_date2.day();
00181   month2=_date2.month();
00182   year2=_date2.year();
00183  
00184   return days360(day1,month1,year1, QDate::isLeapYear(_date1.year()), day2,month2,year2, !european);
00185 }
00186 
00187 
00188 
00189 
00190 // // days360
00191 // int KSpread::days360( const QDate& _date1, const QDate& _date2, bool european )
00192 // {
00193 //   int day1, day2;
00194 //   int month1, month2;
00195 //   int year1, year2;
00196 //   bool negative = false;
00197 //   QDate date1( _date1 );
00198 //   QDate date2( _date2 );
00199 // 
00200 //   if (date1.daysTo( date2 ) < 0)
00201 //   {
00202 //     QDate tmp( date1 );
00203 //     date1 = date2;
00204 //     date2 = tmp;
00205 //     negative = true;
00206 //   }
00207 // 
00208 //   day1   = date1.day();
00209 //   day2   = date2.day();
00210 //   month1 = date1.month();
00211 //   month2 = date2.month();
00212 //   year1  = date1.year();
00213 //   year2  = date2.year();
00214 // 
00215 //   if ( european )
00216 //   {
00217 //     if ( day1 == 31 )
00218 //       day1 = 30;
00219 //     if ( day2 == 31 )
00220 //       day2 = 30;
00221 //   }
00222 //   else
00223 //   {
00224 //     // thanks to the Gnumeric developers for this...
00225 //     if ( month1 == 2 && month2 == 2
00226 //          && date1.daysInMonth() == day1
00227 //          && date2.daysInMonth() == day2 )
00228 //       day2 = 30;
00229 // 
00230 //     if ( month1 == 2 && date1.daysInMonth() == day1 )
00231 //       day1 = 30;
00232 // 
00233 //     if ( day2 == 31 && day1 >= 30 )
00234 //       day2 = 30;
00235 // 
00236 //     if ( day1 == 31 )
00237 //       day1 = 30;
00238 //   }
00239 // 
00240 //   return ( ( year2 - year1 ) * 12 + ( month2 - month1 ) ) * 30
00241 //     + ( day2 - day1 );
00242 // }
00243 
00244 // yearFrac
00245 long double KSpread::yearFrac( const QDate& refDate, const QDate& startDate, const QDate& endDate, int basis )
00246 {
00247   QDate date1 = startDate;
00248   QDate date2 = endDate;
00249 
00250   //
00251   // calculation
00252   //
00253 
00254   QDate date0=refDate; // referenceDate
00255 
00256   if ( date2 < date1 )
00257   {
00258     // exchange dates
00259     QDate Temp1=date1;
00260     date1=date2;
00261     date2=Temp1;
00262   }
00263 
00264   int days = date1.daysTo(date2);
00265 
00266 //   kDebug(36002) <<"date1 =" << date1 <<"    date2 =" << date2 <<"    days =" << days <<"    basis =" << basis;
00267 
00268   long double res=0;
00269   long double peryear=0;
00270   int nYears=0;
00271 
00272   switch(basis)
00273   {
00274     case 1:
00275     {
00276       nYears = date2.year() - date1.year() + 1;
00277       for (int y = date1.year(); y <= date2.year(); ++y) {
00278         peryear += QDate::isLeapYear(y) ? 366 : 365;
00279       }
00280       // less than one year - even if it does span two consequentive years ...
00281       if (QDate(date1.year()+1, date1.month(), date1.day()) >= date2) {
00282         nYears = 1;
00283         peryear = 365;
00284         if (QDate::isLeapYear(date1.year()) && (date1.month() <= 2)) peryear = 366;
00285         if (QDate::isLeapYear(date2.year()) && (date2.month() > 2)) peryear = 366;
00286       }
00287       peryear = peryear / (long double) nYears;
00288       nYears = 0;
00289       break;
00290 
00291     }
00292     case 2:
00293     {
00294       // Actual/360
00295       peryear = 360;
00296       break;
00297     }
00298     case 3:
00299     {
00300       // Actual/365
00301       peryear = 365;
00302       break;
00303     }
00304     case 4:
00305     {
00306       // 30/360 Europe
00307 
00308       // calc datedif360 (start, end, Europe)
00309       days = days360( date1, date2, 1);
00310 
00311       peryear = 360;
00312       break;
00313     }
00314     default:
00315     {
00316       // NASD 30/360
00317       //basis = 0;
00318 
00319       // calc datedif360 (start, end, US)
00320       days = days360( date1, date2, 0);
00321 
00322       peryear = 360;
00323     }
00324   }
00325 
00326   res = (long double)(nYears) + (long double)days / (long double) peryear;
00327 //   kDebug(36002)<<"getYearFrac res="<<res;
00328   return res;
00329 }
00330 
00331 // pow1p calculate (1+x)^y accurately
00332 long double KSpread::pow1p ( const long double& x, const long double& y)
00333 {
00334   if (fabs(x) > 0.5)
00335     return pow(1 + x, y);
00336   else
00337     return exp(y * log1p (x));
00338 }
00339 
00340 // pow1pm1 calculate ((1+x)^y)-1 accurately
00341 long double KSpread::pow1pm1 ( const long double& x, const long double& y)
00342 {
00343   if (x <= -1)
00344     return pow(1 + x, y) - 1;
00345   else
00346     return expm1(y * log1p (x));
00347 }
00348 
00349 long double KSpread::duration( const QDate& refDate, const QDate& settlement, const QDate& maturity, 
00350 const long double& coup_, const long double& yield_, const int& freq, const int& basis, const long double& numOfCoups)
00351 {
00352   long double yield = yield_;
00353   long double coup = coup_;
00354 
00355 //   kDebug(36002)<<"DURATION_HELPER";
00356 //   kDebug(36002)<<"sett ="<<settlement<<" mat ="<<maturity<<" coup ="<<coup<<" yield ="<<yield<<" freq ="<<freq<<" basis ="<<basis;
00357 
00358 
00359   long double yearfrac = yearFrac( refDate, settlement, maturity, basis);
00360   long double res = 0.0l;
00361   const long double f100 = 100.0l;
00362   coup *= f100 / (long double) ( freq );
00363   
00364   yield /= freq;
00365   yield += 1.0;
00366 
00367   long double diff = yearfrac * freq - numOfCoups;  
00368   
00369   long double t;
00370   
00371   for( t = 1.0l ; t < numOfCoups ; t += 1.0l )
00372     res += ( t + diff ) * ( coup ) / pow ( yield, t + diff );
00373 
00374   res += ( numOfCoups + diff ) * ( coup + f100 ) / pow( yield, numOfCoups + diff );
00375 
00376   long double p = 0.0l;
00377   for( t = 1.0l ; t < numOfCoups ; t += 1.0l )
00378     p += coup / pow( yield, t + diff );
00379 
00380   p += ( coup + f100 ) / pow( yield, numOfCoups + diff );
00381 
00382   res /= p;
00383   res /= (long double)( freq );
00384 
00385   return( res );
00386 }