~ubuntu-branches/ubuntu/edgy/koffice/edgy-updates

« back to all changes in this revision

Viewing changes to kspread/kspread_functions_financial.cc

  • Committer: Bazaar Package Importer
  • Author(s): Ben Burton
  • Date: 2004-05-09 11:33:00 UTC
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040509113300-xi5t1z4yxe7n03x7
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 1998-2002 The KSpread Team
 
3
                           www.koffice.org/kspread
 
4
 
 
5
   This library is free software; you can redistribute it and/or
 
6
   modify it under the terms of the GNU Library General Public
 
7
   License as published by the Free Software Foundation; either
 
8
   version 2 of the License.
 
9
 
 
10
   This library is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
   Library General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU Library General Public License
 
16
   along with this library; see the file COPYING.LIB.  If not, write to
 
17
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
   Boston, MA 02111-1307, USA.
 
19
*/
 
20
 
 
21
// built-in financial functions
 
22
 
 
23
#include <stdlib.h>
 
24
#include <math.h>
 
25
#include <float.h>
 
26
 
 
27
#include <kdebug.h>
 
28
 
 
29
#include <koscript_parser.h>
 
30
#include <koscript_util.h>
 
31
#include <koscript_func.h>
 
32
#include <koscript_synext.h>
 
33
 
 
34
#include <kspread_functions.h>
 
35
#include <kspread_functions_helper.h>
 
36
#include <kspread_util.h>
 
37
 
 
38
 
 
39
// prototypes (sorted)
 
40
bool kspreadfunc_accrint( KSContext& context );
 
41
bool kspreadfunc_accrintm( KSContext& context );
 
42
bool kspreadfunc_compound( KSContext& context );
 
43
bool kspreadfunc_continuous( KSContext& context );
 
44
bool kspreadfunc_coupnum( KSContext& context );
 
45
bool kspreadfunc_db( KSContext& context );
 
46
bool kspreadfunc_ddb( KSContext& context );
 
47
bool kspreadfunc_disc( KSContext& context );
 
48
bool kspreadfunc_dollarde( KSContext& context );
 
49
bool kspreadfunc_dollarfr( KSContext& context );
 
50
bool kspreadfunc_duration( KSContext& context );
 
51
bool kspreadfunc_effective( KSContext& context );
 
52
bool kspreadfunc_euro( KSContext& context );
 
53
bool kspreadfunc_fv( KSContext& context );
 
54
bool kspreadfunc_fv_annuity( KSContext& context );
 
55
bool kspreadfunc_intrate( KSContext& context );
 
56
bool kspreadfunc_ipmt( KSContext& context );
 
57
bool kspreadfunc_ispmt( KSContext& context );
 
58
bool kspreadfunc_level_coupon( KSContext& context );
 
59
bool kspreadfunc_nominal( KSContext& context );
 
60
bool kspreadfunc_nper( KSContext& context );
 
61
bool kspreadfunc_pmt( KSContext& context );
 
62
bool kspreadfunc_ppmt( KSContext& context );
 
63
bool kspreadfunc_pv( KSContext& context );
 
64
bool kspreadfunc_pv_annuity( KSContext& context );
 
65
bool kspreadfunc_received( KSContext& context );
 
66
bool kspreadfunc_sln( KSContext& context );
 
67
bool kspreadfunc_syd( KSContext& context );
 
68
bool kspreadfunc_tbilleq( KSContext& context );
 
69
bool kspreadfunc_tbillprice( KSContext& context );
 
70
bool kspreadfunc_tbillyield( KSContext& context );
 
71
bool kspreadfunc_zero_coupon( KSContext& context );
 
72
 
 
73
// registers all financial functions
 
74
void KSpreadRegisterFinancialFunctions()
 
75
{
 
76
  KSpreadFunctionRepository* repo = KSpreadFunctionRepository::self();
 
77
 
 
78
  repo->registerFunction( "ACCRINT", kspreadfunc_accrint );
 
79
  repo->registerFunction( "ACCRINTM", kspreadfunc_accrintm );
 
80
  repo->registerFunction( "COMPOUND", kspreadfunc_compound );
 
81
  repo->registerFunction( "CONTINUOUS", kspreadfunc_continuous );
 
82
  repo->registerFunction( "COUPNUM", kspreadfunc_coupnum );
 
83
  repo->registerFunction( "DB", kspreadfunc_db );
 
84
  repo->registerFunction( "DDB", kspreadfunc_ddb );
 
85
  repo->registerFunction( "DISC", kspreadfunc_disc );
 
86
  repo->registerFunction( "DOLLARDE", kspreadfunc_dollarde );
 
87
  repo->registerFunction( "DOLLARFR", kspreadfunc_dollarfr );
 
88
  repo->registerFunction( "DURATION", kspreadfunc_duration );
 
89
  repo->registerFunction( "EFFECT", kspreadfunc_effective );
 
90
  repo->registerFunction( "EFFECTIVE", kspreadfunc_effective );
 
91
  repo->registerFunction( "EURO", kspreadfunc_euro );  // KSpread-specific, Gnumeric-compatible
 
92
  repo->registerFunction( "FV", kspreadfunc_fv );
 
93
  repo->registerFunction( "FV_ANNUITY", kspreadfunc_fv_annuity );
 
94
  repo->registerFunction( "INTRATE", kspreadfunc_intrate );
 
95
  repo->registerFunction( "IPMT", kspreadfunc_ipmt );
 
96
  repo->registerFunction( "ISPMT", kspreadfunc_ispmt );
 
97
  repo->registerFunction( "LEVEL_COUPON", kspreadfunc_level_coupon );
 
98
  repo->registerFunction( "NOMINAL", kspreadfunc_nominal );
 
99
  repo->registerFunction( "NPER", kspreadfunc_nper );
 
100
  repo->registerFunction( "PMT", kspreadfunc_pmt );
 
101
  repo->registerFunction( "PPMT", kspreadfunc_ppmt );
 
102
  repo->registerFunction( "PV", kspreadfunc_pv );
 
103
  repo->registerFunction( "PV_ANNUITY", kspreadfunc_pv_annuity );
 
104
  repo->registerFunction( "RECEIVED", kspreadfunc_received );
 
105
  repo->registerFunction( "SLN", kspreadfunc_sln );
 
106
  repo->registerFunction( "SYD", kspreadfunc_syd );
 
107
  repo->registerFunction( "TBILLEQ", kspreadfunc_tbilleq );
 
108
  repo->registerFunction( "TBILLPRICE", kspreadfunc_tbillprice );
 
109
  repo->registerFunction( "TBILLYIELD", kspreadfunc_tbillyield );
 
110
  repo->registerFunction( "ZERO_COUPON", kspreadfunc_zero_coupon );
 
111
}
 
