Financial.php 109 KB

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