spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
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);