112
 
 
113
static double getPay( double rate, double nper, double pv, double fv, int type )
 
114
{
 
115
  double pvif, fvifa;
 
116
 
 
117
  pvif  = ( pow( 1 + rate, nper ) );
 
118
  fvifa = ( pow( 1 + rate, nper ) - 1 ) / rate;
 
119
 
 
120
  return ( ( -pv * pvif - fv ) / ( ( 1.0 + rate * type ) * fvifa ) );
 
121
}
 
122
 
 
123
static double getPrinc( double start, double pay,
 
124
                        double rate, double period )
 
125
{
 
126
  return ( start * pow( 1.0 + rate, period) + pay
 
127
           * ( ( pow( 1 + rate, period ) - 1 ) / rate ) );
 
128
}
 
129
 
 
130
static bool getCoupParameter( KSContext & context, QString const & fName, QDate & settlement,
 
131
                              QDate & maturity, int & frequency, int & basis, bool & eom )
 
132
{
 
133
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
134
 
 
135
  if ( !KSUtil::checkArgumentsCount( context, 5, fName, true ) )
 
136
  {
 
137
    if ( !KSUtil::checkArgumentsCount( context, 4, fName, true ) )
 
138
    {
 
139
      if ( !KSUtil::checkArgumentsCount( context, 3, fName, true ) )
 
140
        return false;
 
141
    }
 
142
    else
 
143
    {
 
144
      if ( !KSUtil::checkType( context, args[3], KSValue::IntType, true ) )
 
145
        return false;
 
146
      basis = args[3]->intValue();
 
147
    }
 
148
  }
 
149
  else
 
150
  {
 
151
    if ( !KSUtil::checkType( context, args[3], KSValue::IntType, true ) )
 
152
      return false;
 
153
    if ( !KSUtil::checkType( context, args[4], KSValue::BoolType, true ) )
 
154
      return false;
 
155
 
 
156
    basis = args[3]->intValue();
 
157
    eom   = args[4]->boolValue();
 
158
  }
 
159
 
 
160
  if ( !getDate( context, args[0], settlement ) )
 
161
    return false;
 
162
 
 
163
  if ( !getDate( context, args[1], maturity ) )
 
164
    return false;
 
165
 
 
166
  if ( !KSUtil::checkType( context, args[2], KSValue::IntType, true ) )
 
167
    return false;
 
168
 
 
169
  frequency = args[2]->intValue();
 
170
 
 
171
  if (basis < 0 || basis > 5 || ( frequency == 0 ) || ( 12 % frequency != 0 )
 
172
      || settlement.daysTo( maturity ) <= 0)
 
173
    return false;
 
174
 
 
175
  return true;
 
176
}
 
177
 
 
178
// Function: COUPNUM - taken from GNUMERIC
 
179
bool kspreadfunc_coupnum( KSContext & context )
 
180
{
 
181
  QDate settlement;
 
182
  QDate maturity;
 
183
  int   frequency;
 
184
  int   basis = 0;
 
185
  bool  eom   = true;
 
186
 
 
187
  if ( !getCoupParameter( context, "COUPNUM", settlement, maturity,
 
188
                          frequency, basis, eom ) )
 
189
    return false;
 
190
 
 
191
  double result;
 
192
  QDate cDate( maturity );
 
193
 
 
194
  int months = maturity.month() - settlement.month()
 
195
    + 12 * ( maturity.year() - settlement.year() );
 
196
 
 
197
  subMonths( cDate, months );
 
198
 
 
199
  if ( eom && maturity.daysInMonth() == maturity.day() )
 
200
  {
 
201
    while( cDate.daysInMonth() != cDate.day() )
 
202
      cDate.addDays( 1 );
 
203
  }
 
204
 
 
205
  if ( settlement.day() >= cDate.day() )
 
206
    --months;
 
207
 
 
208
  result = ( 1 + months / ( 12 / frequency ) );
 
209
 
 
210
  context.setValue( new KSValue( result ) );
 
211
  return true;
 
212
}
 
213
 
 
214
// Function: ACCRINT
 
215
bool kspreadfunc_accrint( KSContext& context )
 
216
{
 
217
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
218
 
 
219
  int basis = 0;
 
220
 
 
221
  if ( !KSUtil::checkArgumentsCount( context, 7, "ACCRINT", true ) )
 
222
  {
 
223
    if ( !KSUtil::checkArgumentsCount( context, 6, "ACCRINT", true ) )
 
224
      return false;
 
225
  }
 
226
  else
 
227
  {
 
228
    if ( !KSUtil::checkType( context, args[6], KSValue::IntType, true ) )
 
229
      return false;
 
230
 
 
231
    basis = args[6]->intValue();
 
232
  }
 
233
 
 
234
  QDate maturity;
 
235
  QDate firstInterest;
 
236
  QDate settlement;
 
237
  double rate, par;
 
238
  double frequency;
 
239
 
 
240
  if ( !getDate( context, args[0], maturity ) )
 
241
    return false;
 
242
 
 
243
  if ( !getDate( context, args[1], firstInterest ) )
 
244
    return false;
 
245
 
 
246
  if ( !getDate( context, args[2], settlement ) )
 
247
    return false;
 
248
 
 
249
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
250
    return false;
 
251
 
 
252
  if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
253
    return false;
 
254
 
 
255
  if ( !KSUtil::checkType( context, args[5], KSValue::DoubleType, true ) )
 
256
    return false;
 
257
 
 
258
  rate      = args[3]->doubleValue();
 
259
  par       = args[4]->doubleValue();
 
260
  frequency = (int) args[5]->doubleValue();
 
261
 
 
262
  if ( basis < 0 || basis > 4 || ( frequency == 0 ) || ( 12 % (int) frequency != 0 ) )
 
263
    return false;
 
264
 
 
265
  if ( ( settlement.daysTo( firstInterest ) < 0 )
 
266
       || ( firstInterest.daysTo( maturity ) > 0 ) )
 
267
    return false;
 
268
 
 
269
  double d = daysBetweenDates( maturity, settlement, basis );
 
270
  double y = daysPerYear( maturity, basis );
 
271
 
 
272
  if ( d < 0 || y <= 0 || par <= 0 || rate <= 0 )
 
273
    return false;
 
274
 
 
275
  double coeff = par * rate / frequency;
 
276
  double n = d / y;
 
277
 
 
278
  context.setValue( new KSValue( coeff * frequency * n ) );
 
279
  return true;
 
280
}
 
