FinanceTest.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. <?php
  2. namespace MathPHP\Tests\Finance;
  3. use MathPHP\Finance;
  4. class FinanceTest extends \PHPUnit\Framework\TestCase
  5. {
  6. /**
  7. * @test checkZero
  8. * @dataProvider dataProviderForcheckZero
  9. * @param float $value
  10. * @param float $result
  11. * @throws \Exception
  12. */
  13. public function testCheckZero(float $value, float $result)
  14. {
  15. // Given
  16. $reflection = new \ReflectionClass('MathPHP\Finance');
  17. $method = $reflection->getMethod('checkZero');
  18. $method->setAccessible(true);
  19. // When
  20. $checkedZero = $method->invokeArgs(null, [$value]);
  21. // Then
  22. $this->assertEquals($result, $checkedZero);
  23. }
  24. /**
  25. * @return array
  26. */
  27. public function dataProviderForcheckZero(): array
  28. {
  29. return [
  30. [0.0, 0.0],
  31. [0.1, 0.1],
  32. [0.01, 0.01],
  33. [0.001, 0.001],
  34. [0.0001, 0.0001],
  35. [0.00001, 0.00001],
  36. [0.000001, 0.000001],
  37. [0.0000001, 0.0],
  38. [0.00000001, 0.0],
  39. [0.000000001, 0.0],
  40. [0.0000000001, 0.0],
  41. [Finance::EPSILON, Finance::EPSILON],
  42. [Finance::EPSILON / 2, 0.0],
  43. [1.0, 1.0],
  44. [10.0, 10.0],
  45. [1e8, 1e8],
  46. [1e9, 1e9],
  47. ];
  48. }
  49. /**
  50. * @test pmt
  51. * @dataProvider dataProviderForPmt
  52. * @param float $rate
  53. * @param int $periods
  54. * @param float $pv
  55. * @param float $fv
  56. * @param bool $beginning
  57. * @param float $expected
  58. */
  59. public function testPmt(float $rate, int $periods, float $pv, float $fv, bool $beginning, float $expected)
  60. {
  61. // When
  62. $pmt = Finance::pmt($rate, $periods, $pv, $fv, $beginning);
  63. // Then
  64. $this->assertEqualsWithDelta($expected, $pmt, Finance::EPSILON);
  65. }
  66. /**
  67. * @return array
  68. */
  69. public function dataProviderForPmt(): array
  70. {
  71. return [
  72. [0.0, 1, 0, 0, false, 0.0],
  73. [0.0, 1, 1, 0, false, -1.0],
  74. [0.0, 1, -1, 0, false, 1.0],
  75. [0.0, 1, 1, 0, true, -1.0],
  76. [0.0, 1, -1, 0, true, 1.0],
  77. [0.0, 2, 1, 0, false, -0.5],
  78. [0.0, 2, -1, 0, false, 0.5],
  79. [0.0, 2, 1, 0, true, -0.5],
  80. [0.0, 2, -1, 0, true, 0.5],
  81. [0.05, 30, 250000, 0, false, -16262.858770069148],
  82. [0.05, 30, -250000, 0, false, 16262.858770069148],
  83. [0.05, 30, 250000, 0, true, -15488.436923875368],
  84. [0.05, 30, -250000, 0, true, 15488.436923875368],
  85. [0.04 / 12, 12 * 30, 85000, 0, false, -405.80300114563494],
  86. [0.04 / 12, 12 * 30, -85000, 0, false, 405.80300114563494],
  87. [0.04 / 12, 12 * 30, 85000, 0, true, -404.45481841757629],
  88. [0.04 / 12, 12 * 30, -85000, 0, true, 404.45481841757629],
  89. [0.035 / 12, 12 * 30, 475000, 0, false, -2132.9622670919189],
  90. [0.035 / 12, 12 * 30, -475000, 0, false, 2132.9622670919189],
  91. [0.035 / 12, 12 * 30, 475000, 0, true, -2126.7592193687524],
  92. [0.035 / 12, 12 * 30, -475000, 0, true, 2126.7592193687524],
  93. [0.035 / 12, 12 * 30, 475000, 100000, false, -2290.3402882340679],
  94. [0.035 / 12, 12 * 30, -475000, -100000, false, 2290.3402882340679],
  95. [0.035 / 12, 12 * 30, 475000, 100000, true, -2283.6795561951658],
  96. [0.035 / 12, 12 * 30, -475000, -100000, true, 2283.6795561951658],
  97. [0.10 / 4, 5 * 4, 0, 50000, false, -1957.3564367237279],
  98. [0.10 / 4, 5 * 4, 0, -50000, false, 1957.3564367237279],
  99. [0.10 / 4, 5 * 4, 0, 50000, true, -1909.6160358280276],
  100. [0.10 / 4, 5 * 4, 0, -50000, true, 1909.6160358280276],
  101. [0.035 / 12, 30 * 12, 265000, 0, false, -1189.9684226933862],
  102. [0.035 / 12, 5 * 12, 265000, 265000 / 2, false, -6844.7602923435943],
  103. [0.01 / 52, 3 * 52, -1500, 10000, false, -53.390735324685636],
  104. [0.04 / 4, 20 * 4, 1000000, 0, false, -18218.850112732187],
  105. ];
  106. }
  107. /**
  108. * @test ipmt
  109. * @dataProvider dataProviderForIpmt
  110. * @param float $rate
  111. * @param int $period
  112. * @param int $periods
  113. * @param float $pv
  114. * @param float $fv
  115. * @param bool $beginning
  116. * @param float $expected
  117. */
  118. public function testIPMT(float $rate, int $period, int $periods, float $pv, float $fv, bool $beginning, float $expected)
  119. {
  120. // Given
  121. $ipmt = Finance::ipmt($rate, $period, $periods, $pv, $fv, $beginning);
  122. // Then
  123. $this->assertEqualsWithDelta($expected, $ipmt, Finance::EPSILON);
  124. }
  125. /**
  126. * @return array
  127. */
  128. public function dataProviderForIpmt(): array
  129. {
  130. return [
  131. [0.0, 1, 1, 0, 0, false, 0.0],
  132. [0.0, 1, 2, 0, 0, false, 0.0],
  133. [0.0, 2, 2, 0, 0, false, 0.0],
  134. [0.0, 1, 1, 1, 0, false, 0.0],
  135. [0.0, 1, 2, 1, 0, false, 0.0],
  136. [0.0, 2, 2, 1, 0, false, 0.0],
  137. [0.05, 1, 1, 1, 0, false, -0.05],
  138. [0.05, 1, 2, 1, 0, false, -0.05],
  139. [0.05, 2, 2, 1, 0, false, -0.025609756097560967],
  140. [0.05, 1, 3, 10, 0, false, -0.5],
  141. [0.05, 2, 3, 10, 0, false, -0.34139571768437743],
  142. [0.05, 3, 3, 10, 0, false, -0.17486122125297401],
  143. [0.035 / 12, 1, 360, 475000, 0, false, -1385.4166666666667],
  144. [0.035 / 12, 2, 360, 475000, 0, false, -1383.2363253320932],
  145. [0.035 / 12, 3, 360, 475000, 0, false, -1381.0496246686268],
  146. [0.035 / 12, 358, 360, 475000, 0, false, -18.555076810964287],
  147. [0.035 / 12, 359, 360, 475000, 0, false, -12.388055839311468],
  148. [0.035 / 12, 360, 360, 475000, 0, false, -6.203047723157991],
  149. [0.0, 1, 1, 0, 0, true, 0.0],
  150. [0.0, 1, 2, 0, 0, true, 0.0],
  151. [0.0, 2, 2, 0, 0, true, 0.0],
  152. [0.0, 1, 1, 1, 0, true, 0.0],
  153. [0.0, 1, 2, 1, 0, true, 0.0],
  154. [0.0, 2, 2, 1, 0, true, 0.0],
  155. [0.05, 1, 1, 1, 0, true, 0.0],
  156. [0.05, 1, 2, 1, 0, true, 0.0],
  157. [0.05, 2, 2, 1, 0, true, -0.024390243902439036],
  158. [0.05, 1, 3, 10, 0, true, 0.0],
  159. [0.05, 2, 3, 10, 0, true, -0.32513877874702635],
  160. [0.05, 3, 3, 10, 0, true, -0.16653449643140378],
  161. [0.035 / 12, 1, 360, 475000, 0, true, 0.0],
  162. [0.035 / 12, 2, 360, 475000, 0, true, -1379.213618943508],
  163. [0.035 / 12, 3, 360, 475000, 0, true, -1377.0332776089344],
  164. [0.035 / 12, 358, 360, 475000, 0, true, -18.50111522489313],
  165. [0.035 / 12, 359, 360, 475000, 0, true, -12.352029087806763],
  166. [0.035 / 12, 360, 360, 475000, 0, true, -6.1850081161539432],
  167. ];
  168. }
  169. /**
  170. * @test ipmt not a number
  171. * @dataProvider dataProviderForIpmtNan
  172. * @param float $rate
  173. * @param int $period
  174. * @param int $periods
  175. * @param float $pv
  176. * @param float $fv
  177. * @param bool $beginning
  178. */
  179. public function testIpmtNan(float $rate, int $period, int $periods, float $pv, float $fv, bool $beginning)
  180. {
  181. // When
  182. $ipmt = Finance::ipmt($rate, $period, $periods, $pv, $fv, $beginning);
  183. // Then
  184. $this->assertNan($ipmt);
  185. }
  186. /**
  187. * @return array
  188. */
  189. public function dataProviderForIpmtNan(): array
  190. {
  191. return [
  192. [0.0, 0, 1, 0, 0, false, NAN],
  193. [0.0, 2, 1, 0, 0, false, NAN],
  194. [0.0, 0, 2, 0, 0, false, NAN],
  195. [0.0, 3, 2, 0, 0, false, NAN],
  196. [0.0, 0, 1, 1, 0, false, NAN],
  197. [0.0, 2, 1, 1, 0, false, NAN],
  198. [0.0, 0, 2, 1, 0, false, NAN],
  199. [0.0, 3, 2, 1, 0, false, NAN],
  200. [0.05, 0, 3, 10, 0, false, NAN],
  201. [0.0, 0, 1, 0, 0, true, NAN],
  202. [0.0, 2, 1, 0, 0, true, NAN],
  203. [0.0, 0, 2, 0, 0, true, NAN],
  204. [0.0, 3, 2, 0, 0, true, NAN],
  205. [0.0, 0, 1, 1, 0, true, NAN],
  206. [0.0, 2, 1, 1, 0, true, NAN],
  207. [0.0, 0, 2, 1, 0, true, NAN],
  208. [0.0, 3, 2, 1, 0, true, NAN],
  209. [0.05, 0, 3, 10, 0, true, NAN],
  210. ];
  211. }
  212. /**
  213. * @test ppmt
  214. * @dataProvider dataProviderForPpmt
  215. * @param float $rate
  216. * @param int $period
  217. * @param int $periods
  218. * @param float $pv
  219. * @param float $fv
  220. * @param bool $beginning
  221. * @param float $expected
  222. */
  223. public function testPPMT(float $rate, int $period, int $periods, float $pv, float $fv, bool $beginning, float $expected)
  224. {
  225. // When
  226. $ppmt = Finance::ppmt($rate, $period, $periods, $pv, $fv, $beginning);
  227. // Then
  228. $this->assertEqualsWithDelta($expected, $ppmt, Finance::EPSILON);
  229. }
  230. /**
  231. * @return array
  232. */
  233. public function dataProviderForPpmt(): array
  234. {
  235. return [
  236. [0.0, 1, 1, 0, 0, false, 0.0],
  237. [0.0, 1, 2, 0, 0, false, 0.0],
  238. [0.0, 2, 2, 0, 0, false, 0.0],
  239. [0.0, 1, 1, 1, 0, false, -1.0],
  240. [0.0, 1, 2, 1, 0, false, -0.5],
  241. [0.0, 2, 2, 1, 0, false, -0.5],
  242. [0.05, 1, 1, 1, 0, false, -1.0],
  243. [0.05, 1, 2, 1, 0, false, -0.48780487804878031],
  244. [0.05, 2, 2, 1, 0, false, -0.5121951219512193],
  245. [0.05, 1, 3, 10, 0, false, -3.172085646312448],
  246. [0.05, 2, 3, 10, 0, false, -3.3306899286280705],
  247. [0.05, 3, 3, 10, 0, false, -3.497224425059474],
  248. [0.035 / 12, 1, 360, 475000, 0, false, -747.54560042525213],
  249. [0.035 / 12, 2, 360, 475000, 0, false, -749.72594175982567],
  250. [0.035 / 12, 3, 360, 475000, 0, false, -751.91264242329203],
  251. [0.035 / 12, 358, 360, 475000, 0, false, -2114.4071902809546],
  252. [0.035 / 12, 359, 360, 475000, 0, false, -2120.5742112526073],
  253. [0.035 / 12, 360, 360, 475000, 0, false, -2126.759219368761],
  254. [0.0, 1, 1, 0, 0, true, 0.0],
  255. [0.0, 1, 2, 0, 0, true, 0.0],
  256. [0.0, 2, 2, 0, 0, true, 0.0],
  257. [0.0, 1, 1, 1, 0, true, -1.0],
  258. [0.0, 1, 2, 1, 0, true, -0.5],
  259. [0.0, 2, 2, 1, 0, true, -0.5],
  260. [0.05, 1, 1, 1, 0, true, -1.0],
  261. [0.05, 1, 2, 1, 0, true, -0.5121951219512193],
  262. [0.05, 2, 2, 1, 0, true, -0.48780487804878025],
  263. [0.05, 1, 3, 10, 0, true, -3.497224425059474],
  264. [0.05, 2, 3, 10, 0, true, -3.1720856463124476],
  265. [0.05, 3, 3, 10, 0, true, -3.33068992862807],
  266. [0.035 / 12, 1, 360, 475000, 0, true, -2126.7592193687524],
  267. [0.035 / 12, 2, 360, 475000, 0, true, -747.54560042525168],
  268. [0.035 / 12, 3, 360, 475000, 0, true, -749.72594175982522],
  269. [0.035 / 12, 358, 360, 475000, 0, true, -2108.2581041438666],
  270. [0.035 / 12, 359, 360, 475000, 0, true, -2114.4071902809528],
  271. [0.035 / 12, 360, 360, 475000, 0, true, -2120.5742112526059],
  272. ];
  273. }
  274. /**
  275. * @test ppmt not a number
  276. * @dataProvider dataProviderForPpmtNan
  277. * @param float $rate
  278. * @param int $period
  279. * @param int $periods
  280. * @param float $pv
  281. * @param float $fv
  282. * @param bool $beginning
  283. */
  284. public function testPpmtNan(float $rate, int $period, int $periods, float $pv, float $fv, bool $beginning)
  285. {
  286. // When
  287. $ppmt = Finance::ppmt($rate, $period, $periods, $pv, $fv, $beginning);
  288. // Then
  289. $this->assertNan($ppmt);
  290. }
  291. /**
  292. * @return array
  293. */
  294. public function dataProviderForPpmtNan(): array
  295. {
  296. return [
  297. [0.0, 0, 1, 0, 0, false, NAN],
  298. [0.0, 2, 1, 0, 0, false, NAN],
  299. [0.0, 0, 2, 0, 0, false, NAN],
  300. [0.0, 3, 2, 0, 0, false, NAN],
  301. [0.0, 0, 1, 1, 0, false, NAN],
  302. [0.0, 2, 1, 1, 0, false, NAN],
  303. [0.0, 0, 2, 1, 0, false, NAN],
  304. [0.0, 3, 2, 1, 0, false, NAN],
  305. [0.05, 0, 3, 10, 0, false, NAN],
  306. [0.0, 0, 1, 0, 0, true, NAN],
  307. [0.0, 2, 1, 0, 0, true, NAN],
  308. [0.0, 0, 2, 0, 0, true, NAN],
  309. [0.0, 3, 2, 0, 0, true, NAN],
  310. [0.0, 0, 1, 1, 0, true, NAN],
  311. [0.0, 2, 1, 1, 0, true, NAN],
  312. [0.0, 0, 2, 1, 0, true, NAN],
  313. [0.0, 3, 2, 1, 0, true, NAN],
  314. [0.05, 0, 3, 10, 0, true, NAN],
  315. ];
  316. }
  317. /**
  318. * @test periods
  319. * @dataProvider dataProviderForPeriods
  320. * @param float $rate
  321. * @param float $payment
  322. * @param float $pv
  323. * @param float $fv
  324. * @param bool $beginning
  325. * @param float $expected
  326. */
  327. public function testPeriods(float $rate, float $payment, float $pv, float $fv, bool $beginning, float $expected)
  328. {
  329. // When
  330. $periods = Finance::periods($rate, $payment, $pv, $fv, $beginning);
  331. // Then
  332. $this->assertEqualsWithDelta($expected, $periods, Finance::EPSILON);
  333. }
  334. /**
  335. * @return array
  336. */
  337. public function dataProviderForPeriods(): array
  338. {
  339. return [
  340. [0.0, 1, 0, 0, false, 0.0],
  341. [0.0, 1, 1, 0, false, -1.0],
  342. [0.0, 1, -1, 0, false, 1.0],
  343. [0.0, 1, 0, 1, false, -1.0],
  344. [0.0, 1, 0, -1, false, 1.0],
  345. [0.0, 1, 1, 1, false, -2.0],
  346. [0.0, 1, -1, 1, false, 0.0],
  347. [0.0, 1, 1, -1, false, 0.0],
  348. [0.0, 1, -1, -1, false, 2.0],
  349. [0.0, -1, 0, 0, false, 0.0],
  350. [0.0, -1, 1, 0, false, 1.0],
  351. // numpy 1.12.0b1 gives 1.0 for this, whereas spreadsheet software gives 1.0.
  352. // The interpretation is that a payment of $1 is made to an annuity that owes
  353. // $1. To end up with $0, the payment will need to be reversed once.
  354. [0.0, -1, -1, 0, false, -1.0],
  355. [0.0, -1, 0, 1, false, 1.0],
  356. [0.0, -1, 0, -1, false, -1.0],
  357. [0.0, -1, 1, 1, false, 2.0],
  358. [0.0, -1, -1, 1, false, 0.0],
  359. [0.0, -1, 1, -1, false, 0.0],
  360. [0.0, -1, -1, -1, false, -2.0],
  361. [0.01, -100, 5000, 0, false, 69.660716893574829],
  362. [0.001, -100, 5000, 0, false, 51.318936762444572],
  363. [0.0001, -100, 5000, 0, false, 50.127924464590137],
  364. [0.00001, -100, 5000, 0, false, 50.012754230013776],
  365. [0.000001, -100, 5000, 0, false, 50.001275046275666],
  366. [0.0, -100, 5000, 0, false, 50.0],
  367. [0.035 / 12.0, -2132, 475000, 0, false, 360.28732845118219],
  368. [0.035 / 12.0, -2132.9622670919111, 475000, 0, false, 360.0],
  369. [0.035 / 12.0, -2126.7592193687524, 475000, 0, false, 361.86102291347339],
  370. [0.035 / 12.0, -2126.7592193687524, 475000, 0, true, 360.0],
  371. [0.05, -1000.0, 0, 19600, false, 14.000708059400562],
  372. [0.05, -1000.0, 0, 19600, true, 13.511855106593261],
  373. ];
  374. }
  375. /**
  376. * @test periods not a number
  377. * @dataProvider dataProviderForPeriodsNan
  378. * @param float $rate
  379. * @param float $payment
  380. * @param float $pv
  381. * @param float $fv
  382. * @param bool $beginning
  383. */
  384. public function testPeriodsNan(float $rate, float $payment, float $pv, float $fv, bool $beginning)
  385. {
  386. // When
  387. $periods = Finance::periods($rate, $payment, $pv, $fv, $beginning);
  388. // Then
  389. $this->assertNan($periods);
  390. }
  391. /**
  392. * @return array
  393. */
  394. public function dataProviderForPeriodsNan(): array
  395. {
  396. return [
  397. [0.1, -100, 5000, 0, false],
  398. ];
  399. }
  400. /**
  401. * @test aer
  402. * @dataProvider dataProviderForAer
  403. * @param float $nominal
  404. * @param int $periods
  405. * @param float $expected
  406. */
  407. public function testAer(float $nominal, int $periods, float $expected)
  408. {
  409. // Given
  410. $aer = Finance::aer($nominal, $periods);
  411. // Then
  412. $this->assertEqualsWithDelta($expected, $aer, Finance::EPSILON);
  413. }
  414. /**
  415. * @return array
  416. */
  417. public function dataProviderForAer(): array
  418. {
  419. return [
  420. [0.0, 1, 0.0],
  421. [0.035, 12, 0.035566952945970565],
  422. [0.06, 12, 0.061677811864497611],
  423. [0.01, 1, 0.01],
  424. [0.01, 2, 0.010024999999999729],
  425. [0.01, 4, 0.010037562539062295],
  426. [0.01, 12, 0.010045960887180572],
  427. [0.01, 365, 0.010050028723672],
  428. [0.05, 1, 0.05],
  429. [0.05, 2, 0.05062499999999992],
  430. [0.05, 4, 0.050945336914062445],
  431. [0.05, 12, 0.05116189788173342],
  432. [0.05, 365, 0.051267496467422902],
  433. [0.10, 1, 0.1],
  434. [0.10, 2, 0.1025],
  435. [0.10, 4, 0.10381289062499977],
  436. [0.10, 12, 0.10471306744129683],
  437. [0.10, 365, 0.10515578161622718],
  438. [0.15, 1, 0.15],
  439. [0.15, 2, 0.1556249999999999],
  440. [0.15, 4, 0.15865041503906308],
  441. [0.15, 12, 0.16075451772299854],
  442. [0.15, 365, 0.16179844312826397],
  443. [0.20, 1, 0.2],
  444. [0.20, 2, 0.21000000000000019],
  445. [0.20, 4, 0.21550625000000001],
  446. [0.20, 12, 0.21939108490523185],
  447. [0.20, 365, 0.22133585825175062],
  448. [0.30, 1, 0.3],
  449. [0.30, 2, 0.32249999999999979],
  450. [0.30, 4, 0.33546914062499988],
  451. [0.30, 12, 0.34488882424629752],
  452. [0.30, 365, 0.34969248800768127],
  453. [0.40, 1, 0.4],
  454. [0.40, 2, 0.43999999999999995],
  455. [0.40, 4, 0.4641],
  456. [0.40, 12, 0.48212648965463845],
  457. [0.40, 365, 0.49149799683290096],
  458. [0.50, 1, 0.50],
  459. [0.50, 2, 0.5625],
  460. [0.50, 4, 0.601806640625],
  461. [0.50, 12, 0.63209413272292592],
  462. [0.50, 365, 0.64815725173913452],
  463. [1.0, 1, 1.0],
  464. [1.0, 2, 1.25],
  465. ];
  466. }
  467. /**
  468. * @test nominal
  469. * @dataProvider dataProviderForNominal
  470. * @param float $aer
  471. * @param int $periods
  472. * @param float $rate
  473. */
  474. public function testNominal(float $aer, int $periods, float $rate)
  475. {
  476. // When
  477. $nominal = Finance::nominal($aer, $periods);
  478. // Then
  479. $this->assertEqualsWithDelta($rate, $nominal, Finance::EPSILON);
  480. }
  481. /**
  482. * @return array
  483. */
  484. public function dataProviderForNominal(): array
  485. {
  486. return [
  487. [0.0, 1, 0.0],
  488. [0.035, 12, 0.034450784628919706],
  489. [0.06, 12, 0.058410606784116581],
  490. [0.01, 1, 0.01],
  491. [0.01, 2, 0.0099751242241779003],
  492. [0.01, 4, 0.0099627172572844813],
  493. [0.01, 12, 0.0099544573721539464],
  494. [0.01, 365, 0.0099504664832628098],
  495. [0.05, 1, 0.05],
  496. [0.05, 2, 0.049390153191919861],
  497. [0.05, 4, 0.04908893771615741],
  498. [0.05, 12, 0.048889485403780242],
  499. [0.05, 365, 0.048793425246426159],
  500. [0.10, 1, 0.1],
  501. [0.10, 2, 0.097617696340303262],
  502. [0.10, 4, 0.096454756337780445],
  503. [0.10, 12, 0.095689685146845171],
  504. [0.10, 365, 0.095322624764762054],
  505. [0.15, 1, 0.15],
  506. [0.15, 2, 0.14476105895272173],
  507. [0.15, 4, 0.14223230536648845],
  508. [0.15, 12, 0.14057900303824056],
  509. [0.15, 365, 0.1397887038737311],
  510. [0.20, 1, 0.2],
  511. [0.20, 2, 0.1908902300206643],
  512. [0.20, 4, 0.18654055756842247],
  513. [0.20, 12, 0.18371364599677431],
  514. [0.20, 365, 0.18236710019882918],
  515. [0.30, 1, 0.3],
  516. [0.30, 2, 0.2803508501982761],
  517. [0.30, 4, 0.27115988948976355],
  518. [0.30, 12, 0.26525340712339052],
  519. [0.30, 365, 0.26245858159523849],
  520. [0.40, 1, 0.4],
  521. [0.40, 2, 0.36643191323984636],
  522. [0.40, 4, 0.35102922374910861],
  523. [0.40, 12, 0.34123386871633521],
  524. [0.40, 365, 0.33662737136420096],
  525. [0.50, 1, 0.50],
  526. [0.50, 2, 0.44948974278317788],
  527. [0.50, 4, 0.42672767880128681],
  528. [0.50, 12, 0.41239299758299897],
  529. [0.50, 365, 0.40569039967917164],
  530. [1.0, 1, 1.0],
  531. [1.0, 2, 0.82842712474619029],
  532. ];
  533. }
  534. /**
  535. * @test fv
  536. * @dataProvider dataProviderForFv
  537. * @param float $rate
  538. * @param int $periods
  539. * @param float $pmt
  540. * @param float $pv
  541. * @param bool $beginning
  542. * @param float $expected
  543. */
  544. public function testFv(float $rate, int $periods, float $pmt, float $pv, bool $beginning, float $expected)
  545. {
  546. // When
  547. $fv = Finance::fv($rate, $periods, $pmt, $pv, $beginning);
  548. // Then
  549. $this->assertEqualsWithDelta($expected, $fv, Finance::EPSILON);
  550. }
  551. /**
  552. * @return array
  553. */
  554. public function dataProviderForFv(): array
  555. {
  556. return [
  557. [0.0, 0, 0, 0, false, 0.0],
  558. [0.1, 0, 0, 0, false, 0.0],
  559. [0.0, 1, 0, 0, false, 0.0],
  560. [0.0, 0, 1, 0, false, 0.0],
  561. [0.0, 0, 0, 1, false, -1.0],
  562. [0.0, 0, 0, -1, false, 1.0],
  563. [0.0, 0, 1, 1, false, -1.0],
  564. [0.0, 0, -1, -1, false, 1.0],
  565. [0.0, 0, -1, 1, false, -1.0],
  566. [0.0, 0, 1, -1, false, 1.0],
  567. [0.0, 1, 1, 1, false, -2.0],
  568. [0.0, 1, -1, 1, false, 0.0],
  569. [0.0, 1, 1, -1, false, 0.0],
  570. [0.0, 1, -1, -1, false, 2.0],
  571. [0.1, 0, 0, 0, false, 0.0],
  572. [0.1, 1, 0, 0, false, 0.0],
  573. [0.1, 0, 1, 0, false, 0.0],
  574. [0.1, 0, 0, 1, false, -1.0],
  575. [0.1, 1, 1, 0, false, -1.0],
  576. [0.1, 1, 0, 1, false, -1.1],
  577. [0.1, 1, 1, 1, false, -2.1],
  578. [0.0, 0, 0, 0, true, 0.0],
  579. [0.1, 0, 0, 0, true, 0.0],
  580. [0.0, 1, 0, 0, true, 0.0],
  581. [0.0, 0, 1, 0, true, 0.0],
  582. [0.0, 0, 0, 1, true, -1.0],
  583. [0.0, 0, 0, -1, true, 1.0],
  584. [0.0, 0, 1, 1, true, -1.0],
  585. [0.0, 0, -1, -1, true, 1.0],
  586. [0.0, 0, -1, 1, true, -1.0],
  587. [0.0, 0, 1, -1, true, 1.0],
  588. [0.0, 1, 1, 1, true, -2.0],
  589. [0.0, 1, -1, 1, true, 0.0],
  590. [0.0, 1, 1, -1, true, 0.0],
  591. [0.0, 1, -1, -1, true, 2.0],
  592. [0.1, 0, 0, 0, true, 0.0],
  593. [0.1, 1, 0, 0, true, 0.0],
  594. [0.1, 0, 1, 0, true, 0.0],
  595. [0.1, 0, 0, 1, true, -1.0],
  596. [0.1, 1, 1, 0, true, -1.1],
  597. [0.1, 1, 0, 1, true, -1.1],
  598. [0.1, 1, 1, 1, true, -2.2],
  599. [0.05 / 12, 120, -100, -100, false, 15692.928894335892],
  600. [0.035 / 12, 360, 2132.9622670919189, 475000, false, -2710622.8069359586],
  601. [0.035 / 12, 360, -2132.9622670919189, 475000, false, 0.0],
  602. [0.035 / 12, 360, 2132.9622670919189, -475000, false, 0.0],
  603. [0.035 / 12, 360, -2132.9622670919189, -475000, false, 2710622.8069359586],
  604. [0.035 / 12, 360, 2132.9622670919189, 475000, true, -2714575.798529407],
  605. [0.035 / 12, 360, -2132.9622670919189, 475000, true, 3952.9915934484452],
  606. [0.035 / 12, 360, 2132.9622670919189, -475000, true, -3952.9915934484452],
  607. [0.035 / 12, 360, -2132.9622670919189, -475000, true, 2714575.798529407],
  608. ];
  609. }
  610. /**
  611. * @test pv
  612. * @dataProvider dataProviderForPv
  613. * @param float $rate
  614. * @param int $periods
  615. * @param float $pmt
  616. * @param float $fv
  617. * @param bool $beginning
  618. * @param float $expected
  619. */
  620. public function testPv(float $rate, int $periods, float $pmt, float $fv, bool $beginning, float $expected)
  621. {
  622. // When
  623. $pv = Finance::pv($rate, $periods, $pmt, $fv, $beginning);
  624. // Then
  625. $this->assertEqualsWithDelta($expected, $pv, Finance::EPSILON);
  626. }
  627. /**
  628. * @return array
  629. */
  630. public function dataProviderForPv(): array
  631. {
  632. return [
  633. [0.0, 0, 0, 0, false, 0.0],
  634. [0.1, 0, 0, 0, false, 0.0],
  635. [0.0, 1, 0, 0, false, 0.0],
  636. [0.0, 0, 1, 0, false, 0.0],
  637. [0.0, 0, 0, 1, false, -1.0],
  638. [0.0, 0, 0, -1, false, 1.0],
  639. [0.0, 0, 1, 1, false, -1.0],
  640. [0.0, 0, -1, -1, false, 1.0],
  641. [0.0, 0, -1, 1, false, -1.0],
  642. [0.0, 0, 1, -1, false, 1.0],
  643. [0.0, 1, 1, 1, false, -2.0],
  644. [0.0, 1, -1, 1, false, 0.0],
  645. [0.0, 1, 1, -1, false, 0.0],
  646. [0.0, 1, -1, -1, false, 2.0],
  647. [0.1, 0, 0, 0, false, 0.0],
  648. [0.1, 1, 0, 0, false, 0.0],
  649. [0.1, 0, 1, 0, false, 0.0],
  650. [0.1, 0, 0, 1, false, -1.0],
  651. [0.1, 1, 1, 0, false, -0.90909090909090984],
  652. [0.1, 1, 0, 1, false, -0.90909090909090984],
  653. [0.1, 1, 1, 1, false, -1.8181818181818188],
  654. [0.0, 0, 0, 0, true, 0.0],
  655. [0.1, 0, 0, 0, true, 0.0],
  656. [0.0, 1, 0, 0, true, 0.0],
  657. [0.0, 0, 1, 0, true, 0.0],
  658. [0.0, 0, 0, 1, true, -1.0],
  659. [0.0, 0, 0, -1, true, 1.0],
  660. [0.0, 0, 1, 1, true, -1.0],
  661. [0.0, 0, -1, -1, true, 1.0],
  662. [0.0, 0, -1, 1, true, -1.0],
  663. [0.0, 0, 1, -1, true, 1.0],
  664. [0.0, 1, 1, 1, true, -2.0],
  665. [0.0, 1, -1, 1, true, 0.0],
  666. [0.0, 1, 1, -1, true, 0.0],
  667. [0.0, 1, -1, -1, true, 2.0],
  668. [0.1, 0, 0, 0, true, 0.0],
  669. [0.1, 1, 0, 0, true, 0.0],
  670. [0.1, 0, 1, 0, true, 0.0],
  671. [0.1, 0, 0, 1, true, -1.0],
  672. [0.1, 1, 1, 0, true, -1.0],
  673. [0.1, 1, 0, 1, true, -0.90909090909090906],
  674. [0.1, 1, 1, 1, true, -1.9090909090909098],
  675. [0.035 / 12, 5 * 12, 0, -1000, false, 839.67086876847554],
  676. [0.035 / 12, 5 * 12, 0, -1000, true, 839.67086876847554],
  677. [0.05, 5, -70, -1000, false, 1086.5895334126164],
  678. [0.05, 5, -70, -1000, true, 1101.7427017598243],
  679. [0.035 / 12, 12 * 30, -2132.9622670919189, 0, false, 475000],
  680. ];
  681. }
  682. /**
  683. * @test npv
  684. * @dataProvider dataProviderForNpv
  685. * @param float $rate
  686. * @param array $values
  687. * @param float $expected
  688. */
  689. public function testNpv(float $rate, array $values, float $expected)
  690. {
  691. // When
  692. $npv = Finance::npv($rate, $values);
  693. // Then
  694. $this->assertEqualsWithDelta($expected, $npv, Finance::EPSILON);
  695. }
  696. /**
  697. * @return array
  698. */
  699. public function dataProviderForNpv(): array
  700. {
  701. return [
  702. [0.0, [], 0.0],
  703. [0.0, [0.0], 0.0],
  704. [0.0, [0.0, 0.0], 0.0],
  705. [0.01, [0.0], 0.0],
  706. [0.0, [1.0], 1.0],
  707. [0.0, [1.0, 0.1], 1.1],
  708. [0.0, [1.0, 0.1, 0.5], 1.6],
  709. [0.0, [-1.0], -1.0],
  710. [0.0, [-1.0, -0.1], -1.1],
  711. [0.0, [-1.0, -0.1, -0.5], -1.6],
  712. [0.00, [-1.0, 1.0], 0.0],
  713. [0.01, [-1.0], -1.0],
  714. [0.01, [-1.0, 1.0], -0.0099009900990099098],
  715. [0.01, [-1.0, 1.1], 0.089108910891089188],
  716. [0.01, [-1000, 500, 500], -14.802470346044515],
  717. [0.01, [-1000, 500, 500, 500], 470.49260361777766],
  718. [0.01, [-1000, 100, 200, 300, 400], -29.361706957097013],
  719. [0.12, [-1000, 100, 200, 300, 400], -283.53420449812597],
  720. [0.12, [-1000, 100, 200, 300, 400, 500], 0.17922336117362647],
  721. [0.03, [-1000, 100, -500, 300, 700, 700], 126.09900448974433],
  722. ];
  723. }
  724. /**
  725. * @test rate
  726. * @dataProvider dataProviderForRate
  727. * @param float $periods
  728. * @param float $payment
  729. * @param float $present_value
  730. * @param float $future_value
  731. * @param bool $beginning
  732. * @param float $initial_guess
  733. * @param float $expected
  734. */
  735. public function testRate(float $periods, float $payment, float $present_value, float $future_value, bool $beginning, float $initial_guess, float $expected)
  736. {
  737. // When
  738. $rate = Finance::rate($periods, $payment, $present_value, $future_value, $beginning, $initial_guess, $expected);
  739. // Then
  740. $this->assertEqualsWithDelta($expected, $rate, Finance::EPSILON);
  741. }
  742. /**
  743. * @return array
  744. */
  745. public function dataProviderForRate(): array
  746. {
  747. return [
  748. [1, 0.0, 1.0, 0.0, false, 0.1, -1.0],
  749. [1, 1.0, 1.0, 0.0, false, 0.1, -2.0],
  750. [1, -1.0, 2.0, 0.0, false, 0.1, -0.5],
  751. [1, -1.0, 0.0, 0.0, true, 0.1, -1.0],
  752. [1, 0.0, 1.0, 0.0, true, 0.1, -1.0],
  753. [1, 1.0, 1.0, 0.0, true, 0.1, -1.0],
  754. [1, -1.0, 2.0, 0.0, true, 0.1, -1.0],
  755. [1, -1.0, 0.0, 1.0, true, 0.1, 0.0],
  756. [2, -1.0, 0.0, 0.0, false, 0.1, -2.0],
  757. [2, 0.0, 1.0, 0.0, false, 0.1, -0.99973094574435628],
  758. [2, -1.0, 2.0, 0.0, false, 0.1, 0.0],
  759. [2, -1.0, 0.0, 1.0, false, 0.1, -1.0],
  760. [2, -1.0, 0.0, 0.0, true, 0.1, -1.0],
  761. [2, 0.0, 1.0, 0.0, true, 0.1, -0.99973094574435628],
  762. [2, 1.0, 1.0, 0.0, true, 0.1, -1.0],
  763. [2, -1.0, 2.0, 0.0, true, 0.1, 0.0],
  764. [2, -1.0, 0.0, 1.0, true, 0.1, -0.38196601125010515],
  765. [2, -1, 0, 0, false, 0.1, -2.0],
  766. [2, -1, 0, 1, false, 0.1, -1.0],
  767. [2, -1, 0, 2, false, 0.1, 0.0],
  768. [2, -1, 0, 3, false, 0.1, 1.0],
  769. [2, -1, 0, 0, true, 0.1, -1.0],
  770. [2, -1, 0, 1, true, 0.1, -0.38196601125010515],
  771. [2, -1, 0, 2, true, 0.1, 0.0],
  772. [2, -1, 0, 3, true, 0.1, 0.30277563773199473],
  773. [48, -200, 8000, 0.0, false, 0.1, 0.0077014724882025348],
  774. [360, -2132.96, 475000, 0.0, false, 0.1, 0.0029166595414678938],
  775. ];
  776. }
  777. /**
  778. * @test rate not a number
  779. * @dataProvider dataProviderForRateNan
  780. * @param float $periods
  781. * @param float $payment
  782. * @param float $present_value
  783. * @param float $future_value
  784. * @param bool $beginning
  785. * @param float $initial_guess
  786. */
  787. public function testRateNan(float $periods, float $payment, float $present_value, float $future_value, bool $beginning, float $initial_guess)
  788. {
  789. // When
  790. $rate = Finance::rate($periods, $payment, $present_value, $future_value, $beginning, $initial_guess);
  791. // Then
  792. $this->assertNan($rate);
  793. }
  794. /**
  795. * @return array
  796. */
  797. public function dataProviderForRateNan(): array
  798. {
  799. return [
  800. [0, 0.0, 0.0, 0.0, false, 0.1],
  801. [1, 0.0, 0.0, 0.0, false, 0.1],
  802. [1, -1.0, 0.0, 0.0, false, 0.1],
  803. [1, 0.0, 0.0, 1.0, false, 0.1],
  804. [1, -1.0, 0.0, 1.0, false, 0.1],
  805. [1, 0.0, 0.0, 0.0, true, 0.1],
  806. [1, 0.0, 0.0, 1.0, true, 0.1],
  807. [2, 0.0, 0.0, 0.0, false, 0.1],
  808. [2, 0.0, 0.0, 1.0, false, 0.1],
  809. [2, 1.0, 1.0, 0.0, false, 0.1],
  810. [2, 0.0, 0.0, 0.0, true, 0.1],
  811. [2, 0.0, 0.0, 1.0, true, 0.1],
  812. ];
  813. }
  814. /**
  815. * @test irr
  816. * @dataProvider dataProviderForIrr
  817. * @param array $values
  818. * @param float $initial_guess
  819. * @param float $expected
  820. */
  821. public function testIrr(array $values, float $initial_guess, float $expected)
  822. {
  823. // When
  824. $irr = Finance::irr($values, $initial_guess);
  825. // Then
  826. $this->assertEqualsWithDelta($expected, $irr, Finance::EPSILON);
  827. }
  828. /**
  829. * @return array
  830. */
  831. public function dataProviderForIrr(): array
  832. {
  833. return [
  834. [[1, -1], 0.1, 0.0],
  835. [[-1, 1], 0.1, 0.0],
  836. [[-1, 2], 0.1, 1.0],
  837. [[-1, 3], 0.1, 2.0],
  838. [[-1, 1, 1], 0.1, 0.61803398875009197],
  839. [[-2.3, 2.3, 2.3], 0.1, 0.61803398875009197],
  840. [[2.3, -2.3, -2.3], 0.1, 0.61803398875009197],
  841. [[-2.4, 2.4, 2.4], 0.1, 0.61803398875009197],
  842. [[2.4, -2.4, -2.4], 0.1, 0.61803398875009197],
  843. [[-100, 100, 100], 0.1, 0.61803398875009197],
  844. [[100, -100, -100], 0.1, 0.61803398875009197],
  845. [[-100, 39, 59, 55, 20], 0.1, 0.28094842115996116],
  846. [[-100, 0, 0, 74], 0.1, -0.095495830348972563],
  847. [[-100, 100, 0, -7], 0.1, -0.083299666184932702],
  848. [[-100, 100, 0, 7], 0.1, 0.06205848562992955],
  849. [[-5, 10.5, 1, -8, 1], 0.1, 0.088598338527755019],
  850. [[5, -10.5, -1, 8, -1], 0.1, 0.088598338527755019],
  851. [[-123400, 36200, 54800, 48100], 0.1, 0.059616378567329452],
  852. [[-10, 21, -11], 0.1, 0.1],
  853. [[-10, 21, -11], 0.05, 0.1],
  854. [[-10, 21, -11], 0.01, 0.0],
  855. [[-10, 21, -11], 0.001, 0.0],
  856. [[-10, 21, -11], -0.001, 0.0],
  857. [[-1, 1, 2, 0, 1], 0.1, 1.075483],
  858. [[-1, 1, 0, 2, 1], 0.1, 0.7943097],
  859. [[-14574.6, 3015.43], 0.1, -0.7931037558492171],
  860. [[-14574.6, -14574.6, 9737.3], 0.1, -0.5418243019770277],
  861. [[-14574.6, -14574.6, -14574.6, 19316.3], 0.1, -0.3561376092499646],
  862. [[-14574.6, -14574.6, -14574.6, -14574.6, 31192.3], 0.1, -2.464614995326259],
  863. [[-14574.6, -14574.6, -14574.6, -14574.6, 31192.3], 0.2, -0.2350375548009601],
  864. [[-1000000, 300000, 300000, 300000, 300000, 300000], 0.1, 0.15238237116630671],
  865. [[-1000000, 10000000, -10000000, 0, 0, 0], 0.1, 0.12701665379258315],
  866. [[-1000000, 10000000, -10000000, 0, 0, 0], 0.633, 0.12701665379258315],
  867. [[-1000000, 10000000, -10000000, 0, 0, 0], 0.634, 0.12701665379258315],
  868. [[-1000000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000], 0.1, 0.29999921673],
  869. [[-1000000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000, 300000], 0.1, 0.30],
  870. [[-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,-1607,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250010], 0.01, 0.05090132749],
  871. ];
  872. }
  873. /**
  874. * @test irr not a number
  875. * @dataProvider dataProviderForIrrNan
  876. * @param array $values
  877. * @param float $initial_guess
  878. */
  879. public function testIrrNan(array $values, float $initial_guess)
  880. {
  881. // When
  882. $irr = Finance::irr($values, $initial_guess);
  883. // Then
  884. $this->assertNan($irr);
  885. }
  886. /**
  887. * @return array
  888. */
  889. public function dataProviderForIrrNan(): array
  890. {
  891. return [
  892. [[-1], 0.1],
  893. [[0], 0.1],
  894. [[1], 0.1],
  895. [[1, 0], 0.1],
  896. [[1, 1], 0.1],
  897. [[1, 2], 0.1],
  898. [[1, 3], 0.1],
  899. [[-1, -1], 0.1],
  900. [[-1, 0], 0.1],
  901. ];
  902. }
  903. /**
  904. * @test mirr
  905. * @dataProvider dataProviderForMirr
  906. * @param array $values
  907. * @param float $finance_rate
  908. * @param float $reinvestment_rate
  909. * @param float $expected
  910. */
  911. public function testMirr(array $values, float $finance_rate, float $reinvestment_rate, float $expected)
  912. {
  913. // When
  914. $mirr = Finance::mirr($values, $finance_rate, $reinvestment_rate);
  915. // Then
  916. $this->assertEqualsWithDelta($expected, $mirr, Finance::EPSILON);
  917. }
  918. /**
  919. * @return array
  920. */
  921. public function dataProviderForMirr(): array
  922. {
  923. return [
  924. [[-1, 1], 0.1, 0.1, 0.0],
  925. [[-1, 2], 0.1, 0.1, 1.0],
  926. [[1, -1], 0.05, 0.07, 0.1235],
  927. [[-1000, -4000, 5000, 2000], 0.10, 0.12, 0.17908568603489283],
  928. [[-250000, 50000, 100000, 200000], 0.13, 0.13, 0.14658850347563979],
  929. [[-10000, 18000, -50000, 25000, 25000, 225000], 0.05, 0.1, 0.410571259576975271],
  930. [[-10000, 18000, -50000, 25000, 25000, 225000], 0.1, 0.05, 0.42417388160672798],
  931. [[-100000, 18000, -50000, 25000, 25000, 225000], 0.05, 0.1, 0.16288556821502476],
  932. [[-100000, 18000, -50000, 25000, 25000, 225000], 0.1, 0.05, 0.1630064271697238],
  933. ];
  934. }
  935. /**
  936. * @test mirr not a number
  937. * @dataProvider dataProviderForMirrNan
  938. * @param array $values
  939. * @param float $finance_rate
  940. * @param float $reinvestment_rate
  941. */
  942. public function testMirrNan(array $values, float $finance_rate, float $reinvestment_rate)
  943. {
  944. // When
  945. $mirr = Finance::mirr($values, $finance_rate, $reinvestment_rate);
  946. // Then
  947. $this->assertNan($mirr);
  948. }
  949. /**
  950. * @return array
  951. */
  952. public function dataProviderForMirrNan(): array
  953. {
  954. return [
  955. [[], 0.1, 0.1],
  956. [[-1], 0.1, 0.1],
  957. [[-1, -2], 0.1, 0.1],
  958. [[1], 0.1, 0.1],
  959. [[1, 2], 0.1, 0.1],
  960. ];
  961. }
  962. /**
  963. * @test payback
  964. * @dataProvider dataProviderForPayback
  965. * @param array $values
  966. * @param float $rate
  967. * @param float $expected
  968. */
  969. public function testPayback(array $values, float $rate, float $expected)
  970. {
  971. // When
  972. $payback = Finance::payback($values, $rate);
  973. // Then
  974. $this->assertEqualsWithDelta($expected, $payback, Finance::EPSILON);
  975. }
  976. /**
  977. * @return array
  978. */
  979. public function dataProviderForPayback(): array
  980. {
  981. return [
  982. [[], 0.0, 0.0],
  983. [[0], 0.0, 0.0],
  984. [[1], 0.0, 0.0],
  985. [[0, 0], 0.0, 0.0],
  986. [[1, 0], 0.0, 0.0],
  987. [[0, 1], 0.0, 0.0],
  988. [[1, 1], 0.0, 0.0],
  989. [[-1, 1], 0.0, 1],
  990. [[-1, 0, 1], 0.0, 2],
  991. [[-1, 1, 0], 0.0, 1],
  992. [[-1, 1, 1], 0.0, 1],
  993. [[-1, 1, 1], 0.01, 1.0101],
  994. [[-1, 1, 1], 0.10, 1.11],
  995. [[-1, 1, 1], 0.50, 1.75],
  996. [[-1, 1, 1], 0.60, 1.96],
  997. [[-1, 1, 1], 0.61803398, 1.99999998043464],
  998. [[-2, 1, 1], 0.0, 2],
  999. [[-2, 2, 1], 0.0, 1],
  1000. [[-2, 0, 2], 0.0, 2],
  1001. [[-2, 1, 2], 0.0, 1.5],
  1002. [[-10, 7, 7], 0.0, 1.4285714285714286],
  1003. [[-10, 5, -3, 5, 5], 0.0, 3.6],
  1004. [[-10, 5, -5, 5, 5], 0.0, 4.0],
  1005. [[-10, 5, -5, 5, 6, -1], 0.0, 3.8333333333333335],
  1006. [[-10, 15, -7, 5, 6, -1], 0.0, 2.4],
  1007. [[-10, 15, -7, 5, 6, -10, 1], 0.0, 6],
  1008. [[-1000, 100, 200, 300, 400, 500], 0.0, 4],
  1009. [[-1000, 100, 200, 300, 400, 500], 0.1, 4.7898],
  1010. [[-2324000, 600000, 600000, 600000, 600000, 600000, 600000], 0.11, 5.3318794669369414],
  1011. ];
  1012. }
  1013. /**
  1014. * @test payback not a number
  1015. * @dataProvider dataProviderForPaybackNan
  1016. * @param array $values
  1017. * @param float $rate
  1018. */
  1019. public function testPaybackNan(array $values, float $rate)
  1020. {
  1021. // When
  1022. $payback = Finance::payback($values, $rate);
  1023. // Then
  1024. $this->assertNan($payback);
  1025. }
  1026. /**
  1027. * @return array
  1028. */
  1029. public function dataProviderForPaybackNan(): array
  1030. {
  1031. return [
  1032. [[-1], 0.0],
  1033. [[-1, 0], 0.0],
  1034. [[-1, 1, 1], 0.62],
  1035. [[-1, 1, 1], 0.61803399],
  1036. [[-1, 1, 1], 0.62],
  1037. [[-1, 1, 1], 1.0],
  1038. [[-1, 1, 1], 2.0],
  1039. [[-2], 0.0],
  1040. [[-2, 1], 0.0],
  1041. [[-10, 5, -6, 5, 5], 0.0],
  1042. [[-10, 5, -5, 5, 5, -1], 0.0],
  1043. [[-10, 15, -7, 5, 6, -10], 0.0],
  1044. ];
  1045. }
  1046. /**
  1047. * @test profitabilityIndex
  1048. * @dataProvider dataProviderForProfitabilityIndex
  1049. * @param array $values
  1050. * @param float $rate
  1051. * @param float $expected
  1052. */
  1053. public function testProfitabilityIndex(array $values, float $rate, float $expected)
  1054. {
  1055. // When
  1056. $profitabilityIndex = Finance::profitabilityIndex($values, $rate);
  1057. // Then
  1058. $this->assertEqualsWithDelta($expected, $profitabilityIndex, Finance::EPSILON);
  1059. }
  1060. /**
  1061. * @return array
  1062. */
  1063. public function dataProviderForProfitabilityIndex(): array
  1064. {
  1065. return [
  1066. [[-1], 0.1, 0.0],
  1067. [[-1, 1], 0.0, 1.0],
  1068. [[-1, 1, 1], 0.0, 2.0],
  1069. [[-1, 1, 1, -1], 0.0, 1.0],
  1070. [[-100, 50, 50, 50], 0.10, 1.2434259954921112],
  1071. [[-50000, 65000], 0.0, 1.3],
  1072. [[-50000, 65000], 0.01, 1.2871287128712872],
  1073. [[-40000, 18000, 12000, 10000, 9000, 6000], 0.10, 1.0916697195298382],
  1074. [[-40000, 18000, 12000, -10000, 9000, 6000], 0.10, 0.76091865698558803],
  1075. [[-40000, 18000, 12000, -10000, 9000, 6000], 0.01, 0.88405904911326394],
  1076. [[-40000, 18000, 12000, -10000, 9000, 6000], 0.0, 0.9],
  1077. ];
  1078. }
  1079. /**
  1080. * @test profitabilityIndex not a number
  1081. * @dataProvider dataProviderForProfitabilityIndexNan
  1082. * @param array $values
  1083. * @param float $rate
  1084. */
  1085. public function testProfitabilityIndexNan(array $values, float $rate)
  1086. {
  1087. // When
  1088. $profitabilityIndex = Finance::profitabilityIndex($values, $rate);
  1089. // Then
  1090. $this->assertNan($profitabilityIndex);
  1091. }
  1092. /**
  1093. * @return array
  1094. */
  1095. public function dataProviderForProfitabilityIndexNan(): array
  1096. {
  1097. return [
  1098. [[], 0.1],
  1099. [[1], 0.1],
  1100. ];
  1101. }
  1102. }