Skip to content

Commit 6ada119

Browse files
authored
Merge pull request #17 from sharddith/master
Added XIRR Feature. XIRR determines the IRR for irregular intervals.
2 parents caafda8 + c13208c commit 6ada119

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ Finance.js
121121
finance.IRR(-500000, 200000, 300000, 200000);
122122
=> 18.82</code></pre>
123123

124+
<h3 id="XIRR">XIRR<br>
125+
126+
<code class="highlight">finance.XIRR([cash flows], [dates], guess);</code></h3>
127+
128+
<p>XIRR is used to determine the Internal Rate of Return when the cash flows are at Irregular intervals.<sup><a href="http://www.financialwisdomforum.org/gummy-stuff/xirr.htm" target="_blank">15</a></sup></p>
129+
130+
<pre><code>// e.g., If the cash flows are -$1,000 on 1st Nov 2015, -$100 on 01 Jul 2016 and $1,200 on 19 Jul 2016, the XIRR is 14.11%.
131+
132+
finance.XIRR([-1000, -100, 1200],[new Date(2015, 11, 1 ), new Date(2016, 7, 1 ), new Date(2016, 7, 19 )],0 );
133+
=> 14.11</code></pre>
134+
124135
<h3 id="LR">Leverage Ratio (LR)<br>
125136

126137
<code class="highlight">finance.LR(total liabilities, total debts, total income);</code></h3>

finance.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,62 @@ Finance.prototype.IAR = function(investmentReturn, inflationRate){
192192
return 100 * (((1 + investmentReturn) / (1 + inflationRate)) - 1);
193193
}
194194

195+
// XIRR - IRR for irregular intervals
196+
Finance.prototype.XIRR = function(cfs, dts, guess) {
197+
if (cfs.length != dts.length) throw new Error('Number of cash flows and dates should match');
198+
199+
var positive, negative;
200+
Array.prototype.slice.call(cfs).forEach(function (value) {
201+
if (value > 0) positive = true;
202+
if (value < 0) negative = true;
203+
});
204+
205+
if (!positive || !negative) throw new Error('XIRR requires at least one positive value and one negative value');
206+
207+
208+
guess = !!guess ? guess : 0;
209+
210+
var limit = 100; //loop limit
211+
var guess_last;
212+
var durs = [];
213+
214+
durs.push(0);
215+
216+
//Create Array of durations from First date
217+
for(var i = 1; i < dts.length; i++) {
218+
durs.push(durYear(dts[0], dts[i]));
219+
}
220+
221+
do {
222+
guess_last = guess;
223+
guess = guess_last - sumEq(cfs, durs, guess_last);
224+
limit--;
225+
226+
}while(guess_last.toFixed(5) != guess.toFixed(5) && limit > 0);
227+
228+
var xirr = guess_last.toFixed(5) != guess.toFixed(5) ? null : guess*100;
229+
230+
return Math.round(xirr * 100) / 100;
231+
};
232+
233+
//Returns Sum of f(x)/f'(x)
234+
function sumEq(cfs, durs, guess) {
235+
var sum_fx = 0;
236+
var sum_fdx = 0;
237+
for (var i = 0; i < cfs.length; i++) {
238+
sum_fx = sum_fx + (cfs[i] / Math.pow(1 + guess, durs[i]));
239+
}
240+
for ( i = 0; i < cfs.length; i++) {
241+
sum_fdx = sum_fdx + (-cfs[i] * durs[i] * Math.pow(1 + guess, -1 - durs[i]));
242+
}
243+
return sum_fx / sum_fdx;
244+
}
245+
246+
//Returns duration in years between two dates
247+
function durYear(first, last) {
248+
return (Math.abs(last.getTime() - first.getTime()) / (1000 * 3600 * 24 * 365));
249+
}
250+
195251
if (typeof exports !== 'undefined') {
196252
if (typeof module !== 'undefined' && module.exports) {
197253
module.exports = Finance;

0 commit comments

Comments
 (0)