281
 
 
282
// Function: ACCRINTM
 
283
bool kspreadfunc_accrintm( KSContext& context )
 
284
{
 
285
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
286
 
 
287
  int basis  = 0;
 
288
  double par = 1000;
 
289
 
 
290
  if ( !KSUtil::checkArgumentsCount( context, 5, "ACCRINTM", true ) )
 
291
  {
 
292
    if ( !KSUtil::checkArgumentsCount( context, 4, "ACCRINTM", true ) )
 
293
    {
 
294
      if ( !KSUtil::checkArgumentsCount( context, 3, "ACCRINTM", true ) )
 
295
        return false;
 
296
    }
 
297
    else
 
298
    {
 
299
      if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
300
        return false;
 
301
 
 
302
      par   = args[3]->doubleValue();
 
303
    }
 
304
  }
 
305
  else
 
306
  {
 
307
    if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
308
      return false;
 
309
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
310
      return false;
 
311
 
 
312
    par   = args[3]->doubleValue();
 
313
    basis = args[4]->intValue();
 
314
  }
 
315
 
 
316
  QDate issue;
 
317
  QDate maturity;
 
318
  double rate;
 
319
 
 
320
  if ( !getDate( context, args[0], issue ) )
 
321
    return false;
 
322
 
 
323
  if ( !getDate( context, args[1], maturity ) )
 
324
    return false;
 
325
 
 
326
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
327
    return false;
 
328
 
 
329
  rate = args[2]->doubleValue();
 
330
 
 
331
  double d = daysBetweenDates( issue, maturity, basis );
 
332
  double y = daysPerYear( issue, basis );
 
333
 
 
334
  if ( d < 0 || y <= 0 || par <= 0 || rate <= 0 || basis < 0 || basis > 4 )
 
335
    return false;
 
336
 
 
337
  context.setValue( new KSValue( par * rate * d / y ) );
 
338
  return true;
 
339
}
 
340
 
 
341
// Function: DISC
 
342
bool kspreadfunc_disc( KSContext& context )
 
343
{
 
344
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
345
 
 
346
  int basis = 0;
 
347
 
 
348
  if ( !KSUtil::checkArgumentsCount( context, 5, "DISC", true ) )
 
349
  {
 
350
    if ( !KSUtil::checkArgumentsCount( context, 4, "DISC", true ) )
 
351
      return false;
 
352
  }
 
353
  else
 
354
  {
 
355
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
356
      return false;
 
357
 
 
358
    basis = args[4]->intValue();
 
359
  }
 
360
 
 
361
  QDate settlement;
 
362
  QDate maturity;
 
363
 
 
364
  if ( !getDate( context, args[0], settlement ) )
 
365
    return false;
 
366
 
 
367
  if ( !getDate( context, args[1], maturity ) )
 
368
    return false;
 
369
 
 
370
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
371
    return false;
 
372
 
 
373
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
374
    return false;
 
375
 
 
376
  double par    = args[2]->doubleValue();
 
377
  double redemp = args[3]->doubleValue();
 
378
 
 
379
  double y = daysPerYear( settlement, basis );
 
380
  double d = daysBetweenDates( settlement, maturity, basis );
 
381
 
 
382
  if ( y <= 0 || d <= 0 || basis < 0 || basis > 4 || redemp == 0 )
 
383
    return false;
 
384
 
 
385
  context.setValue( new KSValue( ( redemp - par ) / redemp * ( y / d ) ) );
 
386
  return true;
 
387
}
 
388
 
 
389
 
 
390
// Function: TBILLPRICE
 
391
bool kspreadfunc_tbillprice( KSContext& context )
 
392
{
 
393
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
394
 
 
395
  if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLPRICE", true ) )
 
396
    return false;
 
397
 
 
398
  QDate settlement;
 
399
  QDate maturity;
 
400
  double discount;
 
401
 
 
402
  if ( !getDate( context, args[0], settlement ) )
 
403
    return false;
 
404
 
 
405
  if ( !getDate( context, args[1], maturity ) )
 
406
    return false;
 
407
 
 
408
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
409
    return false;
 
410
 
 
411
  discount = args[2]->doubleValue();
 
412
 
 
413
  double days = settlement.daysTo( maturity );
 
414
 
 
415
  if ( settlement > maturity || discount < 0 || days > 265 )
 
416
    return false;
 
417
 
 
418
  context.setValue( new KSValue( 100 * ( 1.0 - ( discount * days ) / 360.0 ) ) );
 
419
  return true;
 
420
}
 
421
 
 
422
// Function: TBILLYIELD
 
423
bool kspreadfunc_tbillyield( KSContext& context )
 
424
{
 
425
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
426
 
 
427
  if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLYIELD", true ) )
 
428
    return false;
 
429
 
 
430
  QDate settlement;
 
431
  QDate maturity;
 
432
  double rate;
 
433
 
 
434
  if ( !getDate( context, args[0], settlement ) )
 
435
    return false;
 
436
 
 
437
  if ( !getDate( context, args[1], maturity ) )
 
438
    return false;
 
439
 
 
440
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
441
    return false;
 
442
 
 
443
  rate = args[2]->doubleValue();
 
444
 
 
445
  double days = settlement.daysTo( maturity );
 
446
 
 
447
  if ( settlement > maturity || rate <= 0 || days > 265 )
 
448
    return false;
 
449
 
 
450
  context.setValue( new KSValue( ( 100.0 - rate ) / rate * ( 360.0 / days ) ) );
 
451
  return true;
 
452
}
 
453
 
 
454
// Function: TBILLEQ
 
455
bool kspreadfunc_tbilleq( KSContext& context )
 
456
{
 
457
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
458
 
 
459
  if ( !KSUtil::checkArgumentsCount( context, 3, "TBILLEQ", true ) )
 
460
    return false;
 
461
 
 
462
  QDate settlement;
 
463
  QDate maturity;
 
464
  double discount;
 
465
 
 
466
  if ( !getDate( context, args[0], settlement ) )
 
467
    return false;
 
468
 
 
469
  if ( !getDate( context, args[1], maturity ) )
 
470
    return false;
 
471
 
 
472
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
473
    return false;
 
474
 
 
475
  discount = args[2]->doubleValue();
 
476
 
 
477
  double days = settlement.daysTo( maturity );
 
478
 
 
479
  if ( settlement > maturity || discount < 0 || days > 265 )
 
480
    return false;
 
481
 
 
482
  double divisor = 360.0 - discount * days;
 
483
 
 
484
  if ( divisor == 0 )
 
485
    return false;
 
486
 
 
487
  context.setValue( new KSValue( 365.0 * discount / divisor ) );
 
488
  return true;
 
489
}
 
