PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.0.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.0.3
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Calculation / Financial.php

Financial.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.0.3, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Calculation/Financial.php

2,293 lines 85.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PHPExcel
4 *
5 * Copyright (c) 2006 - 2014 PHPExcel
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * @category PHPExcel
22 * @package PHPExcel_Calculation
23 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25 * @version ##VERSION##, ##DATE##
26 */
27
28
29 /** PHPExcel root directory */
30 if (!defined('PHPEXCEL_ROOT')) {
31 /**
32 * @ignore
33 */
34 define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
35 require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
36 }
37
38
39 /** FINANCIAL_MAX_ITERATIONS */
40 define('FINANCIAL_MAX_ITERATIONS', 128);
41
42 /** FINANCIAL_PRECISION */
43 define('FINANCIAL_PRECISION', 1.0e-08);
44
45
46 /**
47 * PHPExcel_Calculation_Financial
48 *
49 * @category PHPExcel
50 * @package PHPExcel_Calculation
51 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
52 */
53 class PHPExcel_Calculation_Financial {
54
55 /**
56 * _lastDayOfMonth
57 *
58 * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month
59 *
60 * @param DateTime $testDate The date for testing
61 * @return boolean
62 */
63 private static function _lastDayOfMonth($testDate)
64 {
65 return ($testDate->format('d') == $testDate->format('t'));
66 } // function _lastDayOfMonth()
67
68
69 /**
70 * _firstDayOfMonth
71 *
72 * Returns a boolean TRUE/FALSE indicating if this date is the first date of the month
73 *
74 * @param DateTime $testDate The date for testing
75 * @return boolean
76 */
77 private static function _firstDayOfMonth($testDate)
78 {
79 return ($testDate->format('d') == 1);
80 } // function _firstDayOfMonth()
81
82
83 private static function _coupFirstPeriodDate($settlement, $maturity, $frequency, $next)
84 {
85 $months = 12 / $frequency;
86
87 $result = PHPExcel_Shared_Date::ExcelToPHPObject($maturity);
88 $eom = self::_lastDayOfMonth($result);
89
90 while ($settlement < PHPExcel_Shared_Date::PHPToExcel($result)) {
91 $result->modify('-'.$months.' months');
92 }
93 if ($next) {
94 $result->modify('+'.$months.' months');
95 }
96
97 if ($eom) {
98 $result->modify('-1 day');
99 }
100
101 return PHPExcel_Shared_Date::PHPToExcel($result);
102 } // function _coupFirstPeriodDate()
103
104
105 private static function _validFrequency($frequency)
106 {
107 if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) {
108 return true;
109 }
110 if ((PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) &&
111 (($frequency == 6) || ($frequency == 12))) {
112 return true;
113 }
114 return false;
115 } // function _validFrequency()
116
117
118 /**
119 * _daysPerYear
120 *
121 * Returns the number of days in a specified year, as defined by the "basis" value
122 *
123 * @param integer $year The year against which we're testing
124 * @param integer $basis The type of day count:
125 * 0 or omitted US (NASD) 360
126 * 1 Actual (365 or 366 in a leap year)
127 * 2 360
128 * 3 365
129 * 4 European 360
130 * @return integer
131 */
132 private static function _daysPerYear($year, $basis=0)
133 {
134 switch ($basis) {
135 case 0 :
136 case 2 :
137 case 4 :
138 $daysPerYear = 360;
139 break;
140 case 3 :
141 $daysPerYear = 365;
142 break;
143 case 1 :
144 $daysPerYear = (PHPExcel_Calculation_DateTime::_isLeapYear($year)) ? 366 : 365;
145 break;
146 default :
147 return PHPExcel_Calculation_Functions::NaN();
148 }
149 return $daysPerYear;
150 } // function _daysPerYear()
151
152
153 private static function _interestAndPrincipal($rate=0, $per=0, $nper=0, $pv=0, $fv=0, $type=0)
154 {
155 $pmt = self::PMT($rate, $nper, $pv, $fv, $type);
156 $capital = $pv;
157 for ($i = 1; $i<= $per; ++$i) {
158 $interest = ($type && $i == 1) ? 0 : -$capital * $rate;
159 $principal = $pmt - $interest;
160 $capital += $principal;
161 }
162 return array($interest, $principal);
163 } // function _interestAndPrincipal()
164
165
166 /**
167 * ACCRINT
168 *
169 * Returns the accrued interest for a security that pays periodic interest.
170 *
171 * Excel Function:
172 * ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis])
173 *
174 * @access public
175 * @category Financial Functions
176 * @param mixed $issue The security's issue date.
177 * @param mixed $firstinterest The security's first interest date.
178 * @param mixed $settlement The security's settlement date.
179 * The security settlement date is the date after the issue date
180 * when the security is traded to the buyer.
181 * @param float $rate The security's annual coupon rate.
182 * @param float $par The security's par value.
183 * If you omit par, ACCRINT uses $1,000.
184 * @param integer $frequency the number of coupon payments per year.
185 * Valid frequency values are:
186 * 1 Annual
187 * 2 Semi-Annual
188 * 4 Quarterly
189 * If working in Gnumeric Mode, the following frequency options are
190 * also available
191 * 6 Bimonthly
192 * 12 Monthly
193 * @param integer $basis The type of day count to use.
194 * 0 or omitted US (NASD) 30/360
195 * 1 Actual/actual
196 * 2 Actual/360
197 * 3 Actual/365
198 * 4 European 30/360
199 * @return float
200 */
201 public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par=1000, $frequency=1, $basis=0)
202 {
203 $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
204 $firstinterest = PHPExcel_Calculation_Functions::flattenSingleValue($firstinterest);
205 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
206 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
207 $par = (is_null($par)) ? 1000 : PHPExcel_Calculation_Functions::flattenSingleValue($par);
208 $frequency = (is_null($frequency)) ? 1 : PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
209 $basis = (is_null($basis)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($basis);
210
211 // Validate
212 if ((is_numeric($rate)) && (is_numeric($par))) {
213 $rate = (float) $rate;
214 $par = (float) $par;
215 if (($rate <= 0) || ($par <= 0)) {
216 return PHPExcel_Calculation_Functions::NaN();
217 }
218 $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
219 if (!is_numeric($daysBetweenIssueAndSettlement)) {
220 // return date error
221 return $daysBetweenIssueAndSettlement;
222 }
223
224 return $par * $rate * $daysBetweenIssueAndSettlement;
225 }
226 return PHPExcel_Calculation_Functions::VALUE();
227 } // function ACCRINT()
228
229
230 /**
231 * ACCRINTM
232 *
233 * Returns the accrued interest for a security that pays interest at maturity.
234 *
235 * Excel Function:
236 * ACCRINTM(issue,settlement,rate[,par[,basis]])
237 *
238 * @access public
239 * @category Financial Functions
240 * @param mixed issue The security's issue date.
241 * @param mixed settlement The security's settlement (or maturity) date.
242 * @param float rate The security's annual coupon rate.
243 * @param float par The security's par value.
244 * If you omit par, ACCRINT uses $1,000.
245 * @param integer basis The type of day count to use.
246 * 0 or omitted US (NASD) 30/360
247 * 1 Actual/actual
248 * 2 Actual/360
249 * 3 Actual/365
250 * 4 European 30/360
251 * @return float
252 */
253 public static function ACCRINTM($issue, $settlement, $rate, $par=1000, $basis=0) {
254 $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
255 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
256 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
257 $par = (is_null($par)) ? 1000 : PHPExcel_Calculation_Functions::flattenSingleValue($par);
258 $basis = (is_null($basis)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($basis);
259
260 // Validate
261 if ((is_numeric($rate)) && (is_numeric($par))) {
262 $rate = (float) $rate;
263 $par = (float) $par;
264 if (($rate <= 0) || ($par <= 0)) {
265 return PHPExcel_Calculation_Functions::NaN();
266 }
267 $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
268 if (!is_numeric($daysBetweenIssueAndSettlement)) {
269 // return date error
270 return $daysBetweenIssueAndSettlement;
271 }
272 return $par * $rate * $daysBetweenIssueAndSettlement;
273 }
274 return PHPExcel_Calculation_Functions::VALUE();
275 } // function ACCRINTM()
276
277
278 /**
279 * AMORDEGRC
280 *
281 * Returns the depreciation for each accounting period.
282 * This function is provided for the French accounting system. If an asset is purchased in
283 * the middle of the accounting period, the prorated depreciation is taken into account.
284 * The function is similar to AMORLINC, except that a depreciation coefficient is applied in
285 * the calculation depending on the life of the assets.
286 * This function will return the depreciation until the last period of the life of the assets
287 * or until the cumulated value of depreciation is greater than the cost of the assets minus
288 * the salvage value.
289 *
290 * Excel Function:
291 * AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
292 *
293 * @access public
294 * @category Financial Functions
295 * @param float cost The cost of the asset.
296 * @param mixed purchased Date of the purchase of the asset.
297 * @param mixed firstPeriod Date of the end of the first period.
298 * @param mixed salvage The salvage value at the end of the life of the asset.
299 * @param float period The period.
300 * @param float rate Rate of depreciation.
301 * @param integer basis The type of day count to use.
302 * 0 or omitted US (NASD) 30/360
303 * 1 Actual/actual
304 * 2 Actual/360
305 * 3 Actual/365
306 * 4 European 30/360
307 * @return float
308 */
309 public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) {
310 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
311 $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased);
312 $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod);
313 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
314 $period = floor(PHPExcel_Calculation_Functions::flattenSingleValue($period));
315 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
316 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
317
318 // The depreciation coefficients are:
319 // Life of assets (1/rate) Depreciation coefficient
320 // Less than 3 years 1
321 // Between 3 and 4 years 1.5
322 // Between 5 and 6 years 2
323 // More than 6 years 2.5
324 $fUsePer = 1.0 / $rate;
325 if ($fUsePer < 3.0) {
326 $amortiseCoeff = 1.0;
327 } elseif ($fUsePer < 5.0) {
328 $amortiseCoeff = 1.5;
329 } elseif ($fUsePer <= 6.0) {
330 $amortiseCoeff = 2.0;
331 } else {
332 $amortiseCoeff = 2.5;
333 }
334
335 $rate *= $amortiseCoeff;
336 $fNRate = round(PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost,0);
337 $cost -= $fNRate;
338 $fRest = $cost - $salvage;
339
340 for ($n = 0; $n < $period; ++$n) {
341 $fNRate = round($rate * $cost,0);
342 $fRest -= $fNRate;
343
344 if ($fRest < 0.0) {
345 switch ($period - $n) {
346 case 0 :
347 case 1 : return round($cost * 0.5, 0);
348 break;
349 default : return 0.0;
350 break;
351 }
352 }
353 $cost -= $fNRate;
354 }
355 return $fNRate;
356 } // function AMORDEGRC()
357
358
359 /**
360 * AMORLINC
361 *
362 * Returns the depreciation for each accounting period.
363 * This function is provided for the French accounting system. If an asset is purchased in
364 * the middle of the accounting period, the prorated depreciation is taken into account.
365 *
366 * Excel Function:
367 * AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
368 *
369 * @access public
370 * @category Financial Functions
371 * @param float cost The cost of the asset.
372 * @param mixed purchased Date of the purchase of the asset.
373 * @param mixed firstPeriod Date of the end of the first period.
374 * @param mixed salvage The salvage value at the end of the life of the asset.
375 * @param float period The period.
376 * @param float rate Rate of depreciation.
377 * @param integer basis The type of day count to use.
378 * 0 or omitted US (NASD) 30/360
379 * 1 Actual/actual
380 * 2 Actual/360
381 * 3 Actual/365
382 * 4 European 30/360
383 * @return float
384 */
385 public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) {
386 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
387 $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased);
388 $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod);
389 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
390 $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
391 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
392 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
393
394 $fOneRate = $cost * $rate;
395 $fCostDelta = $cost - $salvage;
396 // Note, quirky variation for leap years on the YEARFRAC for this function
397 $purchasedYear = PHPExcel_Calculation_DateTime::YEAR($purchased);
398 $yearFrac = PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis);
399
400 if (($basis == 1) && ($yearFrac < 1) && (PHPExcel_Calculation_DateTime::_isLeapYear($purchasedYear))) {
401 $yearFrac *= 365 / 366;
402 }
403
404 $f0Rate = $yearFrac * $rate * $cost;
405 $nNumOfFullPeriods = intval(($cost - $salvage - $f0Rate) / $fOneRate);
406
407 if ($period == 0) {
408 return $f0Rate;
409 } elseif ($period <= $nNumOfFullPeriods) {
410 return $fOneRate;
411 } elseif ($period == ($nNumOfFullPeriods + 1)) {
412 return ($fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate);
413 } else {
414 return 0.0;
415 }
416 } // function AMORLINC()
417
418
419 /**
420 * COUPDAYBS
421 *
422 * Returns the number of days from the beginning of the coupon period to the settlement date.
423 *
424 * Excel Function:
425 * COUPDAYBS(settlement,maturity,frequency[,basis])
426 *
427 * @access public
428 * @category Financial Functions
429 * @param mixed settlement The security's settlement date.
430 * The security settlement date is the date after the issue
431 * date when the security is traded to the buyer.
432 * @param mixed maturity The security's maturity date.
433 * The maturity date is the date when the security expires.
434 * @param mixed frequency the number of coupon payments per year.
435 * Valid frequency values are:
436 * 1 Annual
437 * 2 Semi-Annual
438 * 4 Quarterly
439 * If working in Gnumeric Mode, the following frequency options are
440 * also available
441 * 6 Bimonthly
442 * 12 Monthly
443 * @param integer basis The type of day count to use.
444 * 0 or omitted US (NASD) 30/360
445 * 1 Actual/actual
446 * 2 Actual/360
447 * 3 Actual/365
448 * 4 European 30/360
449 * @return float
450 */
451 public static function COUPDAYBS($settlement, $maturity, $frequency, $basis=0) {
452 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
453 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
454 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
455 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
456
457 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
458 return PHPExcel_Calculation_Functions::VALUE();
459 }
460 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
461 return PHPExcel_Calculation_Functions::VALUE();
462 }
463
464 if (($settlement > $maturity) ||
465 (!self::_validFrequency($frequency)) ||
466 (($basis < 0) || ($basis > 4))) {
467 return PHPExcel_Calculation_Functions::NaN();
468 }
469
470 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis);
471 $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False);
472
473 return PHPExcel_Calculation_DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear;
474 } // function COUPDAYBS()
475
476
477 /**
478 * COUPDAYS
479 *
480 * Returns the number of days in the coupon period that contains the settlement date.
481 *
482 * Excel Function:
483 * COUPDAYS(settlement,maturity,frequency[,basis])
484 *
485 * @access public
486 * @category Financial Functions
487 * @param mixed settlement The security's settlement date.
488 * The security settlement date is the date after the issue
489 * date when the security is traded to the buyer.
490 * @param mixed maturity The security's maturity date.
491 * The maturity date is the date when the security expires.
492 * @param mixed frequency the number of coupon payments per year.
493 * Valid frequency values are:
494 * 1 Annual
495 * 2 Semi-Annual
496 * 4 Quarterly
497 * If working in Gnumeric Mode, the following frequency options are
498 * also available
499 * 6 Bimonthly
500 * 12 Monthly
501 * @param integer basis The type of day count to use.
502 * 0 or omitted US (NASD) 30/360
503 * 1 Actual/actual
504 * 2 Actual/360
505 * 3 Actual/365
506 * 4 European 30/360
507 * @return float
508 */
509 public static function COUPDAYS($settlement, $maturity, $frequency, $basis=0) {
510 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
511 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
512 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
513 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
514
515 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
516 return PHPExcel_Calculation_Functions::VALUE();
517 }
518 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
519 return PHPExcel_Calculation_Functions::VALUE();
520 }
521
522 if (($settlement > $maturity) ||
523 (!self::_validFrequency($frequency)) ||
524 (($basis < 0) || ($basis > 4))) {
525 return PHPExcel_Calculation_Functions::NaN();
526 }
527
528 switch ($basis) {
529 case 3: // Actual/365
530 return 365 / $frequency;
531 case 1: // Actual/actual
532 if ($frequency == 1) {
533 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($maturity),$basis);
534 return ($daysPerYear / $frequency);
535 } else {
536 $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False);
537 $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True);
538 return ($next - $prev);
539 }
540 default: // US (NASD) 30/360, Actual/360 or European 30/360
541 return 360 / $frequency;
542 }
543 return PHPExcel_Calculation_Functions::VALUE();
544 } // function COUPDAYS()
545
546
547 /**
548 * COUPDAYSNC
549 *
550 * Returns the number of days from the settlement date to the next coupon date.
551 *
552 * Excel Function:
553 * COUPDAYSNC(settlement,maturity,frequency[,basis])
554 *
555 * @access public
556 * @category Financial Functions
557 * @param mixed settlement The security's settlement date.
558 * The security settlement date is the date after the issue
559 * date when the security is traded to the buyer.
560 * @param mixed maturity The security's maturity date.
561 * The maturity date is the date when the security expires.
562 * @param mixed frequency the number of coupon payments per year.
563 * Valid frequency values are:
564 * 1 Annual
565 * 2 Semi-Annual
566 * 4 Quarterly
567 * If working in Gnumeric Mode, the following frequency options are
568 * also available
569 * 6 Bimonthly
570 * 12 Monthly
571 * @param integer basis The type of day count to use.
572 * 0 or omitted US (NASD) 30/360
573 * 1 Actual/actual
574 * 2 Actual/360
575 * 3 Actual/365
576 * 4 European 30/360
577 * @return float
578 */
579 public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis=0) {
580 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
581 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
582 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
583 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
584
585 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
586 return PHPExcel_Calculation_Functions::VALUE();
587 }
588 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
589 return PHPExcel_Calculation_Functions::VALUE();
590 }
591
592 if (($settlement > $maturity) ||
593 (!self::_validFrequency($frequency)) ||
594 (($basis < 0) || ($basis > 4))) {
595 return PHPExcel_Calculation_Functions::NaN();
596 }
597
598 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis);
599 $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True);
600
601 return PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear;
602 } // function COUPDAYSNC()
603
604
605 /**
606 * COUPNCD
607 *
608 * Returns the next coupon date after the settlement date.
609 *
610 * Excel Function:
611 * COUPNCD(settlement,maturity,frequency[,basis])
612 *
613 * @access public
614 * @category Financial Functions
615 * @param mixed settlement The security's settlement date.
616 * The security settlement date is the date after the issue
617 * date when the security is traded to the buyer.
618 * @param mixed maturity The security's maturity date.
619 * The maturity date is the date when the security expires.
620 * @param mixed frequency the number of coupon payments per year.
621 * Valid frequency values are:
622 * 1 Annual
623 * 2 Semi-Annual
624 * 4 Quarterly
625 * If working in Gnumeric Mode, the following frequency options are
626 * also available
627 * 6 Bimonthly
628 * 12 Monthly
629 * @param integer basis The type of day count to use.
630 * 0 or omitted US (NASD) 30/360
631 * 1 Actual/actual
632 * 2 Actual/360
633 * 3 Actual/365
634 * 4 European 30/360
635 * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
636 * depending on the value of the ReturnDateType flag
637 */
638 public static function COUPNCD($settlement, $maturity, $frequency, $basis=0) {
639 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
640 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
641 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
642 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
643
644 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
645 return PHPExcel_Calculation_Functions::VALUE();
646 }
647 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
648 return PHPExcel_Calculation_Functions::VALUE();
649 }
650
651 if (($settlement > $maturity) ||
652 (!self::_validFrequency($frequency)) ||
653 (($basis < 0) || ($basis > 4))) {
654 return PHPExcel_Calculation_Functions::NaN();
655 }
656
657 return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True);
658 } // function COUPNCD()
659
660
661 /**
662 * COUPNUM
663 *
664 * Returns the number of coupons payable between the settlement date and maturity date,
665 * rounded up to the nearest whole coupon.
666 *
667 * Excel Function:
668 * COUPNUM(settlement,maturity,frequency[,basis])
669 *
670 * @access public
671 * @category Financial Functions
672 * @param mixed settlement The security's settlement date.
673 * The security settlement date is the date after the issue
674 * date when the security is traded to the buyer.
675 * @param mixed maturity The security's maturity date.
676 * The maturity date is the date when the security expires.
677 * @param mixed frequency the number of coupon payments per year.
678 * Valid frequency values are:
679 * 1 Annual
680 * 2 Semi-Annual
681 * 4 Quarterly
682 * If working in Gnumeric Mode, the following frequency options are
683 * also available
684 * 6 Bimonthly
685 * 12 Monthly
686 * @param integer basis The type of day count to use.
687 * 0 or omitted US (NASD) 30/360
688 * 1 Actual/actual
689 * 2 Actual/360
690 * 3 Actual/365
691 * 4 European 30/360
692 * @return integer
693 */
694 public static function COUPNUM($settlement, $maturity, $frequency, $basis=0) {
695 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
696 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
697 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
698 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
699
700 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
701 return PHPExcel_Calculation_Functions::VALUE();
702 }
703 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
704 return PHPExcel_Calculation_Functions::VALUE();
705 }
706
707 if (($settlement > $maturity) ||
708 (!self::_validFrequency($frequency)) ||
709 (($basis < 0) || ($basis > 4))) {
710 return PHPExcel_Calculation_Functions::NaN();
711 }
712
713 $settlement = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True);
714 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis) * 365;
715
716 switch ($frequency) {
717 case 1: // annual payments
718 return ceil($daysBetweenSettlementAndMaturity / 360);
719 case 2: // half-yearly
720 return ceil($daysBetweenSettlementAndMaturity / 180);
721 case 4: // quarterly
722 return ceil($daysBetweenSettlementAndMaturity / 90);
723 case 6: // bimonthly
724 return ceil($daysBetweenSettlementAndMaturity / 60);
725 case 12: // monthly
726 return ceil($daysBetweenSettlementAndMaturity / 30);
727 }
728 return PHPExcel_Calculation_Functions::VALUE();
729 } // function COUPNUM()
730
731
732 /**
733 * COUPPCD
734 *
735 * Returns the previous coupon date before the settlement date.
736 *
737 * Excel Function:
738 * COUPPCD(settlement,maturity,frequency[,basis])
739 *
740 * @access public
741 * @category Financial Functions
742 * @param mixed settlement The security's settlement date.
743 * The security settlement date is the date after the issue
744 * date when the security is traded to the buyer.
745 * @param mixed maturity The security's maturity date.
746 * The maturity date is the date when the security expires.
747 * @param mixed frequency the number of coupon payments per year.
748 * Valid frequency values are:
749 * 1 Annual
750 * 2 Semi-Annual
751 * 4 Quarterly
752 * If working in Gnumeric Mode, the following frequency options are
753 * also available
754 * 6 Bimonthly
755 * 12 Monthly
756 * @param integer basis The type of day count to use.
757 * 0 or omitted US (NASD) 30/360
758 * 1 Actual/actual
759 * 2 Actual/360
760 * 3 Actual/365
761 * 4 European 30/360
762 * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
763 * depending on the value of the ReturnDateType flag
764 */
765 public static function COUPPCD($settlement, $maturity, $frequency, $basis=0) {
766 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
767 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
768 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
769 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
770
771 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
772 return PHPExcel_Calculation_Functions::VALUE();
773 }
774 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
775 return PHPExcel_Calculation_Functions::VALUE();
776 }
777
778 if (($settlement > $maturity) ||
779 (!self::_validFrequency($frequency)) ||
780 (($basis < 0) || ($basis > 4))) {
781 return PHPExcel_Calculation_Functions::NaN();
782 }
783
784 return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False);
785 } // function COUPPCD()
786
787
788 /**
789 * CUMIPMT
790 *
791 * Returns the cumulative interest paid on a loan between the start and end periods.
792 *
793 * Excel Function:
794 * CUMIPMT(rate,nper,pv,start,end[,type])
795 *
796 * @access public
797 * @category Financial Functions
798 * @param float $rate The Interest rate
799 * @param integer $nper The total number of payment periods
800 * @param float $pv Present Value
801 * @param integer $start The first period in the calculation.
802 * Payment periods are numbered beginning with 1.
803 * @param integer $end The last period in the calculation.
804 * @param integer $type A number 0 or 1 and indicates when payments are due:
805 * 0 or omitted At the end of the period.
806 * 1 At the beginning of the period.
807 * @return float
808 */
809 public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0) {
810 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
811 $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
812 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
813 $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start);
814 $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end);
815 $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
816
817 // Validate parameters
818 if ($type != 0 && $type != 1) {
819 return PHPExcel_Calculation_Functions::NaN();
820 }
821 if ($start < 1 || $start > $end) {
822 return PHPExcel_Calculation_Functions::VALUE();
823 }
824
825 // Calculate
826 $interest = 0;
827 for ($per = $start; $per <= $end; ++$per) {
828 $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type);
829 }
830
831 return $interest;
832 } // function CUMIPMT()
833
834
835 /**
836 * CUMPRINC
837 *
838 * Returns the cumulative principal paid on a loan between the start and end periods.
839 *
840 * Excel Function:
841 * CUMPRINC(rate,nper,pv,start,end[,type])
842 *
843 * @access public
844 * @category Financial Functions
845 * @param float $rate The Interest rate
846 * @param integer $nper The total number of payment periods
847 * @param float $pv Present Value
848 * @param integer $start The first period in the calculation.
849 * Payment periods are numbered beginning with 1.
850 * @param integer $end The last period in the calculation.
851 * @param integer $type A number 0 or 1 and indicates when payments are due:
852 * 0 or omitted At the end of the period.
853 * 1 At the beginning of the period.
854 * @return float
855 */
856 public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0) {
857 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
858 $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
859 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
860 $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start);
861 $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end);
862 $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
863
864 // Validate parameters
865 if ($type != 0 && $type != 1) {
866 return PHPExcel_Calculation_Functions::NaN();
867 }
868 if ($start < 1 || $start > $end) {
869 return PHPExcel_Calculation_Functions::VALUE();
870 }
871
872 // Calculate
873 $principal = 0;
874 for ($per = $start; $per <= $end; ++$per) {
875 $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type);
876 }
877
878 return $principal;
879 } // function CUMPRINC()
880
881
882 /**
883 * DB
884 *
885 * Returns the depreciation of an asset for a specified period using the
886 * fixed-declining balance method.
887 * This form of depreciation is used if you want to get a higher depreciation value
888 * at the beginning of the depreciation (as opposed to linear depreciation). The
889 * depreciation value is reduced with every depreciation period by the depreciation
890 * already deducted from the initial cost.
891 *
892 * Excel Function:
893 * DB(cost,salvage,life,period[,month])
894 *
895 * @access public
896 * @category Financial Functions
897 * @param float cost Initial cost of the asset.
898 * @param float salvage Value at the end of the depreciation.
899 * (Sometimes called the salvage value of the asset)
900 * @param integer life Number of periods over which the asset is depreciated.
901 * (Sometimes called the useful life of the asset)
902 * @param integer period The period for which you want to calculate the
903 * depreciation. Period must use the same units as life.
904 * @param integer month Number of months in the first year. If month is omitted,
905 * it defaults to 12.
906 * @return float
907 */
908 public static function DB($cost, $salvage, $life, $period, $month=12) {
909 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
910 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
911 $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
912 $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
913 $month = PHPExcel_Calculation_Functions::flattenSingleValue($month);
914
915 // Validate
916 if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
917 $cost = (float) $cost;
918 $salvage = (float) $salvage;
919 $life = (int) $life;
920 $period = (int) $period;
921 $month = (int) $month;
922 if ($cost == 0) {
923 return 0.0;
924 } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) {
925 return PHPExcel_Calculation_Functions::NaN();
926 }
927 // Set Fixed Depreciation Rate
928 $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
929 $fixedDepreciationRate = round($fixedDepreciationRate, 3);
930
931 // Loop through each period calculating the depreciation
932 $previousDepreciation = 0;
933 for ($per = 1; $per <= $period; ++$per) {
934 if ($per == 1) {
935 $depreciation = $cost * $fixedDepreciationRate * $month / 12;
936 } elseif ($per == ($life + 1)) {
937 $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12;
938 } else {
939 $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate;
940 }
941 $previousDepreciation += $depreciation;
942 }
943 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
944 $depreciation = round($depreciation,2);
945 }
946 return $depreciation;
947 }
948 return PHPExcel_Calculation_Functions::VALUE();
949 } // function DB()
950
951
952 /**
953 * DDB
954 *
955 * Returns the depreciation of an asset for a specified period using the
956 * double-declining balance method or some other method you specify.
957 *
958 * Excel Function:
959 * DDB(cost,salvage,life,period[,factor])
960 *
961 * @access public
962 * @category Financial Functions
963 * @param float cost Initial cost of the asset.
964 * @param float salvage Value at the end of the depreciation.
965 * (Sometimes called the salvage value of the asset)
966 * @param integer life Number of periods over which the asset is depreciated.
967 * (Sometimes called the useful life of the asset)
968 * @param integer period The period for which you want to calculate the
969 * depreciation. Period must use the same units as life.
970 * @param float factor The rate at which the balance declines.
971 * If factor is omitted, it is assumed to be 2 (the
972 * double-declining balance method).
973 * @return float
974 */
975 public static function DDB($cost, $salvage, $life, $period, $factor=2.0) {
976 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
977 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
978 $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
979 $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
980 $factor = PHPExcel_Calculation_Functions::flattenSingleValue($factor);
981
982 // Validate
983 if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
984 $cost = (float) $cost;
985 $salvage = (float) $salvage;
986 $life = (int) $life;
987 $period = (int) $period;
988 $factor = (float) $factor;
989 if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) {
990 return PHPExcel_Calculation_Functions::NaN();
991 }
992 // Set Fixed Depreciation Rate
993 $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
994 $fixedDepreciationRate = round($fixedDepreciationRate, 3);
995
996 // Loop through each period calculating the depreciation
997 $previousDepreciation = 0;
998 for ($per = 1; $per <= $period; ++$per) {
999 $depreciation = min( ($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation) );
1000 $previousDepreciation += $depreciation;
1001 }
1002 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1003 $depreciation = round($depreciation,2);
1004 }
1005 return $depreciation;
1006 }
1007 return PHPExcel_Calculation_Functions::VALUE();
1008 } // function DDB()
1009
1010
1011 /**
1012 * DISC
1013 *
1014 * Returns the discount rate for a security.
1015 *
1016 * Excel Function:
1017 * DISC(settlement,maturity,price,redemption[,basis])
1018 *
1019 * @access public
1020 * @category Financial Functions
1021 * @param mixed settlement The security's settlement date.
1022 * The security settlement date is the date after the issue
1023 * date when the security is traded to the buyer.
1024 * @param mixed maturity The security's maturity date.
1025 * The maturity date is the date when the security expires.
1026 * @param integer price The security's price per $100 face value.
1027 * @param integer redemption The security's redemption value per $100 face value.
1028 * @param integer basis The type of day count to use.
1029 * 0 or omitted US (NASD) 30/360
1030 * 1 Actual/actual
1031 * 2 Actual/360
1032 * 3 Actual/365
1033 * 4 European 30/360
1034 * @return float
1035 */
1036 public static function DISC($settlement, $maturity, $price, $redemption, $basis=0) {
1037 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1038 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1039 $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
1040 $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
1041 $basis = PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1042
1043 // Validate
1044 if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
1045 $price = (float) $price;
1046 $redemption = (float) $redemption;
1047 $basis = (int) $basis;
1048 if (($price <= 0) || ($redemption <= 0)) {
1049 return PHPExcel_Calculation_Functions::NaN();
1050 }
1051 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
1052 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
1053 // return date error
1054 return $daysBetweenSettlementAndMaturity;
1055 }
1056
1057 return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity);
1058 }
1059 return PHPExcel_Calculation_Functions::VALUE();
1060 } // function DISC()
1061
1062
1063 /**
1064 * DOLLARDE
1065 *
1066 * Converts a dollar price expressed as an integer part and a fraction
1067 * part into a dollar price expressed as a decimal number.
1068 * Fractional dollar numbers are sometimes used for security prices.
1069 *
1070 * Excel Function:
1071 * DOLLARDE(fractional_dollar,fraction)
1072 *
1073 * @access public
1074 * @category Financial Functions
1075 * @param float $fractional_dollar Fractional Dollar
1076 * @param integer $fraction Fraction
1077 * @return float
1078 */
1079 public static function DOLLARDE($fractional_dollar = Null, $fraction = 0) {
1080 $fractional_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($fractional_dollar);
1081 $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction);
1082
1083 // Validate parameters
1084 if (is_null($fractional_dollar) || $fraction < 0) {
1085 return PHPExcel_Calculation_Functions::NaN();
1086 }
1087 if ($fraction == 0) {
1088 return PHPExcel_Calculation_Functions::DIV0();
1089 }
1090
1091 $dollars = floor($fractional_dollar);
1092 $cents = fmod($fractional_dollar,1);
1093 $cents /= $fraction;
1094 $cents *= pow(10,ceil(log10($fraction)));
1095 return $dollars + $cents;
1096 } // function DOLLARDE()
1097
1098
1099 /**
1100 * DOLLARFR
1101 *
1102 * Converts a dollar price expressed as a decimal number into a dollar price
1103 * expressed as a fraction.
1104 * Fractional dollar numbers are sometimes used for security prices.
1105 *
1106 * Excel Function:
1107 * DOLLARFR(decimal_dollar,fraction)
1108 *
1109 * @access public
1110 * @category Financial Functions
1111 * @param float $decimal_dollar Decimal Dollar
1112 * @param integer $fraction Fraction
1113 * @return float
1114 */
1115 public static function DOLLARFR($decimal_dollar = Null, $fraction = 0) {
1116 $decimal_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($decimal_dollar);
1117 $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction);
1118
1119 // Validate parameters
1120 if (is_null($decimal_dollar) || $fraction < 0) {
1121 return PHPExcel_Calculation_Functions::NaN();
1122 }
1123 if ($fraction == 0) {
1124 return PHPExcel_Calculation_Functions::DIV0();
1125 }
1126
1127 $dollars = floor($decimal_dollar);
1128 $cents = fmod($decimal_dollar,1);
1129 $cents *= $fraction;
1130 $cents *= pow(10,-ceil(log10($fraction)));
1131 return $dollars + $cents;
1132 } // function DOLLARFR()
1133
1134
1135 /**
1136 * EFFECT
1137 *
1138 * Returns the effective interest rate given the nominal rate and the number of
1139 * compounding payments per year.
1140 *
1141 * Excel Function:
1142 * EFFECT(nominal_rate,npery)
1143 *
1144 * @access public
1145 * @category Financial Functions
1146 * @param float $nominal_rate Nominal interest rate
1147 * @param integer $npery Number of compounding payments per year
1148 * @return float
1149 */
1150 public static function EFFECT($nominal_rate = 0, $npery = 0) {
1151 $nominal_rate = PHPExcel_Calculation_Functions::flattenSingleValue($nominal_rate);
1152 $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery);
1153
1154 // Validate parameters
1155 if ($nominal_rate <= 0 || $npery < 1) {
1156 return PHPExcel_Calculation_Functions::NaN();
1157 }
1158
1159 return pow((1 + $nominal_rate / $npery), $npery) - 1;
1160 } // function EFFECT()
1161
1162
1163 /**
1164 * FV
1165 *
1166 * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
1167 *
1168 * Excel Function:
1169 * FV(rate,nper,pmt[,pv[,type]])
1170 *
1171 * @access public
1172 * @category Financial Functions
1173 * @param float $rate The interest rate per period
1174 * @param int $nper Total number of payment periods in an annuity
1175 * @param float $pmt The payment made each period: it cannot change over the
1176 * life of the annuity. Typically, pmt contains principal
1177 * and interest but no other fees or taxes.
1178 * @param float $pv Present Value, or the lump-sum amount that a series of
1179 * future payments is worth right now.
1180 * @param integer $type A number 0 or 1 and indicates when payments are due:
1181 * 0 or omitted At the end of the period.
1182 * 1 At the beginning of the period.
1183 * @return float
1184 */
1185 public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0) {
1186 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1187 $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1188 $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
1189 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1190 $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
1191
1192 // Validate parameters
1193 if ($type != 0 && $type != 1) {
1194 return PHPExcel_Calculation_Functions::NaN();
1195 }
1196
1197 // Calculate
1198 if (!is_null($rate) && $rate != 0) {
1199 return -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate;
1200 } else {
1201 return -$pv - $pmt * $nper;
1202 }
1203 } // function FV()
1204
1205
1206 /**
1207 * FVSCHEDULE
1208 *
1209 * Returns the future value of an initial principal after applying a series of compound interest rates.
1210 * Use FVSCHEDULE to calculate the future value of an investment with a variable or adjustable rate.
1211 *
1212 * Excel Function:
1213 * FVSCHEDULE(principal,schedule)
1214 *
1215 * @param float $principal The present value.
1216 * @param float[] $schedule An array of interest rates to apply.
1217 * @return float
1218 */
1219 public static function FVSCHEDULE($principal, $schedule) {
1220 $principal = PHPExcel_Calculation_Functions::flattenSingleValue($principal);
1221 $schedule = PHPExcel_Calculation_Functions::flattenArray($schedule);
1222
1223 foreach($schedule as $rate) {
1224 $principal *= 1 + $rate;
1225 }
1226
1227 return $principal;
1228 } // function FVSCHEDULE()
1229
1230
1231 /**
1232 * INTRATE
1233 *
1234 * Returns the interest rate for a fully invested security.
1235 *
1236 * Excel Function:
1237 * INTRATE(settlement,maturity,investment,redemption[,basis])
1238 *
1239 * @param mixed $settlement The security's settlement date.
1240 * The security settlement date is the date after the issue date when the security is traded to the buyer.
1241 * @param mixed $maturity The security's maturity date.
1242 * The maturity date is the date when the security expires.
1243 * @param integer $investment The amount invested in the security.
1244 * @param integer $redemption The amount to be received at maturity.
1245 * @param integer $basis The type of day count to use.
1246 * 0 or omitted US (NASD) 30/360
1247 * 1 Actual/actual
1248 * 2 Actual/360
1249 * 3 Actual/365
1250 * 4 European 30/360
1251 * @return float
1252 */
1253 public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis=0) {
1254 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1255 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1256 $investment = PHPExcel_Calculation_Functions::flattenSingleValue($investment);
1257 $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
1258 $basis = PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1259
1260 // Validate
1261 if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
1262 $investment = (float) $investment;
1263 $redemption = (float) $redemption;
1264 $basis = (int) $basis;
1265 if (($investment <= 0) || ($redemption <= 0)) {
1266 return PHPExcel_Calculation_Functions::NaN();
1267 }
1268 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
1269 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
1270 // return date error
1271 return $daysBetweenSettlementAndMaturity;
1272 }
1273
1274 return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity);
1275 }
1276 return PHPExcel_Calculation_Functions::VALUE();
1277 } // function INTRATE()
1278
1279
1280 /**
1281 * IPMT
1282 *
1283 * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
1284 *
1285 * Excel Function:
1286 * IPMT(rate,per,nper,pv[,fv][,type])
1287 *
1288 * @param float $rate Interest rate per period
1289 * @param int $per Period for which we want to find the interest
1290 * @param int $nper Number of periods
1291 * @param float $pv Present Value
1292 * @param float $fv Future Value
1293 * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
1294 * @return float
1295 */
1296 public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) {
1297 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1298 $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per);
1299 $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1300 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1301 $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1302 $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
1303
1304 // Validate parameters
1305 if ($type != 0 && $type != 1) {
1306 return PHPExcel_Calculation_Functions::NaN();
1307 }
1308 if ($per <= 0 || $per > $nper) {
1309 return PHPExcel_Calculation_Functions::VALUE();
1310 }
1311
1312 // Calculate
1313 $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
1314 return $interestAndPrincipal[0];
1315 } // function IPMT()
1316
1317 /**
1318 * IRR
1319 *
1320 * Returns the internal rate of return for a series of cash flows represented by the numbers in values.
1321 * These cash flows do not have to be even, as they would be for an annuity. However, the cash flows must occur
1322 * at regular intervals, such as monthly or annually. The internal rate of return is the interest rate received
1323 * for an investment consisting of payments (negative values) and income (positive values) that occur at regular
1324 * periods.
1325 *
1326 * Excel Function:
1327 * IRR(values[,guess])
1328 *
1329 * @param float[] $values An array or a reference to cells that contain numbers for which you want
1330 * to calculate the internal rate of return.
1331 * Values must contain at least one positive value and one negative value to
1332 * calculate the internal rate of return.
1333 * @param float $guess A number that you guess is close to the result of IRR
1334 * @return float
1335 */
1336 public static function IRR($values, $guess = 0.1) {
1337 if (!is_array($values)) return PHPExcel_Calculation_Functions::VALUE();
1338 $values = PHPExcel_Calculation_Functions::flattenArray($values);
1339 $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess);
1340
1341 // create an initial range, with a root somewhere between 0 and guess
1342 $x1 = 0.0;
1343 $x2 = $guess;
1344 $f1 = self::NPV($x1, $values);
1345 $f2 = self::NPV($x2, $values);
1346 for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
1347 if (($f1 * $f2) < 0.0) break;
1348 if (abs($f1) < abs($f2)) {
1349 $f1 = self::NPV($x1 += 1.6 * ($x1 - $x2), $values);
1350 } else {
1351 $f2 = self::NPV($x2 += 1.6 * ($x2 - $x1), $values);
1352 }
1353 }
1354 if (($f1 * $f2) > 0.0) return PHPExcel_Calculation_Functions::VALUE();
1355
1356 $f = self::NPV($x1, $values);
1357 if ($f < 0.0) {
1358 $rtb = $x1;
1359 $dx = $x2 - $x1;
1360 } else {
1361 $rtb = $x2;
1362 $dx = $x1 - $x2;
1363 }
1364
1365 for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
1366 $dx *= 0.5;
1367 $x_mid = $rtb + $dx;
1368 $f_mid = self::NPV($x_mid, $values);
1369 if ($f_mid <= 0.0)
1370 $rtb = $x_mid;
1371 if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION))
1372 return $x_mid;
1373 }
1374 return PHPExcel_Calculation_Functions::VALUE();
1375 } // function IRR()
1376
1377
1378 /**
1379 * ISPMT
1380 *
1381 * Returns the interest payment for an investment based on an interest rate and a constant payment schedule.
1382 *
1383 * Excel Function:
1384 * =ISPMT(interest_rate, period, number_payments, PV)
1385 *
1386 * interest_rate is the interest rate for the investment
1387 *
1388 * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments.
1389 *
1390 * number_payments is the number of payments for the annuity
1391 *
1392 * PV is the loan amount or present value of the payments
1393 */
1394 public static function ISPMT() {
1395 // Return value
1396 $returnValue = 0;
1397
1398 // Get the parameters
1399 $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
1400 $interestRate = array_shift($aArgs);
1401 $period = array_shift($aArgs);
1402 $numberPeriods = array_shift($aArgs);
1403 $principleRemaining = array_shift($aArgs);
1404
1405 // Calculate
1406 $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0);
1407 for($i=0; $i <= $period; ++$i) {
1408 $returnValue = $interestRate * $principleRemaining * -1;
1409 $principleRemaining -= $principlePayment;
1410 // principle needs to be 0 after the last payment, don't let floating point screw it up
1411 if($i == $numberPeriods) {
1412 $returnValue = 0;
1413 }
1414 }
1415 return($returnValue);
1416 } // function ISPMT()
1417
1418
1419 /**
1420 * MIRR
1421 *
1422 * Returns the modified internal rate of return for a series of periodic cash flows. MIRR considers both
1423 * the cost of the investment and the interest received on reinvestment of cash.
1424 *
1425 * Excel Function:
1426 * MIRR(values,finance_rate, reinvestment_rate)
1427 *
1428 * @param float[] $values An array or a reference to cells that contain a series of payments and
1429 * income occurring at regular intervals.
1430 * Payments are negative value, income is positive values.
1431 * @param float $finance_rate The interest rate you pay on the money used in the cash flows
1432 * @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them
1433 * @return float
1434 */
1435 public static function MIRR($values, $finance_rate, $reinvestment_rate) {
1436 if (!is_array($values)) return PHPExcel_Calculation_Functions::VALUE();
1437 $values = PHPExcel_Calculation_Functions::flattenArray($values);
1438 $finance_rate = PHPExcel_Calculation_Functions::flattenSingleValue($finance_rate);
1439 $reinvestment_rate = PHPExcel_Calculation_Functions::flattenSingleValue($reinvestment_rate);
1440 $n = count($values);
1441
1442 $rr = 1.0 + $reinvestment_rate;
1443 $fr = 1.0 + $finance_rate;
1444
1445 $npv_pos = $npv_neg = 0.0;
1446 foreach($values as $i => $v) {
1447 if ($v >= 0) {
1448 $npv_pos += $v / pow($rr, $i);
1449 } else {
1450 $npv_neg += $v / pow($fr, $i);
1451 }
1452 }
1453
1454 if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= -1)) {
1455 return PHPExcel_Calculation_Functions::VALUE();
1456 }
1457
1458 $mirr = pow((-$npv_pos * pow($rr, $n))
1459 / ($npv_neg * ($rr)), (1.0 / ($n - 1))) - 1.0;
1460
1461 return (is_finite($mirr) ? $mirr : PHPExcel_Calculation_Functions::VALUE());
1462 } // function MIRR()
1463
1464
1465 /**
1466 * NOMINAL
1467 *
1468 * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
1469 *
1470 * @param float $effect_rate Effective interest rate
1471 * @param int $npery Number of compounding payments per year
1472 * @return float
1473 */
1474 public static function NOMINAL($effect_rate = 0, $npery = 0) {
1475 $effect_rate = PHPExcel_Calculation_Functions::flattenSingleValue($effect_rate);
1476 $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery);
1477
1478 // Validate parameters
1479 if ($effect_rate <= 0 || $npery < 1) {
1480 return PHPExcel_Calculation_Functions::NaN();
1481 }
1482
1483 // Calculate
1484 return $npery * (pow($effect_rate + 1, 1 / $npery) - 1);
1485 } // function NOMINAL()
1486
1487
1488 /**
1489 * NPER
1490 *
1491 * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
1492 *
1493 * @param float $rate Interest rate per period
1494 * @param int $pmt Periodic payment (annuity)
1495 * @param float $pv Present Value
1496 * @param float $fv Future Value
1497 * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
1498 * @return float
1499 */
1500 public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0) {
1501 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1502 $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
1503 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1504 $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1505 $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
1506
1507 // Validate parameters
1508 if ($type != 0 && $type != 1) {
1509 return PHPExcel_Calculation_Functions::NaN();
1510 }
1511
1512 // Calculate
1513 if (!is_null($rate) && $rate != 0) {
1514 if ($pmt == 0 && $pv == 0) {
1515 return PHPExcel_Calculation_Functions::NaN();
1516 }
1517 return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate);
1518 } else {
1519 if ($pmt == 0) {
1520 return PHPExcel_Calculation_Functions::NaN();
1521 }
1522 return (-$pv -$fv) / $pmt;
1523 }
1524 } // function NPER()
1525
1526 /**
1527 * NPV
1528 *
1529 * Returns the Net Present Value of a cash flow series given a discount rate.
1530 *
1531 * @return float
1532 */
1533 public static function NPV() {
1534 // Return value
1535 $returnValue = 0;
1536
1537 // Loop through arguments
1538 $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
1539
1540 // Calculate
1541 $rate = array_shift($aArgs);
1542 for ($i = 1; $i <= count($aArgs); ++$i) {
1543 // Is it a numeric value?
1544 if (is_numeric($aArgs[$i - 1])) {
1545 $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i);
1546 }
1547 }
1548
1549 // Return
1550 return $returnValue;
1551 } // function NPV()
1552
1553 /**
1554 * PMT
1555 *
1556 * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
1557 *
1558 * @param float $rate Interest rate per period
1559 * @param int $nper Number of periods
1560 * @param float $pv Present Value
1561 * @param float $fv Future Value
1562 * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
1563 * @return float
1564 */
1565 public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) {
1566 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1567 $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1568 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1569 $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1570 $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
1571
1572 // Validate parameters
1573 if ($type != 0 && $type != 1) {
1574 return PHPExcel_Calculation_Functions::NaN();
1575 }
1576
1577 // Calculate
1578 if (!is_null($rate) && $rate != 0) {
1579 return (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate);
1580 } else {
1581 return (-$pv - $fv) / $nper;
1582 }
1583 } // function PMT()
1584
1585
1586 /**
1587 * PPMT
1588 *
1589 * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
1590 *
1591 * @param float $rate Interest rate per period
1592 * @param int $per Period for which we want to find the interest
1593 * @param int $nper Number of periods
1594 * @param float $pv Present Value
1595 * @param float $fv Future Value
1596 * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
1597 * @return float
1598 */
1599 public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) {
1600 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1601 $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per);
1602 $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1603 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1604 $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1605 $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
1606
1607 // Validate parameters
1608 if ($type != 0 && $type != 1) {
1609 return PHPExcel_Calculation_Functions::NaN();
1610 }
1611 if ($per <= 0 || $per > $nper) {
1612 return PHPExcel_Calculation_Functions::VALUE();
1613 }
1614
1615 // Calculate
1616 $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
1617 return $interestAndPrincipal[1];
1618 } // function PPMT()
1619
1620
1621 public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis=0) {
1622 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1623 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1624 $rate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1625 $yield = (float) PHPExcel_Calculation_Functions::flattenSingleValue($yield);
1626 $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
1627 $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
1628 $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1629
1630 if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) {
1631 return PHPExcel_Calculation_Functions::VALUE();
1632 }
1633 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
1634 return PHPExcel_Calculation_Functions::VALUE();
1635 }
1636
1637 if (($settlement > $maturity) ||
1638 (!self::_validFrequency($frequency)) ||
1639 (($basis < 0) || ($basis > 4))) {
1640 return PHPExcel_Calculation_Functions::NaN();
1641 }
1642
1643 $dsc = self::COUPDAYSNC($settlement, $maturity, $frequency, $basis);
1644 $e = self::COUPDAYS($settlement, $maturity, $frequency, $basis);
1645 $n = self::COUPNUM($settlement, $maturity, $frequency, $basis);
1646 $a = self::COUPDAYBS($settlement, $maturity, $frequency, $basis);
1647
1648 $baseYF = 1.0 + ($yield / $frequency);
1649 $rfp = 100 * ($rate / $frequency);
1650 $de = $dsc / $e;
1651
1652 $result = $redemption / pow($baseYF, (--$n + $de));
1653 for($k = 0; $k <= $n; ++$k) {
1654 $result += $rfp / (pow($baseYF, ($k + $de)));
1655 }
1656 $result -= $rfp * ($a / $e);
1657
1658 return $result;
1659 } // function PRICE()
1660
1661
1662 /**
1663 * PRICEDISC
1664 *
1665 * Returns the price per $100 face value of a discounted security.
1666 *
1667 * @param mixed settlement The security's settlement date.
1668 * The security settlement date is the date after the issue date when the security is traded to the buyer.
1669 * @param mixed maturity The security's maturity date.
1670 * The maturity date is the date when the security expires.
1671 * @param int discount The security's discount rate.
1672 * @param int redemption The security's redemption value per $100 face value.
1673 * @param int basis The type of day count to use.
1674 * 0 or omitted US (NASD) 30/360
1675 * 1 Actual/actual
1676 * 2 Actual/360
1677 * 3 Actual/365
1678 * 4 European 30/360
1679 * @return float
1680 */
1681 public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis=0) {
1682 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1683 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1684 $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount);
1685 $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
1686 $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1687
1688 // Validate
1689 if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
1690 if (($discount <= 0) || ($redemption <= 0)) {
1691 return PHPExcel_Calculation_Functions::NaN();
1692 }
1693 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
1694 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
1695 // return date error
1696 return $daysBetweenSettlementAndMaturity;
1697 }
1698
1699 return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity);
1700 }
1701 return PHPExcel_Calculation_Functions::VALUE();
1702 } // function PRICEDISC()
1703
1704
1705 /**
1706 * PRICEMAT
1707 *
1708 * Returns the price per $100 face value of a security that pays interest at maturity.
1709 *
1710 * @param mixed settlement The security's settlement date.
1711 * The security's settlement date is the date after the issue date when the security is traded to the buyer.
1712 * @param mixed maturity The security's maturity date.
1713 * The maturity date is the date when the security expires.
1714 * @param mixed issue The security's issue date.
1715 * @param int rate The security's interest rate at date of issue.
1716 * @param int yield The security's annual yield.
1717 * @param int basis The type of day count to use.
1718 * 0 or omitted US (NASD) 30/360
1719 * 1 Actual/actual
1720 * 2 Actual/360
1721 * 3 Actual/365
1722 * 4 European 30/360
1723 * @return float
1724 */
1725 public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis=0) {
1726 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1727 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1728 $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
1729 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1730 $yield = PHPExcel_Calculation_Functions::flattenSingleValue($yield);
1731 $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1732
1733 // Validate
1734 if (is_numeric($rate) && is_numeric($yield)) {
1735 if (($rate <= 0) || ($yield <= 0)) {
1736 return PHPExcel_Calculation_Functions::NaN();
1737 }
1738 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis);
1739 if (!is_numeric($daysPerYear)) {
1740 return $daysPerYear;
1741 }
1742 $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
1743 if (!is_numeric($daysBetweenIssueAndSettlement)) {
1744 // return date error
1745 return $daysBetweenIssueAndSettlement;
1746 }
1747 $daysBetweenIssueAndSettlement *= $daysPerYear;
1748 $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis);
1749 if (!is_numeric($daysBetweenIssueAndMaturity)) {
1750 // return date error
1751 return $daysBetweenIssueAndMaturity;
1752 }
1753 $daysBetweenIssueAndMaturity *= $daysPerYear;
1754 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
1755 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
1756 // return date error
1757 return $daysBetweenSettlementAndMaturity;
1758 }
1759 $daysBetweenSettlementAndMaturity *= $daysPerYear;
1760
1761 return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) /
1762 (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) -
1763 (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100));
1764 }
1765 return PHPExcel_Calculation_Functions::VALUE();
1766 } // function PRICEMAT()
1767
1768
1769 /**
1770 * PV
1771 *
1772 * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
1773 *
1774 * @param float $rate Interest rate per period
1775 * @param int $nper Number of periods
1776 * @param float $pmt Periodic payment (annuity)
1777 * @param float $fv Future Value
1778 * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
1779 * @return float
1780 */
1781 public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0) {
1782 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
1783 $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1784 $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
1785 $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1786 $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
1787
1788 // Validate parameters
1789 if ($type != 0 && $type != 1) {
1790 return PHPExcel_Calculation_Functions::NaN();
1791 }
1792
1793 // Calculate
1794 if (!is_null($rate) && $rate != 0) {
1795 return (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper);
1796 } else {
1797 return -$fv - $pmt * $nper;
1798 }
1799 } // function PV()
1800
1801
1802 /**
1803 * RATE
1804 *
1805 * Returns the interest rate per period of an annuity.
1806 * RATE is calculated by iteration and can have zero or more solutions.
1807 * If the successive results of RATE do not converge to within 0.0000001 after 20 iterations,
1808 * RATE returns the #NUM! error value.
1809 *
1810 * Excel Function:
1811 * RATE(nper,pmt,pv[,fv[,type[,guess]]])
1812 *
1813 * @access public
1814 * @category Financial Functions
1815 * @param float nper The total number of payment periods in an annuity.
1816 * @param float pmt The payment made each period and cannot change over the life
1817 * of the annuity.
1818 * Typically, pmt includes principal and interest but no other
1819 * fees or taxes.
1820 * @param float pv The present value - the total amount that a series of future
1821 * payments is worth now.
1822 * @param float fv The future value, or a cash balance you want to attain after
1823 * the last payment is made. If fv is omitted, it is assumed
1824 * to be 0 (the future value of a loan, for example, is 0).
1825 * @param integer type A number 0 or 1 and indicates when payments are due:
1826 * 0 or omitted At the end of the period.
1827 * 1 At the beginning of the period.
1828 * @param float guess Your guess for what the rate will be.
1829 * If you omit guess, it is assumed to be 10 percent.
1830 * @return float
1831 **/
1832 public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) {
1833 $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
1834 $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
1835 $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
1836 $fv = (is_null($fv)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($fv);
1837 $type = (is_null($type)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
1838 $guess = (is_null($guess)) ? 0.1 : PHPExcel_Calculation_Functions::flattenSingleValue($guess);
1839
1840 $rate = $guess;
1841 if (abs($rate) < FINANCIAL_PRECISION) {
1842 $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
1843 } else {
1844 $f = exp($nper * log(1 + $rate));
1845 $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
1846 }
1847 $y0 = $pv + $pmt * $nper + $fv;
1848 $y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
1849
1850 // find root by secant method
1851 $i = $x0 = 0.0;
1852 $x1 = $rate;
1853 while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) {
1854 $rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
1855 $x0 = $x1;
1856 $x1 = $rate;
1857 if (($nper * abs($pmt)) > ($pv - $fv))
1858 $x1 = abs($x1);
1859
1860 if (abs($rate) < FINANCIAL_PRECISION) {
1861 $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
1862 } else {
1863 $f = exp($nper * log(1 + $rate));
1864 $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
1865 }
1866
1867 $y0 = $y1;
1868 $y1 = $y;
1869 ++$i;
1870 }
1871 return $rate;
1872 } // function RATE()
1873
1874
1875 /**
1876 * RECEIVED
1877 *
1878 * Returns the price per $100 face value of a discounted security.
1879 *
1880 * @param mixed settlement The security's settlement date.
1881 * The security settlement date is the date after the issue date when the security is traded to the buyer.
1882 * @param mixed maturity The security's maturity date.
1883 * The maturity date is the date when the security expires.
1884 * @param int investment The amount invested in the security.
1885 * @param int discount The security's discount rate.
1886 * @param int basis The type of day count to use.
1887 * 0 or omitted US (NASD) 30/360
1888 * 1 Actual/actual
1889 * 2 Actual/360
1890 * 3 Actual/365
1891 * 4 European 30/360
1892 * @return float
1893 */
1894 public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis=0) {
1895 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1896 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1897 $investment = (float) PHPExcel_Calculation_Functions::flattenSingleValue($investment);
1898 $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount);
1899 $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
1900
1901 // Validate
1902 if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
1903 if (($investment <= 0) || ($discount <= 0)) {
1904 return PHPExcel_Calculation_Functions::NaN();
1905 }
1906 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
1907 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
1908 // return date error
1909 return $daysBetweenSettlementAndMaturity;
1910 }
1911
1912 return $investment / ( 1 - ($discount * $daysBetweenSettlementAndMaturity));
1913 }
1914 return PHPExcel_Calculation_Functions::VALUE();
1915 } // function RECEIVED()
1916
1917
1918 /**
1919 * SLN
1920 *
1921 * Returns the straight-line depreciation of an asset for one period
1922 *
1923 * @param cost Initial cost of the asset
1924 * @param salvage Value at the end of the depreciation
1925 * @param life Number of periods over which the asset is depreciated
1926 * @return float
1927 */
1928 public static function SLN($cost, $salvage, $life) {
1929 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
1930 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
1931 $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
1932
1933 // Calculate
1934 if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
1935 if ($life < 0) {
1936 return PHPExcel_Calculation_Functions::NaN();
1937 }
1938 return ($cost - $salvage) / $life;
1939 }
1940 return PHPExcel_Calculation_Functions::VALUE();
1941 } // function SLN()
1942
1943
1944 /**
1945 * SYD
1946 *
1947 * Returns the sum-of-years' digits depreciation of an asset for a specified period.
1948 *
1949 * @param cost Initial cost of the asset
1950 * @param salvage Value at the end of the depreciation
1951 * @param life Number of periods over which the asset is depreciated
1952 * @param period Period
1953 * @return float
1954 */
1955 public static function SYD($cost, $salvage, $life, $period) {
1956 $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
1957 $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
1958 $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
1959 $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
1960
1961 // Calculate
1962 if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
1963 if (($life < 1) || ($period > $life)) {
1964 return PHPExcel_Calculation_Functions::NaN();
1965 }
1966 return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1));
1967 }
1968 return PHPExcel_Calculation_Functions::VALUE();
1969 } // function SYD()
1970
1971
1972 /**
1973 * TBILLEQ
1974 *
1975 * Returns the bond-equivalent yield for a Treasury bill.
1976 *
1977 * @param mixed settlement The Treasury bill's settlement date.
1978 * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
1979 * @param mixed maturity The Treasury bill's maturity date.
1980 * The maturity date is the date when the Treasury bill expires.
1981 * @param int discount The Treasury bill's discount rate.
1982 * @return float
1983 */
1984 public static function TBILLEQ($settlement, $maturity, $discount) {
1985 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
1986 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
1987 $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount);
1988
1989 // Use TBILLPRICE for validation
1990 $testValue = self::TBILLPRICE($settlement, $maturity, $discount);
1991 if (is_string($testValue)) {
1992 return $testValue;
1993 }
1994
1995 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
1996 return PHPExcel_Calculation_Functions::VALUE();
1997 }
1998
1999 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
2000 ++$maturity;
2001 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
2002 } else {
2003 $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement));
2004 }
2005
2006 return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity);
2007 } // function TBILLEQ()
2008
2009
2010 /**
2011 * TBILLPRICE
2012 *
2013 * Returns the yield for a Treasury bill.
2014 *
2015 * @param mixed settlement The Treasury bill's settlement date.
2016 * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
2017 * @param mixed maturity The Treasury bill's maturity date.
2018 * The maturity date is the date when the Treasury bill expires.
2019 * @param int discount The Treasury bill's discount rate.
2020 * @return float
2021 */
2022 public static function TBILLPRICE($settlement, $maturity, $discount) {
2023 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
2024 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
2025 $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount);
2026
2027 if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) {
2028 return PHPExcel_Calculation_Functions::VALUE();
2029 }
2030
2031 // Validate
2032 if (is_numeric($discount)) {
2033 if ($discount <= 0) {
2034 return PHPExcel_Calculation_Functions::NaN();
2035 }
2036
2037 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
2038 ++$maturity;
2039 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
2040 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
2041 // return date error
2042 return $daysBetweenSettlementAndMaturity;
2043 }
2044 } else {
2045 $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement));
2046 }
2047
2048 if ($daysBetweenSettlementAndMaturity > 360) {
2049 return PHPExcel_Calculation_Functions::NaN();
2050 }
2051
2052 $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360));
2053 if ($price <= 0) {
2054 return PHPExcel_Calculation_Functions::NaN();
2055 }
2056 return $price;
2057 }
2058 return PHPExcel_Calculation_Functions::VALUE();
2059 } // function TBILLPRICE()
2060
2061
2062 /**
2063 * TBILLYIELD
2064 *
2065 * Returns the yield for a Treasury bill.
2066 *
2067 * @param mixed settlement The Treasury bill's settlement date.
2068 * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
2069 * @param mixed maturity The Treasury bill's maturity date.
2070 * The maturity date is the date when the Treasury bill expires.
2071 * @param int price The Treasury bill's price per $100 face value.
2072 * @return float
2073 */
2074 public static function TBILLYIELD($settlement, $maturity, $price) {
2075 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
2076 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
2077 $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
2078
2079 // Validate
2080 if (is_numeric($price)) {
2081 if ($price <= 0) {
2082 return PHPExcel_Calculation_Functions::NaN();
2083 }
2084
2085 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
2086 ++$maturity;
2087 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
2088 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
2089 // return date error
2090 return $daysBetweenSettlementAndMaturity;
2091 }
2092 } else {
2093 $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement));
2094 }
2095
2096 if ($daysBetweenSettlementAndMaturity > 360) {
2097 return PHPExcel_Calculation_Functions::NaN();
2098 }
2099
2100 return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity);
2101 }
2102 return PHPExcel_Calculation_Functions::VALUE();
2103 } // function TBILLYIELD()
2104
2105
2106 public static function XIRR($values, $dates, $guess = 0.1) {
2107 if ((!is_array($values)) && (!is_array($dates))) return PHPExcel_Calculation_Functions::VALUE();
2108 $values = PHPExcel_Calculation_Functions::flattenArray($values);
2109 $dates = PHPExcel_Calculation_Functions::flattenArray($dates);
2110 $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess);
2111 if (count($values) != count($dates)) return PHPExcel_Calculation_Functions::NaN();
2112
2113 // create an initial range, with a root somewhere between 0 and guess
2114 $x1 = 0.0;
2115 $x2 = $guess;
2116 $f1 = self::XNPV($x1, $values, $dates);
2117 $f2 = self::XNPV($x2, $values, $dates);
2118 for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
2119 if (($f1 * $f2) < 0.0) break;
2120 if (abs($f1) < abs($f2)) {
2121 $f1 = self::XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
2122 } else {
2123 $f2 = self::XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
2124 }
2125 }
2126 if (($f1 * $f2) > 0.0) return PHPExcel_Calculation_Functions::VALUE();
2127
2128 $f = self::XNPV($x1, $values, $dates);
2129 if ($f < 0.0) {
2130 $rtb = $x1;
2131 $dx = $x2 - $x1;
2132 } else {
2133 $rtb = $x2;
2134 $dx = $x1 - $x2;
2135 }
2136
2137 for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
2138 $dx *= 0.5;
2139 $x_mid = $rtb + $dx;
2140 $f_mid = self::XNPV($x_mid, $values, $dates);
2141 if ($f_mid <= 0.0) $rtb = $x_mid;
2142 if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid;
2143 }
2144 return PHPExcel_Calculation_Functions::VALUE();
2145 }
2146
2147
2148 /**
2149 * XNPV
2150 *
2151 * Returns the net present value for a schedule of cash flows that is not necessarily periodic.
2152 * To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
2153 *
2154 * Excel Function:
2155 * =XNPV(rate,values,dates)
2156 *
2157 * @param float $rate The discount rate to apply to the cash flows.
2158 * @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates. The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. The series of values must contain at least one positive value and one negative value.
2159 * @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments. The first payment date indicates the beginning of the schedule of payments. All other dates must be later than this date, but they may occur in any order.
2160 * @return float
2161 */
2162 public static function XNPV($rate, $values, $dates) {
2163 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
2164 if (!is_numeric($rate)) return PHPExcel_Calculation_Functions::VALUE();
2165 if ((!is_array($values)) || (!is_array($dates))) return PHPExcel_Calculation_Functions::VALUE();
2166 $values = PHPExcel_Calculation_Functions::flattenArray($values);
2167 $dates = PHPExcel_Calculation_Functions::flattenArray($dates);
2168 $valCount = count($values);
2169 if ($valCount != count($dates)) return PHPExcel_Calculation_Functions::NaN();
2170 if ((min($values) > 0) || (max($values) < 0)) return PHPExcel_Calculation_Functions::VALUE();
2171
2172 $xnpv = 0.0;
2173 for ($i = 0; $i < $valCount; ++$i) {
2174 if (!is_numeric($values[$i])) return PHPExcel_Calculation_Functions::VALUE();
2175 $xnpv += $values[$i] / pow(1 + $rate, PHPExcel_Calculation_DateTime::DATEDIF($dates[0],$dates[$i],'d') / 365);
2176 }
2177 return (is_finite($xnpv)) ? $xnpv : PHPExcel_Calculation_Functions::VALUE();
2178 } // function XNPV()
2179
2180
2181 /**
2182 * YIELDDISC
2183 *
2184 * Returns the annual yield of a security that pays interest at maturity.
2185 *
2186 * @param mixed settlement The security's settlement date.
2187 * The security's settlement date is the date after the issue date when the security is traded to the buyer.
2188 * @param mixed maturity The security's maturity date.
2189 * The maturity date is the date when the security expires.
2190 * @param int price The security's price per $100 face value.
2191 * @param int redemption The security's redemption value per $100 face value.
2192 * @param int basis The type of day count to use.
2193 * 0 or omitted US (NASD) 30/360
2194 * 1 Actual/actual
2195 * 2 Actual/360
2196 * 3 Actual/365
2197 * 4 European 30/360
2198 * @return float
2199 */
2200 public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis=0) {
2201 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
2202 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
2203 $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
2204 $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
2205 $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
2206
2207 // Validate
2208 if (is_numeric($price) && is_numeric($redemption)) {
2209 if (($price <= 0) || ($redemption <= 0)) {
2210 return PHPExcel_Calculation_Functions::NaN();
2211 }
2212 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis);
2213 if (!is_numeric($daysPerYear)) {
2214 return $daysPerYear;
2215 }
2216 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity,$basis);
2217 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
2218 // return date error
2219 return $daysBetweenSettlementAndMaturity;
2220 }
2221 $daysBetweenSettlementAndMaturity *= $daysPerYear;
2222
2223 return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity);
2224 }
2225 return PHPExcel_Calculation_Functions::VALUE();
2226 } // function YIELDDISC()
2227
2228
2229 /**
2230 * YIELDMAT
2231 *
2232 * Returns the annual yield of a security that pays interest at maturity.
2233 *
2234 * @param mixed settlement The security's settlement date.
2235 * The security's settlement date is the date after the issue date when the security is traded to the buyer.
2236 * @param mixed maturity The security's maturity date.
2237 * The maturity date is the date when the security expires.
2238 * @param mixed issue The security's issue date.
2239 * @param int rate The security's interest rate at date of issue.
2240 * @param int price The security's price per $100 face value.
2241 * @param int basis The type of day count to use.
2242 * 0 or omitted US (NASD) 30/360
2243 * 1 Actual/actual
2244 * 2 Actual/360
2245 * 3 Actual/365
2246 * 4 European 30/360
2247 * @return float
2248 */
2249 public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis=0) {
2250 $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
2251 $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
2252 $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
2253 $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
2254 $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
2255 $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
2256
2257 // Validate
2258 if (is_numeric($rate) && is_numeric($price)) {
2259 if (($rate <= 0) || ($price <= 0)) {
2260 return PHPExcel_Calculation_Functions::NaN();
2261 }
2262 $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis);
2263 if (!is_numeric($daysPerYear)) {
2264 return $daysPerYear;
2265 }
2266 $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
2267 if (!is_numeric($daysBetweenIssueAndSettlement)) {
2268 // return date error
2269 return $daysBetweenIssueAndSettlement;
2270 }
2271 $daysBetweenIssueAndSettlement *= $daysPerYear;
2272 $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis);
2273 if (!is_numeric($daysBetweenIssueAndMaturity)) {
2274 // return date error
2275 return $daysBetweenIssueAndMaturity;
2276 }
2277 $daysBetweenIssueAndMaturity *= $daysPerYear;
2278 $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
2279 if (!is_numeric($daysBetweenSettlementAndMaturity)) {
2280 // return date error
2281 return $daysBetweenSettlementAndMaturity;
2282 }
2283 $daysBetweenSettlementAndMaturity *= $daysPerYear;
2284
2285 return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) /
2286 (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) *
2287 ($daysPerYear / $daysBetweenSettlementAndMaturity);
2288 }
2289 return PHPExcel_Calculation_Functions::VALUE();
2290 } // function YIELDMAT()
2291
2292 } // class PHPExcel_Calculation_Financial
2293