PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/phpexcel/PHPExcel/Calculation/Financial.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 2064 lines | 1284 code | 231 blank | 549 comment | 316 complexity | 29cfe0668c547fcf32a0ebce829d0a60 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0
  1. <?php
  2. /**
  3. * PHPExcel
  4. *
  5. * Copyright (c) 2006 - 2011 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 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version 1.7.6, 2011-02-27
  26. */
  27. /** PHPExcel root directory */
  28. if (! defined('PHPEXCEL_ROOT'))
  29. {
  30. /**
  31. * @ignore
  32. */
  33. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  34. require (PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  35. }
  36. /** FINANCIAL_MAX_ITERATIONS */
  37. define('FINANCIAL_MAX_ITERATIONS', 128);
  38. /** FINANCIAL_PRECISION */
  39. define('FINANCIAL_PRECISION', 1.0e-08);
  40. /**
  41. * PHPExcel_Calculation_Financial
  42. *
  43. * @category PHPExcel
  44. * @package PHPExcel_Calculation
  45. * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
  46. */
  47. class PHPExcel_Calculation_Financial
  48. {
  49. private static function _lastDayOfMonth($testDate)
  50. {
  51. $date = clone $testDate;
  52. $date->modify('+1 day');
  53. return ($date->format('d') == 1);
  54. } // function _lastDayOfMonth()
  55. private static function _firstDayOfMonth($testDate)
  56. {
  57. $date = clone $testDate;
  58. return ($date->format('d') == 1);
  59. } // function _lastDayOfMonth()
  60. private static function _coupFirstPeriodDate($settlement, $maturity, $frequency, $next)
  61. {
  62. $months = 12 / $frequency;
  63. $result = PHPExcel_Shared_Date :: ExcelToPHPObject($maturity);
  64. $eom = self :: _lastDayOfMonth($result);
  65. while ($settlement < PHPExcel_Shared_Date :: PHPToExcel($result))
  66. {
  67. $result->modify('-' . $months . ' months');
  68. }
  69. if ($next)
  70. {
  71. $result->modify('+' . $months . ' months');
  72. }
  73. if ($eom)
  74. {
  75. $result->modify('-1 day');
  76. }
  77. return PHPExcel_Shared_Date :: PHPToExcel($result);
  78. } // function _coupFirstPeriodDate()
  79. private static function _validFrequency($frequency)
  80. {
  81. if (($frequency == 1) || ($frequency == 2) || ($frequency == 4))
  82. {
  83. return true;
  84. }
  85. if ((PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_GNUMERIC) && (($frequency == 6) || ($frequency == 12)))
  86. {
  87. return true;
  88. }
  89. return false;
  90. } // function _validFrequency()
  91. private static function _daysPerYear($year, $basis)
  92. {
  93. switch ($basis)
  94. {
  95. case 0 :
  96. case 2 :
  97. case 4 :
  98. $daysPerYear = 360;
  99. break;
  100. case 3 :
  101. $daysPerYear = 365;
  102. break;
  103. case 1 :
  104. if (PHPExcel_Calculation_DateTime :: _isLeapYear($year))
  105. {
  106. $daysPerYear = 366;
  107. }
  108. else
  109. {
  110. $daysPerYear = 365;
  111. }
  112. break;
  113. default :
  114. return PHPExcel_Calculation_Functions :: NaN();
  115. }
  116. return $daysPerYear;
  117. } // function _daysPerYear()
  118. private static function _interestAndPrincipal($rate = 0, $per = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
  119. {
  120. $pmt = self :: PMT($rate, $nper, $pv, $fv, $type);
  121. $capital = $pv;
  122. for($i = 1; $i <= $per; ++ $i)
  123. {
  124. $interest = ($type && $i == 1) ? 0 : - $capital * $rate;
  125. $principal = $pmt - $interest;
  126. $capital += $principal;
  127. }
  128. return array($interest, $principal);
  129. } // function _interestAndPrincipal()
  130. /**
  131. * ACCRINT
  132. *
  133. * Returns the discount rate for a security.
  134. *
  135. * @param mixed issue The security's issue date.
  136. * @param mixed firstinter The security's first interest date.
  137. * @param mixed settlement The security's settlement date.
  138. * @param float rate The security's annual coupon rate.
  139. * @param float par The security's par value.
  140. * @param int basis The type of day count to use.
  141. * 0 or omitted US (NASD) 30/360
  142. * 1 Actual/actual
  143. * 2 Actual/360
  144. * 3 Actual/365
  145. * 4 European 30/360
  146. * @return float
  147. */
  148. public static function ACCRINT($issue, $firstinter, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
  149. {
  150. $issue = PHPExcel_Calculation_Functions :: flattenSingleValue($issue);
  151. $firstinter = PHPExcel_Calculation_Functions :: flattenSingleValue($firstinter);
  152. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  153. $rate = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  154. $par = (is_null($par)) ? 1000 : (float) PHPExcel_Calculation_Functions :: flattenSingleValue($par);
  155. $frequency = (is_null($frequency)) ? 1 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  156. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  157. // Validate
  158. if ((is_numeric($rate)) && (is_numeric($par)))
  159. {
  160. if (($rate <= 0) || ($par <= 0))
  161. {
  162. return PHPExcel_Calculation_Functions :: NaN();
  163. }
  164. $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $settlement, $basis);
  165. if (! is_numeric($daysBetweenIssueAndSettlement))
  166. {
  167. // return date error
  168. return $daysBetweenIssueAndSettlement;
  169. }
  170. return $par * $rate * $daysBetweenIssueAndSettlement;
  171. }
  172. return PHPExcel_Calculation_Functions :: VALUE();
  173. } // function ACCRINT()
  174. /**
  175. * ACCRINTM
  176. *
  177. * Returns the discount rate for a security.
  178. *
  179. * @param mixed issue The security's issue date.
  180. * @param mixed settlement The security's settlement date.
  181. * @param float rate The security's annual coupon rate.
  182. * @param float par The security's par value.
  183. * @param int basis The type of day count to use.
  184. * 0 or omitted US (NASD) 30/360
  185. * 1 Actual/actual
  186. * 2 Actual/360
  187. * 3 Actual/365
  188. * 4 European 30/360
  189. * @return float
  190. */
  191. public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
  192. {
  193. $issue = PHPExcel_Calculation_Functions :: flattenSingleValue($issue);
  194. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  195. $rate = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  196. $par = (is_null($par)) ? 1000 : (float) PHPExcel_Calculation_Functions :: flattenSingleValue($par);
  197. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  198. // Validate
  199. if ((is_numeric($rate)) && (is_numeric($par)))
  200. {
  201. if (($rate <= 0) || ($par <= 0))
  202. {
  203. return PHPExcel_Calculation_Functions :: NaN();
  204. }
  205. $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $settlement, $basis);
  206. if (! is_numeric($daysBetweenIssueAndSettlement))
  207. {
  208. // return date error
  209. return $daysBetweenIssueAndSettlement;
  210. }
  211. return $par * $rate * $daysBetweenIssueAndSettlement;
  212. }
  213. return PHPExcel_Calculation_Functions :: VALUE();
  214. } // function ACCRINTM()
  215. public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0)
  216. {
  217. $cost = PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  218. $purchased = PHPExcel_Calculation_Functions :: flattenSingleValue($purchased);
  219. $firstPeriod = PHPExcel_Calculation_Functions :: flattenSingleValue($firstPeriod);
  220. $salvage = PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  221. $period = floor(PHPExcel_Calculation_Functions :: flattenSingleValue($period));
  222. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  223. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  224. $fUsePer = 1.0 / $rate;
  225. if ($fUsePer < 3.0)
  226. {
  227. $amortiseCoeff = 1.0;
  228. }
  229. elseif ($fUsePer < 5.0)
  230. {
  231. $amortiseCoeff = 1.5;
  232. }
  233. elseif ($fUsePer <= 6.0)
  234. {
  235. $amortiseCoeff = 2.0;
  236. }
  237. else
  238. {
  239. $amortiseCoeff = 2.5;
  240. }
  241. $rate *= $amortiseCoeff;
  242. $fNRate = round(PHPExcel_Calculation_DateTime :: YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost, 0);
  243. $cost -= $fNRate;
  244. $fRest = $cost - $salvage;
  245. for($n = 0; $n < $period; ++ $n)
  246. {
  247. $fNRate = round($rate * $cost, 0);
  248. $fRest -= $fNRate;
  249. if ($fRest < 0.0)
  250. {
  251. switch ($period - $n)
  252. {
  253. case 0 :
  254. case 1 :
  255. return round($cost * 0.5, 0);
  256. break;
  257. default :
  258. return 0.0;
  259. break;
  260. }
  261. }
  262. $cost -= $fNRate;
  263. }
  264. return $fNRate;
  265. } // function AMORDEGRC()
  266. public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0)
  267. {
  268. $cost = PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  269. $purchased = PHPExcel_Calculation_Functions :: flattenSingleValue($purchased);
  270. $firstPeriod = PHPExcel_Calculation_Functions :: flattenSingleValue($firstPeriod);
  271. $salvage = PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  272. $period = PHPExcel_Calculation_Functions :: flattenSingleValue($period);
  273. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  274. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  275. $fOneRate = $cost * $rate;
  276. $fCostDelta = $cost - $salvage;
  277. // Note, quirky variation for leap years on the YEARFRAC for this function
  278. $purchasedYear = PHPExcel_Calculation_DateTime :: YEAR($purchased);
  279. $yearFrac = PHPExcel_Calculation_DateTime :: YEARFRAC($purchased, $firstPeriod, $basis);
  280. if (($basis == 1) && ($yearFrac < 1) && (PHPExcel_Calculation_DateTime :: _isLeapYear($purchasedYear)))
  281. {
  282. $yearFrac *= 365 / 366;
  283. }
  284. $f0Rate = $yearFrac * $rate * $cost;
  285. $nNumOfFullPeriods = intval(($cost - $salvage - $f0Rate) / $fOneRate);
  286. if ($period == 0)
  287. {
  288. return $f0Rate;
  289. }
  290. elseif ($period <= $nNumOfFullPeriods)
  291. {
  292. return $fOneRate;
  293. }
  294. elseif ($period == ($nNumOfFullPeriods + 1))
  295. {
  296. return ($fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate);
  297. }
  298. else
  299. {
  300. return 0.0;
  301. }
  302. } // function AMORLINC()
  303. public static function COUPDAYBS($settlement, $maturity, $frequency, $basis = 0)
  304. {
  305. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  306. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  307. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  308. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  309. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  310. {
  311. return PHPExcel_Calculation_Functions :: VALUE();
  312. }
  313. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  314. {
  315. return PHPExcel_Calculation_Functions :: VALUE();
  316. }
  317. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  318. {
  319. return PHPExcel_Calculation_Functions :: NaN();
  320. }
  321. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($settlement), $basis);
  322. $prev = self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, False);
  323. return PHPExcel_Calculation_DateTime :: YEARFRAC($prev, $settlement, $basis) * $daysPerYear;
  324. } // function COUPDAYBS()
  325. public static function COUPDAYS($settlement, $maturity, $frequency, $basis = 0)
  326. {
  327. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  328. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  329. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  330. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  331. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  332. {
  333. return PHPExcel_Calculation_Functions :: VALUE();
  334. }
  335. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  336. {
  337. return PHPExcel_Calculation_Functions :: VALUE();
  338. }
  339. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  340. {
  341. return PHPExcel_Calculation_Functions :: NaN();
  342. }
  343. switch ($basis)
  344. {
  345. case 3 : // Actual/365
  346. return 365 / $frequency;
  347. case 1 : // Actual/actual
  348. if ($frequency == 1)
  349. {
  350. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($maturity), $basis);
  351. return ($daysPerYear / $frequency);
  352. }
  353. else
  354. {
  355. $prev = self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, False);
  356. $next = self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, True);
  357. return ($next - $prev);
  358. }
  359. default : // US (NASD) 30/360, Actual/360 or European 30/360
  360. return 360 / $frequency;
  361. }
  362. return PHPExcel_Calculation_Functions :: VALUE();
  363. } // function COUPDAYS()
  364. public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = 0)
  365. {
  366. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  367. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  368. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  369. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  370. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  371. {
  372. return PHPExcel_Calculation_Functions :: VALUE();
  373. }
  374. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  375. {
  376. return PHPExcel_Calculation_Functions :: VALUE();
  377. }
  378. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  379. {
  380. return PHPExcel_Calculation_Functions :: NaN();
  381. }
  382. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($settlement), $basis);
  383. $next = self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, True);
  384. return PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $next, $basis) * $daysPerYear;
  385. } // function COUPDAYSNC()
  386. public static function COUPNCD($settlement, $maturity, $frequency, $basis = 0)
  387. {
  388. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  389. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  390. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  391. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  392. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  393. {
  394. return PHPExcel_Calculation_Functions :: VALUE();
  395. }
  396. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  397. {
  398. return PHPExcel_Calculation_Functions :: VALUE();
  399. }
  400. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  401. {
  402. return PHPExcel_Calculation_Functions :: NaN();
  403. }
  404. return self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, True);
  405. } // function COUPNCD()
  406. public static function COUPNUM($settlement, $maturity, $frequency, $basis = 0)
  407. {
  408. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  409. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  410. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  411. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  412. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  413. {
  414. return PHPExcel_Calculation_Functions :: VALUE();
  415. }
  416. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  417. {
  418. return PHPExcel_Calculation_Functions :: VALUE();
  419. }
  420. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  421. {
  422. return PHPExcel_Calculation_Functions :: NaN();
  423. }
  424. $settlement = self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, True);
  425. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis) * 365;
  426. switch ($frequency)
  427. {
  428. case 1 : // annual payments
  429. return ceil($daysBetweenSettlementAndMaturity / 360);
  430. case 2 : // half-yearly
  431. return ceil($daysBetweenSettlementAndMaturity / 180);
  432. case 4 : // quarterly
  433. return ceil($daysBetweenSettlementAndMaturity / 90);
  434. case 6 : // bimonthly
  435. return ceil($daysBetweenSettlementAndMaturity / 60);
  436. case 12 : // monthly
  437. return ceil($daysBetweenSettlementAndMaturity / 30);
  438. }
  439. return PHPExcel_Calculation_Functions :: VALUE();
  440. } // function COUPNUM()
  441. public static function COUPPCD($settlement, $maturity, $frequency, $basis = 0)
  442. {
  443. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  444. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  445. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  446. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  447. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  448. {
  449. return PHPExcel_Calculation_Functions :: VALUE();
  450. }
  451. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  452. {
  453. return PHPExcel_Calculation_Functions :: VALUE();
  454. }
  455. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  456. {
  457. return PHPExcel_Calculation_Functions :: NaN();
  458. }
  459. return self :: _coupFirstPeriodDate($settlement, $maturity, $frequency, False);
  460. } // function COUPPCD()
  461. /**
  462. * CUMIPMT
  463. *
  464. * Returns the cumulative interest paid on a loan between start_period and end_period.
  465. *
  466. * @param float $rate Interest rate per period
  467. * @param int $nper Number of periods
  468. * @param float $pv Present Value
  469. * @param int start The first period in the calculation.
  470. * Payment periods are numbered beginning with 1.
  471. * @param int end The last period in the calculation.
  472. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  473. * @return float
  474. */
  475. public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0)
  476. {
  477. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  478. $nper = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  479. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  480. $start = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($start);
  481. $end = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($end);
  482. $type = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  483. // Validate parameters
  484. if ($type != 0 && $type != 1)
  485. {
  486. return PHPExcel_Calculation_Functions :: NaN();
  487. }
  488. if ($start < 1 || $start > $end)
  489. {
  490. return PHPExcel_Calculation_Functions :: VALUE();
  491. }
  492. // Calculate
  493. $interest = 0;
  494. for($per = $start; $per <= $end; ++ $per)
  495. {
  496. $interest += self :: IPMT($rate, $per, $nper, $pv, 0, $type);
  497. }
  498. return $interest;
  499. } // function CUMIPMT()
  500. /**
  501. * CUMPRINC
  502. *
  503. * Returns the cumulative principal paid on a loan between start_period and end_period.
  504. *
  505. * @param float $rate Interest rate per period
  506. * @param int $nper Number of periods
  507. * @param float $pv Present Value
  508. * @param int start The first period in the calculation.
  509. * Payment periods are numbered beginning with 1.
  510. * @param int end The last period in the calculation.
  511. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  512. * @return float
  513. */
  514. public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0)
  515. {
  516. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  517. $nper = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  518. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  519. $start = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($start);
  520. $end = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($end);
  521. $type = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  522. // Validate parameters
  523. if ($type != 0 && $type != 1)
  524. {
  525. return PHPExcel_Calculation_Functions :: NaN();
  526. }
  527. if ($start < 1 || $start > $end)
  528. {
  529. return PHPExcel_Calculation_Functions :: VALUE();
  530. }
  531. // Calculate
  532. $principal = 0;
  533. for($per = $start; $per <= $end; ++ $per)
  534. {
  535. $principal += self :: PPMT($rate, $per, $nper, $pv, 0, $type);
  536. }
  537. return $principal;
  538. } // function CUMPRINC()
  539. /**
  540. * DB
  541. *
  542. * Returns the depreciation of an asset for a specified period using the fixed-declining balance method.
  543. * This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation
  544. * (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the
  545. * depreciation already deducted from the initial cost.
  546. *
  547. * @param float cost Initial cost of the asset.
  548. * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  549. * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  550. * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life.
  551. * @param float month Number of months in the first year. If month is omitted, it defaults to 12.
  552. * @return float
  553. */
  554. public static function DB($cost, $salvage, $life, $period, $month = 12)
  555. {
  556. $cost = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  557. $salvage = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  558. $life = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($life);
  559. $period = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($period);
  560. $month = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($month);
  561. // Validate
  562. if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month)))
  563. {
  564. if ($cost == 0)
  565. {
  566. return 0.0;
  567. }
  568. elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1))
  569. {
  570. return PHPExcel_Calculation_Functions :: NaN();
  571. }
  572. // Set Fixed Depreciation Rate
  573. $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
  574. $fixedDepreciationRate = round($fixedDepreciationRate, 3);
  575. // Loop through each period calculating the depreciation
  576. $previousDepreciation = 0;
  577. for($per = 1; $per <= $period; ++ $per)
  578. {
  579. if ($per == 1)
  580. {
  581. $depreciation = $cost * $fixedDepreciationRate * $month / 12;
  582. }
  583. elseif ($per == ($life + 1))
  584. {
  585. $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12;
  586. }
  587. else
  588. {
  589. $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate;
  590. }
  591. $previousDepreciation += $depreciation;
  592. }
  593. if (PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_GNUMERIC)
  594. {
  595. $depreciation = round($depreciation, 2);
  596. }
  597. return $depreciation;
  598. }
  599. return PHPExcel_Calculation_Functions :: VALUE();
  600. } // function DB()
  601. /**
  602. * DDB
  603. *
  604. * Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify.
  605. *
  606. * @param float cost Initial cost of the asset.
  607. * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset)
  608. * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset)
  609. * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life.
  610. * @param float factor The rate at which the balance declines.
  611. * If factor is omitted, it is assumed to be 2 (the double-declining balance method).
  612. * @return float
  613. */
  614. public static function DDB($cost, $salvage, $life, $period, $factor = 2.0)
  615. {
  616. $cost = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  617. $salvage = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  618. $life = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($life);
  619. $period = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($period);
  620. $factor = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($factor);
  621. // Validate
  622. if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor)))
  623. {
  624. if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life))
  625. {
  626. return PHPExcel_Calculation_Functions :: NaN();
  627. }
  628. // Set Fixed Depreciation Rate
  629. $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
  630. $fixedDepreciationRate = round($fixedDepreciationRate, 3);
  631. // Loop through each period calculating the depreciation
  632. $previousDepreciation = 0;
  633. for($per = 1; $per <= $period; ++ $per)
  634. {
  635. $depreciation = min(($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation));
  636. $previousDepreciation += $depreciation;
  637. }
  638. if (PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_GNUMERIC)
  639. {
  640. $depreciation = round($depreciation, 2);
  641. }
  642. return $depreciation;
  643. }
  644. return PHPExcel_Calculation_Functions :: VALUE();
  645. } // function DDB()
  646. /**
  647. * DISC
  648. *
  649. * Returns the discount rate for a security.
  650. *
  651. * @param mixed settlement The security's settlement date.
  652. * The security settlement date is the date after the issue date when the security is traded to the buyer.
  653. * @param mixed maturity The security's maturity date.
  654. * The maturity date is the date when the security expires.
  655. * @param int price The security's price per $100 face value.
  656. * @param int redemption the security's redemption value per $100 face value.
  657. * @param int basis The type of day count to use.
  658. * 0 or omitted US (NASD) 30/360
  659. * 1 Actual/actual
  660. * 2 Actual/360
  661. * 3 Actual/365
  662. * 4 European 30/360
  663. * @return float
  664. */
  665. public static function DISC($settlement, $maturity, $price, $redemption, $basis = 0)
  666. {
  667. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  668. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  669. $price = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($price);
  670. $redemption = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($redemption);
  671. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  672. // Validate
  673. if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis)))
  674. {
  675. if (($price <= 0) || ($redemption <= 0))
  676. {
  677. return PHPExcel_Calculation_Functions :: NaN();
  678. }
  679. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  680. if (! is_numeric($daysBetweenSettlementAndMaturity))
  681. {
  682. // return date error
  683. return $daysBetweenSettlementAndMaturity;
  684. }
  685. return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity);
  686. }
  687. return PHPExcel_Calculation_Functions :: VALUE();
  688. } // function DISC()
  689. /**
  690. * DOLLARDE
  691. *
  692. * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number.
  693. * Fractional dollar numbers are sometimes used for security prices.
  694. *
  695. * @param float $fractional_dollar Fractional Dollar
  696. * @param int $fraction Fraction
  697. * @return float
  698. */
  699. public static function DOLLARDE($fractional_dollar = Null, $fraction = 0)
  700. {
  701. $fractional_dollar = PHPExcel_Calculation_Functions :: flattenSingleValue($fractional_dollar);
  702. $fraction = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($fraction);
  703. // Validate parameters
  704. if (is_null($fractional_dollar) || $fraction < 0)
  705. {
  706. return PHPExcel_Calculation_Functions :: NaN();
  707. }
  708. if ($fraction == 0)
  709. {
  710. return PHPExcel_Calculation_Functions :: DIV0();
  711. }
  712. $dollars = floor($fractional_dollar);
  713. $cents = fmod($fractional_dollar, 1);
  714. $cents /= $fraction;
  715. $cents *= pow(10, ceil(log10($fraction)));
  716. return $dollars + $cents;
  717. } // function DOLLARDE()
  718. /**
  719. * DOLLARFR
  720. *
  721. * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction.
  722. * Fractional dollar numbers are sometimes used for security prices.
  723. *
  724. * @param float $decimal_dollar Decimal Dollar
  725. * @param int $fraction Fraction
  726. * @return float
  727. */
  728. public static function DOLLARFR($decimal_dollar = Null, $fraction = 0)
  729. {
  730. $decimal_dollar = PHPExcel_Calculation_Functions :: flattenSingleValue($decimal_dollar);
  731. $fraction = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($fraction);
  732. // Validate parameters
  733. if (is_null($decimal_dollar) || $fraction < 0)
  734. {
  735. return PHPExcel_Calculation_Functions :: NaN();
  736. }
  737. if ($fraction == 0)
  738. {
  739. return PHPExcel_Calculation_Functions :: DIV0();
  740. }
  741. $dollars = floor($decimal_dollar);
  742. $cents = fmod($decimal_dollar, 1);
  743. $cents *= $fraction;
  744. $cents *= pow(10, - ceil(log10($fraction)));
  745. return $dollars + $cents;
  746. } // function DOLLARFR()
  747. /**
  748. * EFFECT
  749. *
  750. * Returns the effective interest rate given the nominal rate and the number of compounding payments per year.
  751. *
  752. * @param float $nominal_rate Nominal interest rate
  753. * @param int $npery Number of compounding payments per year
  754. * @return float
  755. */
  756. public static function EFFECT($nominal_rate = 0, $npery = 0)
  757. {
  758. $nominal_rate = PHPExcel_Calculation_Functions :: flattenSingleValue($nominal_rate);
  759. $npery = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($npery);
  760. // Validate parameters
  761. if ($nominal_rate <= 0 || $npery < 1)
  762. {
  763. return PHPExcel_Calculation_Functions :: NaN();
  764. }
  765. return pow((1 + $nominal_rate / $npery), $npery) - 1;
  766. } // function EFFECT()
  767. /**
  768. * FV
  769. *
  770. * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
  771. *
  772. * @param float $rate Interest rate per period
  773. * @param int $nper Number of periods
  774. * @param float $pmt Periodic payment (annuity)
  775. * @param float $pv Present Value
  776. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  777. * @return float
  778. */
  779. public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0)
  780. {
  781. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  782. $nper = PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  783. $pmt = PHPExcel_Calculation_Functions :: flattenSingleValue($pmt);
  784. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  785. $type = PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  786. // Validate parameters
  787. if ($type != 0 && $type != 1)
  788. {
  789. return PHPExcel_Calculation_Functions :: NaN();
  790. }
  791. // Calculate
  792. if (! is_null($rate) && $rate != 0)
  793. {
  794. return - $pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate;
  795. }
  796. else
  797. {
  798. return - $pv - $pmt * $nper;
  799. }
  800. } // function FV()
  801. /**
  802. * FVSCHEDULE
  803. *
  804. */
  805. public static function FVSCHEDULE($principal, $schedule)
  806. {
  807. $principal = PHPExcel_Calculation_Functions :: flattenSingleValue($principal);
  808. $schedule = PHPExcel_Calculation_Functions :: flattenArray($schedule);
  809. foreach ($schedule as $n)
  810. {
  811. $principal *= 1 + $n;
  812. }
  813. return $principal;
  814. } // function FVSCHEDULE()
  815. /**
  816. * INTRATE
  817. *
  818. * Returns the interest rate for a fully invested security.
  819. *
  820. * @param mixed settlement The security's settlement date.
  821. * The security settlement date is the date after the issue date when the security is traded to the buyer.
  822. * @param mixed maturity The security's maturity date.
  823. * The maturity date is the date when the security expires.
  824. * @param int investment The amount invested in the security.
  825. * @param int redemption The amount to be received at maturity.
  826. * @param int basis The type of day count to use.
  827. * 0 or omitted US (NASD) 30/360
  828. * 1 Actual/actual
  829. * 2 Actual/360
  830. * 3 Actual/365
  831. * 4 European 30/360
  832. * @return float
  833. */
  834. public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis = 0)
  835. {
  836. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  837. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  838. $investment = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($investment);
  839. $redemption = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($redemption);
  840. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  841. // Validate
  842. if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis)))
  843. {
  844. if (($investment <= 0) || ($redemption <= 0))
  845. {
  846. return PHPExcel_Calculation_Functions :: NaN();
  847. }
  848. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  849. if (! is_numeric($daysBetweenSettlementAndMaturity))
  850. {
  851. // return date error
  852. return $daysBetweenSettlementAndMaturity;
  853. }
  854. return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity);
  855. }
  856. return PHPExcel_Calculation_Functions :: VALUE();
  857. } // function INTRATE()
  858. /**
  859. * IPMT
  860. *
  861. * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  862. *
  863. * @param float $rate Interest rate per period
  864. * @param int $per Period for which we want to find the interest
  865. * @param int $nper Number of periods
  866. * @param float $pv Present Value
  867. * @param float $fv Future Value
  868. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  869. * @return float
  870. */
  871. public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
  872. {
  873. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  874. $per = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($per);
  875. $nper = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  876. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  877. $fv = PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  878. $type = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  879. // Validate parameters
  880. if ($type != 0 && $type != 1)
  881. {
  882. return PHPExcel_Calculation_Functions :: NaN();
  883. }
  884. if ($per <= 0 || $per > $nper)
  885. {
  886. return PHPExcel_Calculation_Functions :: VALUE();
  887. }
  888. // Calculate
  889. $interestAndPrincipal = self :: _interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
  890. return $interestAndPrincipal[0];
  891. } // function IPMT()
  892. public static function IRR($values, $guess = 0.1)
  893. {
  894. if (! is_array($values))
  895. return PHPExcel_Calculation_Functions :: VALUE();
  896. $values = PHPExcel_Calculation_Functions :: flattenArray($values);
  897. $guess = PHPExcel_Calculation_Functions :: flattenSingleValue($guess);
  898. // create an initial range, with a root somewhere between 0 and guess
  899. $x1 = 0.0;
  900. $x2 = $guess;
  901. $f1 = self :: NPV($x1, $values);
  902. $f2 = self :: NPV($x2, $values);
  903. for($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++ $i)
  904. {
  905. if (($f1 * $f2) < 0.0)
  906. break;
  907. if (abs($f1) < abs($f2))
  908. {
  909. $f1 = self :: NPV($x1 += 1.6 * ($x1 - $x2), $values);
  910. }
  911. else
  912. {
  913. $f2 = self :: NPV($x2 += 1.6 * ($x2 - $x1), $values);
  914. }
  915. }
  916. if (($f1 * $f2) > 0.0)
  917. return PHPExcel_Calculation_Functions :: VALUE();
  918. $f = self :: NPV($x1, $values);
  919. if ($f < 0.0)
  920. {
  921. $rtb = $x1;
  922. $dx = $x2 - $x1;
  923. }
  924. else
  925. {
  926. $rtb = $x2;
  927. $dx = $x1 - $x2;
  928. }
  929. for($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++ $i)
  930. {
  931. $dx *= 0.5;
  932. $x_mid = $rtb + $dx;
  933. $f_mid = self :: NPV($x_mid, $values);
  934. if ($f_mid <= 0.0)
  935. $rtb = $x_mid;
  936. if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION))
  937. return $x_mid;
  938. }
  939. return PHPExcel_Calculation_Functions :: VALUE();
  940. } // function IRR()
  941. /**
  942. * ISPMT
  943. *
  944. * Returns the interest payment for an investment based on an interest rate and a constant payment schedule.
  945. *
  946. * Excel Function:
  947. * =ISPMT(interest_rate, period, number_payments, PV)
  948. *
  949. * interest_rate is the interest rate for the investment
  950. *
  951. * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments.
  952. *
  953. * number_payments is the number of payments for the annuity
  954. *
  955. * PV is the loan amount or present value of the payments
  956. */
  957. public static function ISPMT()
  958. {
  959. // Return value
  960. $returnValue = 0;
  961. // Get the parameters
  962. $aArgs = PHPExcel_Calculation_Functions :: flattenArray(func_get_args());
  963. $interestRate = array_shift($aArgs);
  964. $period = array_shift($aArgs);
  965. $numberPeriods = array_shift($aArgs);
  966. $principleRemaining = array_shift($aArgs);
  967. // Calculate
  968. $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0);
  969. for($i = 0; $i <= $period; ++ $i)
  970. {
  971. $returnValue = $interestRate * $principleRemaining * - 1;
  972. $principleRemaining -= $principlePayment;
  973. // principle needs to be 0 after the last payment, don't let floating point screw it up
  974. if ($i == $numberPeriods)
  975. {
  976. $returnValue = 0;
  977. }
  978. }
  979. return ($returnValue);
  980. } // function ISPMT()
  981. public static function MIRR($values, $finance_rate, $reinvestment_rate)
  982. {
  983. if (! is_array($values))
  984. return PHPExcel_Calculation_Functions :: VALUE();
  985. $values = PHPExcel_Calculation_Functions :: flattenArray($values);
  986. $finance_rate = PHPExcel_Calculation_Functions :: flattenSingleValue($finance_rate);
  987. $reinvestment_rate = PHPExcel_Calculation_Functions :: flattenSingleValue($reinvestment_rate);
  988. $n = count($values);
  989. $rr = 1.0 + $reinvestment_rate;
  990. $fr = 1.0 + $finance_rate;
  991. $npv_pos = $npv_neg = 0.0;
  992. foreach ($values as $i => $v)
  993. {
  994. if ($v >= 0)
  995. {
  996. $npv_pos += $v / pow($rr, $i);
  997. }
  998. else
  999. {
  1000. $npv_neg += $v / pow($fr, $i);
  1001. }
  1002. }
  1003. if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= - 1))
  1004. {
  1005. return PHPExcel_Calculation_Functions :: VALUE();
  1006. }
  1007. $mirr = pow((- $npv_pos * pow($rr, $n)) / ($npv_neg * ($rr)), (1.0 / ($n - 1))) - 1.0;
  1008. return (is_finite($mirr) ? $mirr : PHPExcel_Calculation_Functions :: VALUE());
  1009. } // function MIRR()
  1010. /**
  1011. * NOMINAL
  1012. *
  1013. * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
  1014. *
  1015. * @param float $effect_rate Effective interest rate
  1016. * @param int $npery Number of compounding payments per year
  1017. * @return float
  1018. */
  1019. public static function NOMINAL($effect_rate = 0, $npery = 0)
  1020. {
  1021. $effect_rate = PHPExcel_Calculation_Functions :: flattenSingleValue($effect_rate);
  1022. $npery = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($npery);
  1023. // Validate parameters
  1024. if ($effect_rate <= 0 || $npery < 1)
  1025. {
  1026. return PHPExcel_Calculation_Functions :: NaN();
  1027. }
  1028. // Calculate
  1029. return $npery * (pow($effect_rate + 1, 1 / $npery) - 1);
  1030. } // function NOMINAL()
  1031. /**
  1032. * NPER
  1033. *
  1034. * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
  1035. *
  1036. * @param float $rate Interest rate per period
  1037. * @param int $pmt Periodic payment (annuity)
  1038. * @param float $pv Present Value
  1039. * @param float $fv Future Value
  1040. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  1041. * @return float
  1042. */
  1043. public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
  1044. {
  1045. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1046. $pmt = PHPExcel_Calculation_Functions :: flattenSingleValue($pmt);
  1047. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  1048. $fv = PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  1049. $type = PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  1050. // Validate parameters
  1051. if ($type != 0 && $type != 1)
  1052. {
  1053. return PHPExcel_Calculation_Functions :: NaN();
  1054. }
  1055. // Calculate
  1056. if (! is_null($rate) && $rate != 0)
  1057. {
  1058. if ($pmt == 0 && $pv == 0)
  1059. {
  1060. return PHPExcel_Calculation_Functions :: NaN();
  1061. }
  1062. return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate);
  1063. }
  1064. else
  1065. {
  1066. if ($pmt == 0)
  1067. {
  1068. return PHPExcel_Calculation_Functions :: NaN();
  1069. }
  1070. return (- $pv - $fv) / $pmt;
  1071. }
  1072. } // function NPER()
  1073. /**
  1074. * NPV
  1075. *
  1076. * Returns the Net Present Value of a cash flow series given a discount rate.
  1077. *
  1078. * @param float Discount interest rate
  1079. * @param array Cash flow series
  1080. * @return float
  1081. */
  1082. public static function NPV()
  1083. {
  1084. // Return value
  1085. $returnValue = 0;
  1086. // Loop through arguments
  1087. $aArgs = PHPExcel_Calculation_Functions :: flattenArray(func_get_args());
  1088. // Calculate
  1089. $rate = array_shift($aArgs);
  1090. for($i = 1; $i <= count($aArgs); ++ $i)
  1091. {
  1092. // Is it a numeric value?
  1093. if (is_numeric($aArgs[$i - 1]))
  1094. {
  1095. $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i);
  1096. }
  1097. }
  1098. // Return
  1099. return $returnValue;
  1100. } // function NPV()
  1101. /**
  1102. * PMT
  1103. *
  1104. * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
  1105. *
  1106. * @param float $rate Interest rate per period
  1107. * @param int $nper Number of periods
  1108. * @param float $pv Present Value
  1109. * @param float $fv Future Value
  1110. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  1111. * @return float
  1112. */
  1113. public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
  1114. {
  1115. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1116. $nper = PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  1117. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  1118. $fv = PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  1119. $type = PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  1120. // Validate parameters
  1121. if ($type != 0 && $type != 1)
  1122. {
  1123. return PHPExcel_Calculation_Functions :: NaN();
  1124. }
  1125. // Calculate
  1126. if (! is_null($rate) && $rate != 0)
  1127. {
  1128. return (- $fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate);
  1129. }
  1130. else
  1131. {
  1132. return (- $pv - $fv) / $nper;
  1133. }
  1134. } // function PMT()
  1135. /**
  1136. * PPMT
  1137. *
  1138. * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
  1139. *
  1140. * @param float $rate Interest rate per period
  1141. * @param int $per Period for which we want to find the interest
  1142. * @param int $nper Number of periods
  1143. * @param float $pv Present Value
  1144. * @param float $fv Future Value
  1145. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  1146. * @return float
  1147. */
  1148. public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
  1149. {
  1150. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1151. $per = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($per);
  1152. $nper = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  1153. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  1154. $fv = PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  1155. $type = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  1156. // Validate parameters
  1157. if ($type != 0 && $type != 1)
  1158. {
  1159. return PHPExcel_Calculation_Functions :: NaN();
  1160. }
  1161. if ($per <= 0 || $per > $nper)
  1162. {
  1163. return PHPExcel_Calculation_Functions :: VALUE();
  1164. }
  1165. // Calculate
  1166. $interestAndPrincipal = self :: _interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
  1167. return $interestAndPrincipal[1];
  1168. } // function PPMT()
  1169. public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis = 0)
  1170. {
  1171. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1172. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1173. $rate = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1174. $yield = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($yield);
  1175. $redemption = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($redemption);
  1176. $frequency = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($frequency);
  1177. $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1178. if (is_string($settlement = PHPExcel_Calculation_DateTime :: _getDateValue($settlement)))
  1179. {
  1180. return PHPExcel_Calculation_Functions :: VALUE();
  1181. }
  1182. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  1183. {
  1184. return PHPExcel_Calculation_Functions :: VALUE();
  1185. }
  1186. if (($settlement > $maturity) || (! self :: _validFrequency($frequency)) || (($basis < 0) || ($basis > 4)))
  1187. {
  1188. return PHPExcel_Calculation_Functions :: NaN();
  1189. }
  1190. $dsc = self :: COUPDAYSNC($settlement, $maturity, $frequency, $basis);
  1191. $e = self :: COUPDAYS($settlement, $maturity, $frequency, $basis);
  1192. $n = self :: COUPNUM($settlement, $maturity, $frequency, $basis);
  1193. $a = self :: COUPDAYBS($settlement, $maturity, $frequency, $basis);
  1194. $baseYF = 1.0 + ($yield / $frequency);
  1195. $rfp = 100 * ($rate / $frequency);
  1196. $de = $dsc / $e;
  1197. $result = $redemption / pow($baseYF, (-- $n + $de));
  1198. for($k = 0; $k <= $n; ++ $k)
  1199. {
  1200. $result += $rfp / (pow($baseYF, ($k + $de)));
  1201. }
  1202. $result -= $rfp * ($a / $e);
  1203. return $result;
  1204. } // function PRICE()
  1205. /**
  1206. * PRICEDISC
  1207. *
  1208. * Returns the price per $100 face value of a discounted security.
  1209. *
  1210. * @param mixed settlement The security's settlement date.
  1211. * The security settlement date is the date after the issue date when the security is traded to the buyer.
  1212. * @param mixed maturity The security's maturity date.
  1213. * The maturity date is the date when the security expires.
  1214. * @param int discount The security's discount rate.
  1215. * @param int redemption The security's redemption value per $100 face value.
  1216. * @param int basis The type of day count to use.
  1217. * 0 or omitted US (NASD) 30/360
  1218. * 1 Actual/actual
  1219. * 2 Actual/360
  1220. * 3 Actual/365
  1221. * 4 European 30/360
  1222. * @return float
  1223. */
  1224. public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0)
  1225. {
  1226. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1227. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1228. $discount = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($discount);
  1229. $redemption = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($redemption);
  1230. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1231. // Validate
  1232. if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis)))
  1233. {
  1234. if (($discount <= 0) || ($redemption <= 0))
  1235. {
  1236. return PHPExcel_Calculation_Functions :: NaN();
  1237. }
  1238. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  1239. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1240. {
  1241. // return date error
  1242. return $daysBetweenSettlementAndMaturity;
  1243. }
  1244. return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity);
  1245. }
  1246. return PHPExcel_Calculation_Functions :: VALUE();
  1247. } // function PRICEDISC()
  1248. /**
  1249. * PRICEMAT
  1250. *
  1251. * Returns the price per $100 face value of a security that pays interest at maturity.
  1252. *
  1253. * @param mixed settlement The security's settlement date.
  1254. * The security's settlement date is the date after the issue date when the security is traded to the buyer.
  1255. * @param mixed maturity The security's maturity date.
  1256. * The maturity date is the date when the security expires.
  1257. * @param mixed issue The security's issue date.
  1258. * @param int rate The security's interest rate at date of issue.
  1259. * @param int yield The security's annual yield.
  1260. * @param int basis The type of day count to use.
  1261. * 0 or omitted US (NASD) 30/360
  1262. * 1 Actual/actual
  1263. * 2 Actual/360
  1264. * 3 Actual/365
  1265. * 4 European 30/360
  1266. * @return float
  1267. */
  1268. public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0)
  1269. {
  1270. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1271. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1272. $issue = PHPExcel_Calculation_Functions :: flattenSingleValue($issue);
  1273. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1274. $yield = PHPExcel_Calculation_Functions :: flattenSingleValue($yield);
  1275. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1276. // Validate
  1277. if (is_numeric($rate) && is_numeric($yield))
  1278. {
  1279. if (($rate <= 0) || ($yield <= 0))
  1280. {
  1281. return PHPExcel_Calculation_Functions :: NaN();
  1282. }
  1283. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($settlement), $basis);
  1284. if (! is_numeric($daysPerYear))
  1285. {
  1286. return $daysPerYear;
  1287. }
  1288. $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $settlement, $basis);
  1289. if (! is_numeric($daysBetweenIssueAndSettlement))
  1290. {
  1291. // return date error
  1292. return $daysBetweenIssueAndSettlement;
  1293. }
  1294. $daysBetweenIssueAndSettlement *= $daysPerYear;
  1295. $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $maturity, $basis);
  1296. if (! is_numeric($daysBetweenIssueAndMaturity))
  1297. {
  1298. // return date error
  1299. return $daysBetweenIssueAndMaturity;
  1300. }
  1301. $daysBetweenIssueAndMaturity *= $daysPerYear;
  1302. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  1303. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1304. {
  1305. // return date error
  1306. return $daysBetweenSettlementAndMaturity;
  1307. }
  1308. $daysBetweenSettlementAndMaturity *= $daysPerYear;
  1309. return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) / (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100));
  1310. }
  1311. return PHPExcel_Calculation_Functions :: VALUE();
  1312. } // function PRICEMAT()
  1313. /**
  1314. * PV
  1315. *
  1316. * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
  1317. *
  1318. * @param float $rate Interest rate per period
  1319. * @param int $nper Number of periods
  1320. * @param float $pmt Periodic payment (annuity)
  1321. * @param float $fv Future Value
  1322. * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
  1323. * @return float
  1324. */
  1325. public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0)
  1326. {
  1327. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1328. $nper = PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  1329. $pmt = PHPExcel_Calculation_Functions :: flattenSingleValue($pmt);
  1330. $fv = PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  1331. $type = PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  1332. // Validate parameters
  1333. if ($type != 0 && $type != 1)
  1334. {
  1335. return PHPExcel_Calculation_Functions :: NaN();
  1336. }
  1337. // Calculate
  1338. if (! is_null($rate) && $rate != 0)
  1339. {
  1340. return (- $pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper);
  1341. }
  1342. else
  1343. {
  1344. return - $fv - $pmt * $nper;
  1345. }
  1346. } // function PV()
  1347. /**
  1348. * RATE
  1349. *
  1350. **/
  1351. public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1)
  1352. {
  1353. $nper = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($nper);
  1354. $pmt = PHPExcel_Calculation_Functions :: flattenSingleValue($pmt);
  1355. $pv = PHPExcel_Calculation_Functions :: flattenSingleValue($pv);
  1356. $fv = (is_null($fv)) ? 0.0 : PHPExcel_Calculation_Functions :: flattenSingleValue($fv);
  1357. $type = (is_null($type)) ? 0 : (int) PHPExcel_Calculation_Functions :: flattenSingleValue($type);
  1358. $guess = (is_null($guess)) ? 0.1 : PHPExcel_Calculation_Functions :: flattenSingleValue($guess);
  1359. $rate = $guess;
  1360. if (abs($rate) < FINANCIAL_PRECISION)
  1361. {
  1362. $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
  1363. }
  1364. else
  1365. {
  1366. $f = exp($nper * log(1 + $rate));
  1367. $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
  1368. }
  1369. $y0 = $pv + $pmt * $nper + $fv;
  1370. $y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
  1371. // find root by secant method
  1372. $i = $x0 = 0.0;
  1373. $x1 = $rate;
  1374. while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS))
  1375. {
  1376. $rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
  1377. $x0 = $x1;
  1378. $x1 = $rate;
  1379. if (abs($rate) < FINANCIAL_PRECISION)
  1380. {
  1381. $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
  1382. }
  1383. else
  1384. {
  1385. $f = exp($nper * log(1 + $rate));
  1386. $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
  1387. }
  1388. $y0 = $y1;
  1389. $y1 = $y;
  1390. ++ $i;
  1391. }
  1392. return $rate;
  1393. } // function RATE()
  1394. /**
  1395. * RECEIVED
  1396. *
  1397. * Returns the price per $100 face value of a discounted security.
  1398. *
  1399. * @param mixed settlement The security's settlement date.
  1400. * The security settlement date is the date after the issue date when the security is traded to the buyer.
  1401. * @param mixed maturity The security's maturity date.
  1402. * The maturity date is the date when the security expires.
  1403. * @param int investment The amount invested in the security.
  1404. * @param int discount The security's discount rate.
  1405. * @param int basis The type of day count to use.
  1406. * 0 or omitted US (NASD) 30/360
  1407. * 1 Actual/actual
  1408. * 2 Actual/360
  1409. * 3 Actual/365
  1410. * 4 European 30/360
  1411. * @return float
  1412. */
  1413. public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0)
  1414. {
  1415. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1416. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1417. $investment = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($investment);
  1418. $discount = (float) PHPExcel_Calculation_Functions :: flattenSingleValue($discount);
  1419. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1420. // Validate
  1421. if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis)))
  1422. {
  1423. if (($investment <= 0) || ($discount <= 0))
  1424. {
  1425. return PHPExcel_Calculation_Functions :: NaN();
  1426. }
  1427. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  1428. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1429. {
  1430. // return date error
  1431. return $daysBetweenSettlementAndMaturity;
  1432. }
  1433. return $investment / (1 - ($discount * $daysBetweenSettlementAndMaturity));
  1434. }
  1435. return PHPExcel_Calculation_Functions :: VALUE();
  1436. } // function RECEIVED()
  1437. /**
  1438. * SLN
  1439. *
  1440. * Returns the straight-line depreciation of an asset for one period
  1441. *
  1442. * @param cost Initial cost of the asset
  1443. * @param salvage Value at the end of the depreciation
  1444. * @param life Number of periods over which the asset is depreciated
  1445. * @return float
  1446. */
  1447. public static function SLN($cost, $salvage, $life)
  1448. {
  1449. $cost = PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  1450. $salvage = PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  1451. $life = PHPExcel_Calculation_Functions :: flattenSingleValue($life);
  1452. // Calculate
  1453. if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)))
  1454. {
  1455. if ($life < 0)
  1456. {
  1457. return PHPExcel_Calculation_Functions :: NaN();
  1458. }
  1459. return ($cost - $salvage) / $life;
  1460. }
  1461. return PHPExcel_Calculation_Functions :: VALUE();
  1462. } // function SLN()
  1463. /**
  1464. * SYD
  1465. *
  1466. * Returns the sum-of-years' digits depreciation of an asset for a specified period.
  1467. *
  1468. * @param cost Initial cost of the asset
  1469. * @param salvage Value at the end of the depreciation
  1470. * @param life Number of periods over which the asset is depreciated
  1471. * @param period Period
  1472. * @return float
  1473. */
  1474. public static function SYD($cost, $salvage, $life, $period)
  1475. {
  1476. $cost = PHPExcel_Calculation_Functions :: flattenSingleValue($cost);
  1477. $salvage = PHPExcel_Calculation_Functions :: flattenSingleValue($salvage);
  1478. $life = PHPExcel_Calculation_Functions :: flattenSingleValue($life);
  1479. $period = PHPExcel_Calculation_Functions :: flattenSingleValue($period);
  1480. // Calculate
  1481. if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)))
  1482. {
  1483. if (($life < 1) || ($period > $life))
  1484. {
  1485. return PHPExcel_Calculation_Functions :: NaN();
  1486. }
  1487. return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1));
  1488. }
  1489. return PHPExcel_Calculation_Functions :: VALUE();
  1490. } // function SYD()
  1491. /**
  1492. * TBILLEQ
  1493. *
  1494. * Returns the bond-equivalent yield for a Treasury bill.
  1495. *
  1496. * @param mixed settlement The Treasury bill's settlement date.
  1497. * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  1498. * @param mixed maturity The Treasury bill's maturity date.
  1499. * The maturity date is the date when the Treasury bill expires.
  1500. * @param int discount The Treasury bill's discount rate.
  1501. * @return float
  1502. */
  1503. public static function TBILLEQ($settlement, $maturity, $discount)
  1504. {
  1505. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1506. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1507. $discount = PHPExcel_Calculation_Functions :: flattenSingleValue($discount);
  1508. // Use TBILLPRICE for validation
  1509. $testValue = self :: TBILLPRICE($settlement, $maturity, $discount);
  1510. if (is_string($testValue))
  1511. {
  1512. return $testValue;
  1513. }
  1514. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  1515. {
  1516. return PHPExcel_Calculation_Functions :: VALUE();
  1517. }
  1518. if (PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_OPENOFFICE)
  1519. {
  1520. ++ $maturity;
  1521. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity) * 360;
  1522. }
  1523. else
  1524. {
  1525. $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime :: _getDateValue($maturity) - PHPExcel_Calculation_DateTime :: _getDateValue($settlement));
  1526. }
  1527. return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity);
  1528. } // function TBILLEQ()
  1529. /**
  1530. * TBILLPRICE
  1531. *
  1532. * Returns the yield for a Treasury bill.
  1533. *
  1534. * @param mixed settlement The Treasury bill's settlement date.
  1535. * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  1536. * @param mixed maturity The Treasury bill's maturity date.
  1537. * The maturity date is the date when the Treasury bill expires.
  1538. * @param int discount The Treasury bill's discount rate.
  1539. * @return float
  1540. */
  1541. public static function TBILLPRICE($settlement, $maturity, $discount)
  1542. {
  1543. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1544. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1545. $discount = PHPExcel_Calculation_Functions :: flattenSingleValue($discount);
  1546. if (is_string($maturity = PHPExcel_Calculation_DateTime :: _getDateValue($maturity)))
  1547. {
  1548. return PHPExcel_Calculation_Functions :: VALUE();
  1549. }
  1550. // Validate
  1551. if (is_numeric($discount))
  1552. {
  1553. if ($discount <= 0)
  1554. {
  1555. return PHPExcel_Calculation_Functions :: NaN();
  1556. }
  1557. if (PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_OPENOFFICE)
  1558. {
  1559. ++ $maturity;
  1560. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity) * 360;
  1561. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1562. {
  1563. // return date error
  1564. return $daysBetweenSettlementAndMaturity;
  1565. }
  1566. }
  1567. else
  1568. {
  1569. $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime :: _getDateValue($maturity) - PHPExcel_Calculation_DateTime :: _getDateValue($settlement));
  1570. }
  1571. if ($daysBetweenSettlementAndMaturity > 360)
  1572. {
  1573. return PHPExcel_Calculation_Functions :: NaN();
  1574. }
  1575. $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360));
  1576. if ($price <= 0)
  1577. {
  1578. return PHPExcel_Calculation_Functions :: NaN();
  1579. }
  1580. return $price;
  1581. }
  1582. return PHPExcel_Calculation_Functions :: VALUE();
  1583. } // function TBILLPRICE()
  1584. /**
  1585. * TBILLYIELD
  1586. *
  1587. * Returns the yield for a Treasury bill.
  1588. *
  1589. * @param mixed settlement The Treasury bill's settlement date.
  1590. * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
  1591. * @param mixed maturity The Treasury bill's maturity date.
  1592. * The maturity date is the date when the Treasury bill expires.
  1593. * @param int price The Treasury bill's price per $100 face value.
  1594. * @return float
  1595. */
  1596. public static function TBILLYIELD($settlement, $maturity, $price)
  1597. {
  1598. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1599. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1600. $price = PHPExcel_Calculation_Functions :: flattenSingleValue($price);
  1601. // Validate
  1602. if (is_numeric($price))
  1603. {
  1604. if ($price <= 0)
  1605. {
  1606. return PHPExcel_Calculation_Functions :: NaN();
  1607. }
  1608. if (PHPExcel_Calculation_Functions :: getCompatibilityMode() == PHPExcel_Calculation_Functions :: COMPATIBILITY_OPENOFFICE)
  1609. {
  1610. ++ $maturity;
  1611. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity) * 360;
  1612. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1613. {
  1614. // return date error
  1615. return $daysBetweenSettlementAndMaturity;
  1616. }
  1617. }
  1618. else
  1619. {
  1620. $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime :: _getDateValue($maturity) - PHPExcel_Calculation_DateTime :: _getDateValue($settlement));
  1621. }
  1622. if ($daysBetweenSettlementAndMaturity > 360)
  1623. {
  1624. return PHPExcel_Calculation_Functions :: NaN();
  1625. }
  1626. return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity);
  1627. }
  1628. return PHPExcel_Calculation_Functions :: VALUE();
  1629. } // function TBILLYIELD()
  1630. public static function XIRR($values, $dates, $guess = 0.1)
  1631. {
  1632. if ((! is_array($values)) && (! is_array($dates)))
  1633. return PHPExcel_Calculation_Functions :: VALUE();
  1634. $values = PHPExcel_Calculation_Functions :: flattenArray($values);
  1635. $dates = PHPExcel_Calculation_Functions :: flattenArray($dates);
  1636. $guess = PHPExcel_Calculation_Functions :: flattenSingleValue($guess);
  1637. if (count($values) != count($dates))
  1638. return PHPExcel_Calculation_Functions :: NaN();
  1639. // create an initial range, with a root somewhere between 0 and guess
  1640. $x1 = 0.0;
  1641. $x2 = $guess;
  1642. $f1 = self :: XNPV($x1, $values, $dates);
  1643. $f2 = self :: XNPV($x2, $values, $dates);
  1644. for($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++ $i)
  1645. {
  1646. if (($f1 * $f2) < 0.0)
  1647. break;
  1648. if (abs($f1) < abs($f2))
  1649. {
  1650. $f1 = self :: XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
  1651. }
  1652. else
  1653. {
  1654. $f2 = self :: XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
  1655. }
  1656. }
  1657. if (($f1 * $f2) > 0.0)
  1658. return PHPExcel_Calculation_Functions :: VALUE();
  1659. $f = self :: XNPV($x1, $values, $dates);
  1660. if ($f < 0.0)
  1661. {
  1662. $rtb = $x1;
  1663. $dx = $x2 - $x1;
  1664. }
  1665. else
  1666. {
  1667. $rtb = $x2;
  1668. $dx = $x1 - $x2;
  1669. }
  1670. for($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++ $i)
  1671. {
  1672. $dx *= 0.5;
  1673. $x_mid = $rtb + $dx;
  1674. $f_mid = self :: XNPV($x_mid, $values, $dates);
  1675. if ($f_mid <= 0.0)
  1676. $rtb = $x_mid;
  1677. if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION))
  1678. return $x_mid;
  1679. }
  1680. return PHPExcel_Calculation_Functions :: VALUE();
  1681. }
  1682. /**
  1683. * XNPV
  1684. *
  1685. * Returns the net present value for a schedule of cash flows that is not necessarily periodic.
  1686. * To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
  1687. *
  1688. * Excel Function:
  1689. * =XNPV(rate,values,dates)
  1690. *
  1691. * @param float $rate The discount rate to apply to the cash flows.
  1692. * @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.
  1693. * @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.
  1694. * @return float
  1695. */
  1696. public static function XNPV($rate, $values, $dates)
  1697. {
  1698. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1699. if (! is_numeric($rate))
  1700. return PHPExcel_Calculation_Functions :: VALUE();
  1701. if ((! is_array($values)) || (! is_array($dates)))
  1702. return PHPExcel_Calculation_Functions :: VALUE();
  1703. $values = PHPExcel_Calculation_Functions :: flattenArray($values);
  1704. $dates = PHPExcel_Calculation_Functions :: flattenArray($dates);
  1705. $valCount = count($values);
  1706. if ($valCount != count($dates))
  1707. return PHPExcel_Calculation_Functions :: NaN();
  1708. if ((min($values) > 0) || (max($values) < 0))
  1709. return PHPExcel_Calculation_Functions :: VALUE();
  1710. $xnpv = 0.0;
  1711. for($i = 0; $i < $valCount; ++ $i)
  1712. {
  1713. if (! is_numeric($values[$i]))
  1714. return PHPExcel_Calculation_Functions :: VALUE();
  1715. $xnpv += $values[$i] / pow(1 + $rate, PHPExcel_Calculation_DateTime :: DATEDIF($dates[0], $dates[$i], 'd') / 365);
  1716. }
  1717. return (is_finite($xnpv)) ? $xnpv : PHPExcel_Calculation_Functions :: VALUE();
  1718. } // function XNPV()
  1719. /**
  1720. * YIELDDISC
  1721. *
  1722. * Returns the annual yield of a security that pays interest at maturity.
  1723. *
  1724. * @param mixed settlement The security's settlement date.
  1725. * The security's settlement date is the date after the issue date when the security is traded to the buyer.
  1726. * @param mixed maturity The security's maturity date.
  1727. * The maturity date is the date when the security expires.
  1728. * @param int price The security's price per $100 face value.
  1729. * @param int redemption The security's redemption value per $100 face value.
  1730. * @param int basis The type of day count to use.
  1731. * 0 or omitted US (NASD) 30/360
  1732. * 1 Actual/actual
  1733. * 2 Actual/360
  1734. * 3 Actual/365
  1735. * 4 European 30/360
  1736. * @return float
  1737. */
  1738. public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0)
  1739. {
  1740. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1741. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1742. $price = PHPExcel_Calculation_Functions :: flattenSingleValue($price);
  1743. $redemption = PHPExcel_Calculation_Functions :: flattenSingleValue($redemption);
  1744. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1745. // Validate
  1746. if (is_numeric($price) && is_numeric($redemption))
  1747. {
  1748. if (($price <= 0) || ($redemption <= 0))
  1749. {
  1750. return PHPExcel_Calculation_Functions :: NaN();
  1751. }
  1752. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($settlement), $basis);
  1753. if (! is_numeric($daysPerYear))
  1754. {
  1755. return $daysPerYear;
  1756. }
  1757. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  1758. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1759. {
  1760. // return date error
  1761. return $daysBetweenSettlementAndMaturity;
  1762. }
  1763. $daysBetweenSettlementAndMaturity *= $daysPerYear;
  1764. return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity);
  1765. }
  1766. return PHPExcel_Calculation_Functions :: VALUE();
  1767. } // function YIELDDISC()
  1768. /**
  1769. * YIELDMAT
  1770. *
  1771. * Returns the annual yield of a security that pays interest at maturity.
  1772. *
  1773. * @param mixed settlement The security's settlement date.
  1774. * The security's settlement date is the date after the issue date when the security is traded to the buyer.
  1775. * @param mixed maturity The security's maturity date.
  1776. * The maturity date is the date when the security expires.
  1777. * @param mixed issue The security's issue date.
  1778. * @param int rate The security's interest rate at date of issue.
  1779. * @param int price The security's price per $100 face value.
  1780. * @param int basis The type of day count to use.
  1781. * 0 or omitted US (NASD) 30/360
  1782. * 1 Actual/actual
  1783. * 2 Actual/360
  1784. * 3 Actual/365
  1785. * 4 European 30/360
  1786. * @return float
  1787. */
  1788. public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0)
  1789. {
  1790. $settlement = PHPExcel_Calculation_Functions :: flattenSingleValue($settlement);
  1791. $maturity = PHPExcel_Calculation_Functions :: flattenSingleValue($maturity);
  1792. $issue = PHPExcel_Calculation_Functions :: flattenSingleValue($issue);
  1793. $rate = PHPExcel_Calculation_Functions :: flattenSingleValue($rate);
  1794. $price = PHPExcel_Calculation_Functions :: flattenSingleValue($price);
  1795. $basis = (int) PHPExcel_Calculation_Functions :: flattenSingleValue($basis);
  1796. // Validate
  1797. if (is_numeric($rate) && is_numeric($price))
  1798. {
  1799. if (($rate <= 0) || ($price <= 0))
  1800. {
  1801. return PHPExcel_Calculation_Functions :: NaN();
  1802. }
  1803. $daysPerYear = self :: _daysPerYear(PHPExcel_Calculation_DateTime :: YEAR($settlement), $basis);
  1804. if (! is_numeric($daysPerYear))
  1805. {
  1806. return $daysPerYear;
  1807. }
  1808. $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $settlement, $basis);
  1809. if (! is_numeric($daysBetweenIssueAndSettlement))
  1810. {
  1811. // return date error
  1812. return $daysBetweenIssueAndSettlement;
  1813. }
  1814. $daysBetweenIssueAndSettlement *= $daysPerYear;
  1815. $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($issue, $maturity, $basis);
  1816. if (! is_numeric($daysBetweenIssueAndMaturity))
  1817. {
  1818. // return date error
  1819. return $daysBetweenIssueAndMaturity;
  1820. }
  1821. $daysBetweenIssueAndMaturity *= $daysPerYear;
  1822. $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime :: YEARFRAC($settlement, $maturity, $basis);
  1823. if (! is_numeric($daysBetweenSettlementAndMaturity))
  1824. {
  1825. // return date error
  1826. return $daysBetweenSettlementAndMaturity;
  1827. }
  1828. $daysBetweenSettlementAndMaturity *= $daysPerYear;
  1829. return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * ($daysPerYear / $daysBetweenSettlementAndMaturity);
  1830. }
  1831. return PHPExcel_Calculation_Functions :: VALUE();
  1832. } // function YIELDMAT()
  1833. } // class PHPExcel_Calculation_Financial