490
 
 
491
// Function: RECEIVED
 
492
bool kspreadfunc_received( KSContext& context )
 
493
{
 
494
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
495
 
 
496
  int basis = 0;
 
497
 
 
498
  if ( !KSUtil::checkArgumentsCount( context, 5, "RECEIVED", true ) )
 
499
  {
 
500
    if ( !KSUtil::checkArgumentsCount( context, 4, "RECEIVED", true ) )
 
501
      return false;
 
502
  }
 
503
  else
 
504
  {
 
505
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
506
      return false;
 
507
 
 
508
    basis = args[4]->intValue();
 
509
  }
 
510
 
 
511
  QDate settlement;
 
512
  QDate maturity;
 
513
 
 
514
  if ( !getDate( context, args[0], settlement ) )
 
515
    return false;
 
516
 
 
517
  if ( !getDate( context, args[1], maturity ) )
 
518
    return false;
 
519
 
 
520
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
521
    return false;
 
522
 
 
523
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
524
    return false;
 
525
 
 
526
  double investment = args[2]->doubleValue();
 
527
  double discount   = args[3]->doubleValue();
 
528
 
 
529
  double d = daysBetweenDates( settlement, maturity, basis );
 
530
  double y = daysPerYear( settlement, basis );
 
531
 
 
532
  if ( d <= 0 || y <= 0 || basis < 0 || basis > 4 )
 
533
    return false;
 
534
 
 
535
  double x = 1.0 - ( discount * d / y );
 
536
 
 
537
  if ( x == 0 )
 
538
    return false;
 
539
 
 
540
  context.setValue( new KSValue( investment / x ) );
 
541
  return true;
 
542
}
 
543
 
 
544
// Function: DOLLARDE
 
545
bool kspreadfunc_dollarde( KSContext& context )
 
546
{
 
547
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
548
 
 
549
  if ( !KSUtil::checkArgumentsCount( context, 2, "DOLLARDE", true ) )
 
550
    return false;
 
551
 
 
552
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
553
    return false;
 
554
 
 
555
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
556
    return false;
 
557
 
 
558
  double d = args[0]->doubleValue();
 
559
  int f = (int) args[1]->intValue();
 
560
 
 
561
  if ( f <= 0 )
 
562
    return false;
 
563
 
 
564
  int tmp = f;
 
565
  int n = 0;
 
566
  while ( tmp > 0 )
 
567
  {
 
568
    tmp /= 10;
 
569
    ++n;
 
570
  }
 
571
 
 
572
  double fl = floor( d );
 
573
  double r  = d - fl;
 
574
 
 
575
  context.setValue( new KSValue( fl + ( r * pow( 10.0, n ) / (double) f ) ) );
 
576
  return true;
 
577
}
 
578
 
 
579
// Function: DOLLARFR
 
580
bool kspreadfunc_dollarfr( KSContext& context )
 
581
{
 
582
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
583
 
 
584
  if ( !KSUtil::checkArgumentsCount( context, 2, "DOLLARFR", true ) )
 
585
    return false;
 
586
 
 
587
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
588
    return false;
 
589
 
 
590
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
591
    return false;
 
592
 
 
593
  double d = args[0]->doubleValue();
 
594
  int f = (int) args[1]->intValue();
 
595
 
 
596
  if ( f <= 0 )
 
597
    return false;
 
598
 
 
599
  int tmp = f;
 
600
  int n = 0;
 
601
  while ( tmp > 0 )
 
602
  {
 
603
    tmp /= 10;
 
604
    ++n;
 
605
  }
 
606
 
 
607
  double fl = floor( d );
 
608
  double r  = d - fl;
 
609
 
 
610
  context.setValue( new KSValue( fl + ( ( r * (double) f ) / pow( 10.0, n ) ) ) );
 
611
  return true;
 
612
}
 
613
 
 
614
// Function: INTRATE
 
615
bool kspreadfunc_intrate( KSContext& context )
 
616
{
 
617
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
618
 
 
619
  int basis = 0;
 
620
 
 
621
  if ( !KSUtil::checkArgumentsCount( context, 5, "INTRATE", true ) )
 
622
  {
 
623
    if ( !KSUtil::checkArgumentsCount( context, 4, "INTRATE", true ) )
 
624
      return false;
 
625
  }
 
626
  else
 
627
  {
 
628
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
629
      return false;
 
630
 
 
631
    basis = args[4]->intValue();
 
632
  }
 
633
 
 
634
  QDate settlement;
 
635
  QDate maturity;
 
636
  double investment;
 
637
  double redemption;
 
638
 
 
639
  if ( !getDate( context, args[0], settlement ) )
 
640
    return false;
 
641
 
 
642
  if ( !getDate( context, args[1], maturity ) )
 
643
    return false;
 
644
 
 
645
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
646
    return false;
 
647
 
 
648
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
649
    return false;
 
650
 
 
651
  investment = args[2]->doubleValue();
 
652
  redemption = args[3]->doubleValue();
 
653
 
 
654
  double d = daysBetweenDates( settlement, maturity, basis );
 
655
  double y = daysPerYear( settlement, basis );
 
656
 
 
657
  if ( d <= 0 || y <= 0 || investment == 0 || basis < 0 || basis > 4 )
 
658
    return false;
 
659
 
 
660
  double result = ( redemption -investment ) / investment * ( y / d );
 
661
 
 
662
  context.setValue( new KSValue( result ) );
 
663
  return true;
 
664
}
 
665
 
 
666
 
 
667
// Function: DURATION
 
668
bool kspreadfunc_duration( KSContext& context )
 
669
{
 
670
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
671
 
 
672
  if ( !KSUtil::checkArgumentsCount( context, 3, "DURATION", true ) )
 
673
    return false;
 
674
 
 
675
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
676
    return false;
 
677
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
678
    return false;
 
679
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
680
    return false;
 
681
 
 
682
  double rate = args[0]->doubleValue();
 
683
  double pv   = args[1]->doubleValue();
 
684
  double fv   = args[2]->doubleValue();
 
685
 
 
686
  if ( rate <= 0.0 )
 
687
    return false;
 
688
  if ( fv == 0.0 || pv == 0.0 )
 
689
    return false;
 
690
  if ( fv / pv < 0 )
 
691
    return false;
 
692
 
 
693
  context.setValue( new KSValue( log( fv / pv ) / log( 1.0 + rate ) ) );
 
694
  return true;
 
695
}
 
696
 
 
697
// Function: PMT
 
698
bool kspreadfunc_pmt( KSContext& context )
 
