commit
message
[IRR] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-06-30 13:02:07
stats
8 file(s) changed,
122 insertions(+),
5 deletions(-)
files
DOCS.md
TODO.md
dist/Formulas/AllFormulas.js
dist/Formulas/Financial.js
src/Formulas/AllFormulas.ts
src/Formulas/Financial.ts
tests/Formulas/FinancialTest.ts
tests/SheetFormulaTest.ts
1diff --git a/DOCS.md b/DOCS.md
2index 774de27..49e50df 100644
3--- a/DOCS.md
4+++ b/DOCS.md
5@@ -503,6 +503,16 @@
6 @returns {number}
7 @constructor TODO: This relies on NPV and will therefore be prone to floating-point errors.
8 ```
9+
10+### IRR
11+
12+```
13+ Calculates the internal rate of return for an investment. The values represent cash flow values at regular intervals; at least one value must be negative (payments), and at least one value must be positive (income). Relevant StackOverflow discussion: https:tackoverflow.comquestion15089151javascript-irr-internal-rate-of-return-formula-accuracy
14+@param values - Range containing values.
15+@param guess - [OPTIONAL] - The estimated value. Defaults to 0.01.
16+@returns {number}
17+@constructor
18+```
19 ## Info
20
21
22diff --git a/TODO.md b/TODO.md
23index 88df852..cc6ce41 100644
24--- a/TODO.md
25+++ b/TODO.md
26@@ -141,7 +141,6 @@ For example 64 tbs to a qt.
27 * FVSCHEDULE
28 * INTRATE
29 * IPMT
30-* IRR
31 * PPMT - Similar to PMT, which is already written.
32 * PRICE
33 * PRICEDISC
34diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
35index f4f8937..96cf996 100644
36--- a/dist/Formulas/AllFormulas.js
37+++ b/dist/Formulas/AllFormulas.js
38@@ -116,6 +116,7 @@ exports.NPV = Financial_1.NPV;
39 exports.NPER = Financial_1.NPER;
40 exports.NOMINAL = Financial_1.NOMINAL;
41 exports.MIRR = Financial_1.MIRR;
42+exports.IRR = Financial_1.IRR;
43 var Statistical_1 = require("./Statistical");
44 exports.AVERAGE = Statistical_1.AVERAGE;
45 exports.AVERAGEA = Statistical_1.AVERAGEA;
46diff --git a/dist/Formulas/Financial.js b/dist/Formulas/Financial.js
47index ae57292..8a6278a 100644
48--- a/dist/Formulas/Financial.js
49+++ b/dist/Formulas/Financial.js
50@@ -577,3 +577,41 @@ var MIRR = function (values, financeRate, reinvestRate) {
51 return Math.pow(num / den, 1 / (n - 1)) - 1;
52 };
53 exports.MIRR = MIRR;
54+/**
55+ * Calculates the internal rate of return for an investment. The values represent cash flow values at regular intervals;
56+ * at least one value must be negative (payments), and at least one value must be positive (income).
57+ *
58+ * Relevant StackOverflow discussion: https://stackoverflow.com/questions/15089151/javascript-irr-internal-rate-of-return-formula-accuracy
59+ *
60+ * @param values - Range containing values.
61+ * @param guess - [OPTIONAL] - The estimated value. Defaults to 0.01.
62+ * @returns {number}
63+ * @constructor
64+ */
65+var IRR = function (values, guess) {
66+ ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "IRR");
67+ values = Filter_1.Filter.flattenAndThrow(values).map(function (value) {
68+ return TypeConverter_1.TypeConverter.valueToNumber(value);
69+ });
70+ guess = (guess === undefined) ? 0.1 : TypeConverter_1.TypeConverter.firstValueAsNumber(guess);
71+ var min = -1.0;
72+ var max = 10.0;
73+ var val;
74+ var counter = 1;
75+ var MAX_ITERATIONS = 500000;
76+ do {
77+ guess = (min + max) / 2;
78+ val = 0;
79+ for (var j = 0; j < values.length; j++) {
80+ val += values[j] / Math.pow((1 + guess), j);
81+ }
82+ if (val > 0) {
83+ min = guess;
84+ }
85+ else {
86+ max = guess;
87+ }
88+ } while (Math.abs(val) > 0.000001 && ++counter < MAX_ITERATIONS);
89+ return guess;
90+};
91+exports.IRR = IRR;
92diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
93index 80e70fd..90827c5 100644
94--- a/src/Formulas/AllFormulas.ts
95+++ b/src/Formulas/AllFormulas.ts
96@@ -119,7 +119,8 @@ import {
97 NPV,
98 NPER,
99 NOMINAL,
100- MIRR
101+ MIRR,
102+ IRR
103 } from "./Financial";
104 import {
105 AVERAGE,
106@@ -377,5 +378,6 @@ export {
107 NPV,
108 NPER,
109 NOMINAL,
110- MIRR
111+ MIRR,
112+ IRR
113 }
114\ No newline at end of file
115diff --git a/src/Formulas/Financial.ts b/src/Formulas/Financial.ts
116index 3d282bc..0ccc0ac 100644
117--- a/src/Formulas/Financial.ts
118+++ b/src/Formulas/Financial.ts
119@@ -588,6 +588,45 @@ var MIRR = function (values, financeRate, reinvestRate) {
120 return Math.pow(num / den, 1 / (n - 1)) - 1;
121 };
122
123+
124+/**
125+ * Calculates the internal rate of return for an investment. The values represent cash flow values at regular intervals;
126+ * at least one value must be negative (payments), and at least one value must be positive (income).
127+ *
128+ * Relevant StackOverflow discussion: https://stackoverflow.com/questions/15089151/javascript-irr-internal-rate-of-return-formula-accuracy
129+ *
130+ * @param values - Range containing values.
131+ * @param guess - [OPTIONAL] - The estimated value. Defaults to 0.01.
132+ * @returns {number}
133+ * @constructor
134+ */
135+var IRR = function (values, guess?) {
136+ ArgsChecker.checkLengthWithin(arguments, 1, 2, "IRR");
137+ values = Filter.flattenAndThrow(values).map(function (value) {
138+ return TypeConverter.valueToNumber(value);
139+ });
140+ guess = (guess === undefined) ? 0.1 : TypeConverter.firstValueAsNumber(guess);
141+ var min = -1.0;
142+ var max = 10.0;
143+ var val;
144+ var counter = 1;
145+ const MAX_ITERATIONS = 500000;
146+ do {
147+ guess = (min + max) / 2;
148+ val = 0;
149+ for (var j = 0; j < values.length; j++) {
150+ val += values[j] / Math.pow((1 + guess), j);
151+ }
152+ if (val > 0) {
153+ min = guess;
154+ }
155+ else {
156+ max = guess;
157+ }
158+ } while(Math.abs(val) > 0.000001 && ++counter < MAX_ITERATIONS);
159+ return guess;
160+};
161+
162 export {
163 ACCRINT,
164 CUMPRINC,
165@@ -604,5 +643,6 @@ export {
166 NPV,
167 NPER,
168 NOMINAL,
169- MIRR
170+ MIRR,
171+ IRR
172 }
173\ No newline at end of file
174diff --git a/tests/Formulas/FinancialTest.ts b/tests/Formulas/FinancialTest.ts
175index b015061..98fde6c 100644
176--- a/tests/Formulas/FinancialTest.ts
177+++ b/tests/Formulas/FinancialTest.ts
178@@ -14,7 +14,8 @@ import {
179 NPV,
180 NPER,
181 NOMINAL,
182- MIRR
183+ MIRR,
184+ IRR
185 } from "../../src/Formulas/Financial";
186 import {
187 DATE
188@@ -374,4 +375,21 @@ test("MIRR", function() {
189 catchAndAssertEquals(function() {
190 MIRR.apply(this, [[10, 20, 30, -10], 0.05, 0.01, 0.09]);
191 }, ERRORS.NA_ERROR);
192+});
193+
194+
195+test("MIRR", function() {
196+ assertEquals(IRR([-1, 4, 10, 15, -22, 99, 44, 1000, -10]), 5.059102535247803);
197+ assertEquals(IRR([-1, 4, 10, 15, -22, 99, 44, 1000, -10], 0.1), 5.059102535247803);
198+ assertEquals(IRR([-100, 100, 100, 100, 100, 100]), 0.9659482464194298);
199+ assertEquals(IRR([-100, 100, 100, 100, 100]), 0.9275619648396969);
200+ assertEquals(IRR([-4000, 200, 250, 300, 350]), -0.35242662353266496);
201+ assertEquals(IRR([-100, 100]), 9.313225746154785e-9);
202+ assertEquals(IRR([-100, 100, 100]), 0.6180339809507132);
203+ catchAndAssertEquals(function() {
204+ IRR.apply(this, []);
205+ }, ERRORS.NA_ERROR);
206+ catchAndAssertEquals(function() {
207+ IRR.apply(this, [[100, 100, 100], 0.01, 4.4]);
208+ }, ERRORS.NA_ERROR);
209 });
210\ No newline at end of file
211diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
212index 5880ead..100de34 100644
213--- a/tests/SheetFormulaTest.ts
214+++ b/tests/SheetFormulaTest.ts
215@@ -739,6 +739,14 @@ test("Sheet NOMINAL", function(){
216 assertFormulaEquals('=NOMINAL(0.8, 12)', 0.6024201620105654);
217 });
218
219+test("Sheet MIRR", function(){
220+ assertFormulaEquals('=MIRR([10, 20, -30, 40], 0.05, 0.06)', 0.3458084697540138);
221+});
222+
223+test("Sheet IRR", function(){
224+ assertFormulaEquals('=IRR([-100, 100, 100])', 0.6180339809507132);
225+});
226+
227 test("Sheet *", function(){
228 assertFormulaEquals('= 10 * 10', 100);
229 assertFormulaEquals('= 10 * 0', 0);