699
{
 
700
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
701
 
 
702
  int type = -1;
 
703
  double fv = -1.0;
 
704
 
 
705
  if ( !KSUtil::checkArgumentsCount( context, 5, "PMT", false ) )
 
706
  {
 
707
    type = 0;
 
708
 
 
709
    if ( !KSUtil::checkArgumentsCount( context, 4, "PMT", false ) )
 
710
    {
 
711
      fv = 0.0;
 
712
 
 
713
      if ( !KSUtil::checkArgumentsCount( context, 3, "PMT", true ) )
 
714
        return false;
 
715
    }
 
716
  }
 
717
 
 
718
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
719
    return false;
 
720
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
721
    return false;
 
722
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
723
    return false;
 
724
  if ( fv == -1.0 )
 
725
  {
 
726
    if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
727
      return false;
 
728
    fv = args[3]->doubleValue();
 
729
  }
 
730
  if ( type == -1 )
 
731
  {
 
732
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
733
      return false;
 
734
    type = args[4]->intValue();
 
735
  }
 
736
 
 
737
  double rate = args[0]->doubleValue();
 
738
  double nper = args[1]->doubleValue();
 
739
  double pv   = args[2]->doubleValue();
 
740
 
 
741
  context.setValue( new KSValue( getPay( rate, nper, pv, fv, type ) ) );
 
742
  return true;
 
743
}
 
744
 
 
745
// Function: NPER
 
746
bool kspreadfunc_nper( KSContext& context )
 
747
{
 
748
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
749
 
 
750
  double fv = 0.0;
 
751
  int type  = 0;
 
752
 
 
753
  if ( KSUtil::checkArgumentsCount( context, 5, "NPER", true ) )
 
754
  {
 
755
    if ( !KSUtil::checkType( context, args[4], KSValue::IntType, true ) )
 
756
      return false;
 
757
    if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
758
      return false;
 
759
 
 
760
    fv   = args[3]->doubleValue();
 
761
    type = args[4]->intValue();
 
762
  }
 
763
  else
 
764
  if ( KSUtil::checkArgumentsCount( context, 4, "NPER", true ) )
 
765
  {
 
766
    type = 0;
 
767
    if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
768
      return false;
 
769
 
 
770
    fv   = args[3]->doubleValue();
 
771
  }
 
772
  else
 
773
  if ( !KSUtil::checkArgumentsCount( context, 3, "NPER", false ) )
 
774
    return false;
 
775
 
 
776
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
777
    return false;
 
778
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
779
    return false;
 
780
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
781
    return false;
 
782
 
 
783
  double rate = args[0]->doubleValue();
 
784
  double pmt  = args[1]->doubleValue();
 
785
  double pv   = args[2]->doubleValue();
 
786
 
 
787
  if ( rate <= 0.0 )
 
788
    return false;
 
789
 
 
790
  // taken from Gnumeric
 
791
  double d  = ( pmt * ( 1.0 + rate * type ) - fv * rate );
 
792
  double d2 = pv * rate + pmt * ( 1.0 + rate * type );
 
793
 
 
794
  double res = d / d2;
 
795
 
 
796
  if ( res <= 0.0 )
 
797
    return false;
 
798
 
 
799
  context.setValue( new KSValue( log( res ) / log( 1.0 + rate ) ) );
 
800
  return true;
 
801
}
 
802
 
 
803
// Function: ISPMT
 
804
bool kspreadfunc_ispmt( KSContext& context )
 
805
{
 
806
  QValueList<KSValue::Ptr> & args = context.value()->listValue();
 
807
 
 
808
  if ( !KSUtil::checkArgumentsCount( context, 4, "ISPMT", false ) )
 
809
    return false;
 
810
 
 
811
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
812
    return false;
 
813
  if ( !KSUtil::checkType( context, args[1], KSValue::IntType, true ) )
 
814
    return false;
 
815
  if ( !KSUtil::checkType( context, args[2], KSValue::IntType, true ) )
 
816
    return false;
 
817
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
818
    return false;
 
819
 
 
820
  double rate = args[0]->doubleValue();
 
821
  int    per  = args[1]->intValue();
 
822
  int    nper = args[2]->intValue();
 
823
  double pv   = args[3]->doubleValue();
 
824
 
 
825
  if ( per < 1 || per > nper )
 
826
    return false;
 
827
 
 
828
  double d = -pv * rate;
 
829
 
 
830
  context.setValue( new KSValue( d - ( d / nper * per ) ) );
 
831
  return true;
 
832
}
 
833
 
 
834
// Function: IPMT
 
835
bool kspreadfunc_ipmt( KSContext& context )
 
836
{
 
837
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
838
 
 
839
  double rate;
 
840
  double per;
 
841
  double nper;
 
842
  double pv;
 
843
  double fv = 0.0;
 
844
  int type  = 0;
 
845
 
 
846
  if ( KSUtil::checkArgumentsCount( context, 6, "IPMT", true ) )
 
847
  {
 
848
    if ( !KSUtil::checkType( context, args[5], KSValue::IntType, true ) )
 
849
      return false;
 
850
    if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
851
      return false;
 
852
    type = args[5]->intValue();
 
853
    fv   = args[4]->doubleValue();
 
854
  }
 
855
  else
 
856
  if ( KSUtil::checkArgumentsCount( context, 5, "IPMT", true ) )
 
857
  {
 
858
    if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
859
      return false;
 
860
 
 
861
    fv = args[4]->doubleValue();
 
862
  }
 
863
  else
 
864
  if ( !KSUtil::checkArgumentsCount( context, 4, "IPMT", false ) )
 
865
    return false;
 
866
 
 
867
 
 
868
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
869
    return false;
 
870
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
871
    return false;
 
872
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
873
    return false;
 
874
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
875
    return false;
 
876
 
 
877
  rate = args[0]->doubleValue();
 
878
  per  = args[1]->doubleValue();
 
879
  nper = args[2]->doubleValue();
 
880
  pv   = args[3]->doubleValue();
 
881
 
 
882
  double payment = getPay( rate, nper, pv, fv, type );
 
883
  double ipmt    = -getPrinc( pv, payment, rate, per - 1 );
 
884
 
 
885
  context.setValue( new KSValue( ipmt * rate ) );
 
886
  return true;
 
887
}
 
888
 
 
889
// Function: FV
 
890
/* Returns future value, given current value, interest rate and time */
 
891
bool kspreadfunc_fv( KSContext& context )
 
892
{
 
893
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
894
 
 
895
  if ( !KSUtil::checkArgumentsCount( context, 3, "FV", true ) )
 
896
    return false;
 
897
 
 
898
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
899
    return false;
 
900
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
901
    return false;
 
902
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
903
    return false;
 
904
 
 
905
  double present = args[0]->doubleValue();
 
906
  double interest = args[1]->doubleValue();
 
907
  double periods = args[2]->doubleValue();
 
908
 
 
909
  context.setValue( new KSValue( present * pow(1+interest, periods)));
 
910
  return true;
 
911
}
 
912
 
 
913
// Function: compound
 
914
/* Returns value after compounded interest, given principal, rate, periods
 
915
per year and year */
 
916
 bool kspreadfunc_compound( KSContext& context )
 
917
{
 
918
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
919
 
 
920
  if ( !KSUtil::checkArgumentsCount( context, 4, "compound", true ) )
 
921
    return false;
 
922
 
 
923
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
924
    return false;
 
925
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
926
    return false;
 
927
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
928
    return false;
 
929
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
930
    return false;
 
931
  double principal = args[0]->doubleValue();
 
932
  double interest = args[1]->doubleValue();
 
933
  double periods = args[2]->doubleValue();
 
934
  double years = args[3]->doubleValue();
 
935
 
 
936
  context.setValue( new KSValue( principal * pow(1+(interest/periods),
 
937
periods*years)));
 
938
 
 
939
  return true;
 
940
}
 
941
 
 
942
// Function: continuous
 
943
/* Returns value after continuous compounding of interest, given prinicpal,
 
944
rate and years */
 
945
bool kspreadfunc_continuous( KSContext& context )
 
946
{
 
947
    // If you still don't understand this, let me know!  ;-)  jsinger@leeta.net
 
948
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
949
 
 
950
  if ( !KSUtil::checkArgumentsCount( context, 3, "continuous", true ) )
 
951
    return false;
 
952
 
 
953
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
954
    return false;
 
955
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
956
    return false;
 
957
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
958
    return false;
 
959
  double principal = args[0]->doubleValue();
 
960
  double interest = args[1]->doubleValue();
 
961
  double years = args[2]->doubleValue();
 
962
 
 
963
 
 
964
  context.setValue( new KSValue( principal * exp(interest * years)));
 
965
  return true;
 
966
}
 
967
 
 
968
// Function: PV
 
969
bool kspreadfunc_pv( KSContext& context )
 
970
{
 
971
/* Returns presnt value, given future value, interest rate and years */
 
972
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
973
 
 
974
  if ( !KSUtil::checkArgumentsCount( context, 3, "PV", true ) )
 
975
    return false;
 
976
 
 
977
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
978
    return false;
 
979
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
980
    return false;
 
981
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
982
    return false;
 
983
  double future = args[0]->doubleValue();
 
984
  double interest = args[1]->doubleValue();
 
985
  double periods = args[2]->doubleValue();
 
986
 
 
987
 
 
988
  context.setValue( new KSValue( future / pow(1+interest, periods)));
 
989
  return true;
 
990
}
 
991
 
 
992
// Function: PV_annuity
 
993
bool kspreadfunc_pv_annuity( KSContext& context )
 
994
{
 
995
    /* Returns present value of an annuity or cash flow, given payment,
 
996
       interest rate,
 
997
       periods, initial amount and whether payments are made at the start (TRUE)
 
998
       or end of a period */
 
999
 
 
1000
    QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1001
 
 
1002
    if ( !KSUtil::checkArgumentsCount( context, 3, "PV_annuity", true ) )
 
1003
        return false;
 
1004
 
 
1005
    if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1006
        return false;
 
1007
    if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1008
        return false;
 
1009
    if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1010
        return false;
 
1011
    double amount = args[0]->doubleValue();
 
1012
    double interest = args[1]->doubleValue();
 
1013
    double periods = args[2]->doubleValue();
 
1014
 
 
1015
    double result;
 
1016
    result = amount * (1 - 1/(pow( (1+interest), periods ))) / interest ;
 
1017
 
 
1018
  context.setValue( new KSValue( result ) );
 
1019
 
 
1020
  return true;
 
1021
}
 
1022
 
 
1023
// Function: FV_annnuity
 
1024
bool kspreadfunc_fv_annuity( KSContext& context )
 
1025
{
 
1026
    /* Returns future value of an annuity or cash flow, given payment, interest
 
1027
       rate and periods */
 
1028
 
 
1029
    QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1030
 
 
1031
    if ( !KSUtil::checkArgumentsCount( context, 3, "FV_annuity", true ) )
 
1032
        return false;
 
1033
 
 
1034
    if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1035
        return false;
 
1036
    if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1037
        return false;
 
1038
    if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1039
        return false;
 
1040
    double amount= args[0]->doubleValue();
 
1041
    double interest = args[1]->doubleValue();
 
1042
    double periods = args[2]->doubleValue();
 
1043
 
 
1044
    double result;
 
1045
 
 
1046
    result = amount * ((pow( (1+interest),periods))/interest - 1/interest)   ;
 
1047
 
 
1048
    context.setValue( new KSValue( result ) );
 
1049
 
 
1050
    return true;
 
1051
}
 
1052
 
 
1053
// Function: effective
 
1054
bool kspreadfunc_effective( KSContext& context )
 
1055
{
 
1056
/* Returns effective interest rate given nominal rate and periods per year */
 
1057
 
 
1058
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1059
 
 
1060
  if ( !KSUtil::checkArgumentsCount( context, 2, "effective", true ) )
 
1061
    return false;
 
1062
 
 
1063
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1064
    return false;
 
1065
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1066
    return false;
 
1067
  double nominal = args[0]->doubleValue();
 
1068
  double periods = args[1]->doubleValue();
 
1069
 
 
1070
  context.setValue( new KSValue(  pow( 1 + (nominal/periods), periods )- 1 ) );
 
1071
 
 
1072
  return true;
 
1073
}
 
1074
 
 
1075
// Function: zero_coupon
 
1076
bool kspreadfunc_zero_coupon( KSContext& context )
 
1077
{
 
1078
/* Returns effective interest rate given nominal rate and periods per year */
 
1079
 
 
1080
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1081
 
 
1082
  if ( !KSUtil::checkArgumentsCount( context, 3, "zero_coupon", true ) )
 
1083
    return false;
 
1084
 
 
1085
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1086
    return false;
 
1087
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1088
    return false;
 
1089
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1090
    return false;
 
1091
  double face = args[0]->doubleValue();
 
1092
  double rate = args[1]->doubleValue();
 
1093
  double years = args[2]->doubleValue();
 
1094
 
 
1095
  context.setValue( new KSValue(  face / pow( (1 + rate), years )  ) );
 
1096
 
 
1097
  return true;
 
1098
}
 
1099
 
 
1100
// Function: level_coupon
 
1101
bool kspreadfunc_level_coupon( KSContext& context )
 
1102
{
 
1103
/* Returns effective interest rate given nominal rate and periods per year */
 
1104
 
 
1105
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1106
 
 
1107
  if ( !KSUtil::checkArgumentsCount( context, 5, "level_coupon", true ) )
 
1108
    return false;
 
1109
 
 
1110
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1111
    return false;
 
1112
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1113
    return false;
 
1114
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1115
    return false;
 
1116
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
1117
    return false;
 
1118
  if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
1119
    return false;
 
1120
  double face = args[0]->doubleValue();
 
1121
  double coupon_rate = args[1]->doubleValue();
 
1122
  double coupon_year = args[2]->doubleValue();
 
1123
  double years = args[3]->doubleValue();
 
1124
  double market_rate = args[4]->doubleValue();
 
1125
 
 
1126
  double coupon = coupon_rate * face / coupon_year;
 
1127
  double interest =  market_rate/coupon_year;
 
1128
  double pv_annuity = (1 - 1/(pow( (1+interest), (years*coupon_year) ))) / interest ;
 
1129
  context.setValue( new KSValue( coupon * pv_annuity + (face/ pow( (1+interest), (years*coupon_year) ) ) ) );
 
1130
 
 
1131
  return true;
 
1132
}
 
1133
 
 
1134
// Function: nominal
 
1135
bool kspreadfunc_nominal( KSContext& context )
 
1136
{
 
1137
/* Returns nominal interest rate given effective rate and periods per year */
 
1138
 
 
1139
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1140
 
 
1141
  if ( !KSUtil::checkArgumentsCount( context, 2, "nominal", true ) )
 
1142
    return false;
 
1143
 
 
1144
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1145
    return false;
 
1146
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1147
    return false;
 
1148
  double effective = args[0]->doubleValue();
 
1149
  double periods = args[1]->doubleValue();
 
1150
 
 
1151
  if ( periods == 0.0 ) // Check null
 
1152
      return false;
 
1153
 
 
1154
  context.setValue( new KSValue( periods * (pow( (effective + 1), (1 / periods) ) -1) ) );
 
1155
 
 
1156
  return true;
 
1157
}
 
1158
 
 
1159
// Function: SLN
 
1160
/* straight-line depreciation for a single period */
 
1161
bool kspreadfunc_sln( KSContext& context )
 
1162
{
 
1163
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1164
 
 
1165
  if ( !KSUtil::checkArgumentsCount( context, 3, "SLN", true ) )
 
1166
    return false;
 
1167
 
 
1168
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1169
    return false;
 
1170
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1171
    return false;
 
1172
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1173
    return false;
 
1174
 
 
1175
  double cost = args[0]->doubleValue();
 
1176
  double salvage_value = args[1]->doubleValue();
 
1177
  double life = args[2]->doubleValue();
 
1178
 
 
1179
  // sentinel check
 
1180
  if( life <= 0.0 ) return false;
 
1181
 
 
1182
  context.setValue( new KSValue( (cost - salvage_value) / life ) );
 
1183
 
 
1184
  return true;
 
1185
}
 
1186
 
 
1187
// Function: SYD
 
1188
/* sum-of-years digits depreciation */
 
1189
bool kspreadfunc_syd( KSContext& context )
 
1190
{
 
1191
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1192
 
 
1193
  if ( !KSUtil::checkArgumentsCount( context, 4, "SYD", true ) )
 
1194
    return false;
 
1195
 
 
1196
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1197
    return false;
 
1198
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1199
    return false;
 
1200
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1201
    return false;
 
1202
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
1203
    return false;
 
1204
 
 
1205
  double cost = args[0]->doubleValue();
 
1206
  double salvage_value = args[1]->doubleValue();
 
1207
  double life = args[2]->doubleValue();
 
1208
  double period = args[3]->doubleValue();
 
1209
 
 
1210
  // sentinel check
 
1211
  if( life <= 0.0 ) return false;
 
1212
 
 
1213
  context.setValue( new KSValue( ( ( (cost - salvage_value) * (life - period + 1) * 2) /
 
1214
     (life * (life + 1.0) ) ) ) ) ;
 
1215
 
 
1216
  return true;
 
1217
}
 
1218
 
 
1219
// Function: DB
 
1220
/* fixed-declining depreciation */
 
1221
bool kspreadfunc_db( KSContext& context )
 
1222
{
 
1223
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1224
 
 
1225
  double month = 12;
 
1226
 
 
1227
  if( KSUtil::checkArgumentsCount( context, 5, "DB", false ) )
 
1228
  {
 
1229
    if( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
1230
      return false;
 
1231
    month = args[4]->doubleValue();
 
1232
  }
 
1233
  else
 
1234
  {
 
1235
    if ( !KSUtil::checkArgumentsCount( context, 4, "DB", true ) )
 
1236
      return false;
 
1237
  }
 
1238
 
 
1239
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1240
    return false;
 
1241
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1242
    return false;
 
1243
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1244
    return false;
 
1245
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
1246
    return false;
 
1247
 
 
1248
  double cost = args[0]->doubleValue();
 
1249
  double salvage = args[1]->doubleValue();
 
1250
  double life = args[2]->doubleValue();
 
1251
  double period = args[3]->doubleValue();
 
1252
 
 
1253
  // sentinel check
 
1254
  if( cost == 0 || life <= 0.0 ) return false;
 
1255
  if( salvage / cost < 0 ) return false;
 
1256
 
 
1257
  double rate = 1000 * (1 - pow( (salvage/cost), (1/life) ));
 
1258
  rate = floor( rate + 0.5 )  / 1000;
 
1259
 
 
1260
  double total = cost * rate * month / 12;
 
1261
 
 
1262
  if( period == 1 )
 
1263
  {
 
1264
    context.setValue( new KSValue( total ) );
 
1265
    return true;
 
1266
  }
 
1267
 
 
1268
  for( int i = 1; i < life; ++i )
 
1269
    if( i == period-1 )
 
1270
    {
 
1271
      context.setValue( new KSValue( rate * (cost-total) ) );
 
1272
      return true;
 
1273
    }
 
1274
    else total += rate * (cost-total);
 
1275
 
 
1276
  context.setValue( new KSValue( (cost-total) * rate * (12-month)/12 ) );
 
1277
 
 
1278
  return true;
 
1279
}
 
1280
 
 
1281
// Function: DDB
 
1282
/* depreciation per period */
 
1283
bool kspreadfunc_ddb( KSContext& context )
 
1284
{
 
1285
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1286
 
 
1287
  double factor = 2;
 
1288
 
 
1289
  if( KSUtil::checkArgumentsCount( context, 5, "DB", false ) )
 
1290
  {
 
1291
    if( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
1292
      return false;
 
1293
 
 
1294
    factor = args[4]->doubleValue();
 
1295
  }
 
1296
  else
 
1297
  {
 
1298
    if ( !KSUtil::checkArgumentsCount( context, 4, "DB", true ) )
 
1299
      return false;
 
1300
  }
 
1301
 
 
1302
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1303
    return false;
 
1304
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1305
    return false;
 
1306
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1307
    return false;
 
1308
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
1309
    return false;
 
1310
 
 
1311
  double cost    = args[0]->doubleValue();
 
1312
  double salvage = args[1]->doubleValue();
 
1313
  double life    = args[2]->doubleValue();
 
1314
  double period  = args[3]->doubleValue();
 
1315
  double total   = 0.0;
 
1316
 
 
1317
  if ( cost < 0.0 || salvage < 0.0 || life <= 0.0 || period < 0.0 || factor < 0.0 )
 
1318
    return false;
 
1319
 
 
1320
  for( int i = 0; i < life; ++i )
 
1321
  {
 
1322
    double periodDep = ( cost - total ) * ( factor / life );
 
1323
    if ( i == period - 1 )
 
1324
    {
 
1325
      context.setValue( new KSValue( periodDep ) );
 
1326
      return true;
 
1327
    }
 
1328
    else
 
1329
    {
 
1330
      total += periodDep;
 
1331
    }
 
1332
  }
 
1333
 
 
1334
  context.setValue( new KSValue( cost - total - salvage ) );
 
1335
 
 
1336
  return true;
 
1337
}
 
1338
 
 
1339
bool kspreadfunc_ppmt( KSContext & context )
 
1340
{
 
1341
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1342
  /*
 
1343
Docs partly copied from OO.
 
1344
Syntax
 
1345
PPMT(Rate;Period;NPER;PV;FV;Type)
 
1346
 
 
1347
Rate is the periodic interest rate.
 
1348
Period is the amortizement period. P=1 for the first and P=NPER for the last period.
 
1349
NPER is the total number of periods during which annuity is paid.
 
1350
PV is the present value in the sequence of payments.
 
1351
FV (optional) is the desired (future) value.
 
1352
Type (optional) defines the due date. F=1 for payment at the beginning of a period and F=0 for payment at the end of a period.
 
1353
  */
 
1354
 
 
1355
  double fv = -1.0;
 
1356
  int type = -1;
 
1357
 
 
1358
  if ( !KSUtil::checkArgumentsCount( context, 6, "PPMT", false ) )
 
1359
  {
 
1360
    type = 0;
 
1361
 
 
1362
    if ( !KSUtil::checkArgumentsCount( context, 5, "PPMT", false ) )
 
1363
    {
 
1364
      fv = 0.0;
 
1365
 
 
1366
      if ( !KSUtil::checkArgumentsCount( context, 4, "PPMT", true ) )
 
1367
        return false;
 
1368
    }
 
1369
  }
 
1370
 
 
1371
  if ( !KSUtil::checkType( context, args[0], KSValue::DoubleType, true ) )
 
1372
    return false;
 
1373
  if ( !KSUtil::checkType( context, args[1], KSValue::DoubleType, true ) )
 
1374
    return false;
 
1375
  if ( !KSUtil::checkType( context, args[2], KSValue::DoubleType, true ) )
 
1376
    return false;
 
1377
  if ( !KSUtil::checkType( context, args[3], KSValue::DoubleType, true ) )
 
1378
    return false;
 
1379
  if ( fv == -1 )
 
1380
  {
 
1381
    if ( !KSUtil::checkType( context, args[4], KSValue::DoubleType, true ) )
 
1382
      return false;
 
1383
    fv = args[4]->doubleValue();
 
1384
  }
 
1385
  if ( type == -1 )
 
1386
  {
 
1387
    if ( !KSUtil::checkType( context, args[5], KSValue::IntType, true ) )
 
1388
      return false;
 
1389
    type = args[5]->intValue();
 
1390
  }
 
1391
 
 
1392
  double rate   = args[0]->doubleValue();
 
1393
  double period = args[1]->doubleValue();
 
1394
  double nper   = args[2]->doubleValue();
 
1395
  double pv     = args[3]->doubleValue();
 
1396
 
 
1397
  double pay  = getPay( rate, nper, pv, fv, type );
 
1398
  double ipmt = -getPrinc( pv, pay, rate, period - 1 ) * rate;
 
1399
 
 
1400
  context.setValue( new KSValue( pay - ipmt ) );
 
1401
 
 
1402
  return true;
 
1403
}
 
1404
 
 
1405
// Function: EURO
 
1406
bool kspreadfunc_euro( KSContext& context )
 
1407
{
 
1408
  QValueList<KSValue::Ptr>& args = context.value()->listValue();
 
1409
 
 
1410
  if ( !KSUtil::checkArgumentsCount( context, 1, "EURO", true ) )
 
1411
    return false;
 
1412
 
 
1413
  if ( !KSUtil::checkType( context, args[0], KSValue::StringType, true ) )
 
1414
    return false;
 
1415
 
 
1416
  QString currency = args[0]->stringValue().upper();
 
1417
  double result = -1;
 
1418
 
 
1419
  if( currency == "ATS" ) result = 13.7603;  // Austria
 
1420
  else if( currency == "BEF" ) result = 40.3399;  // Belgium
 
1421
  else if( currency == "DEM" ) result = 1.95583;  // Germany
 
1422
  else if( currency == "ESP" ) result = 166.386;  // Spain
 
1423
  else if( currency == "FIM" ) result = 5.94573;  // Finland
 
1424
  else if( currency == "FRF" ) result = 6.55957;  // France
 
1425
  else if( currency == "GRD" ) result = 340.75;   // Greece
 
1426
  else if( currency == "IEP" ) result = 0.787564; // Ireland
 
1427
  else if( currency == "ITL" ) result = 1936.27;  // Italy
 
1428
  else if( currency == "LUX" ) result = 40.3399;  // Luxemburg
 
1429
  else if( currency == "NLG" ) result = 2.20371;  // Nederland
 
1430
  else if( currency == "PTE" ) result = 200.482;  // Portugal
 
1431
 
 
1432
  if( result <= 0 ) return false;
 
1433
 
 
1434
  context.setValue( new KSValue( result ) );
 
1435
  return true;
 
1436
}