function IRR(values, guess) {
// Calculates the resulting amount
const irrResult = function(values, dates, rate) {
const r = rate + 1;
let result = values[0];
for (let i = 1; i < values.length; i++) {
result += values[i] / Math.pow(r, (dates[i] - dates[0]) / 365);
}
return result;
};
// Calculates the first derivation
const irrResultDeriv = function(values, dates, rate) {
const r = rate + 1;
let result = 0;
for (var i = 1; i < values.length; i++) {
var frac = (dates[i] - dates[0]) / 365;
result -= (frac * values[i]) / Math.pow(r, frac + 1);
}
return result;
};
// Initialize dates and check that values contains at least one positive value and one negative value
let dates = [];
let positive = false;
let negative = false;
for (let i = 0; i < values.length; i++) {
dates[i] = i === 0 ? 0 : dates[i - 1] + 365;
if (values[i] > 0) positive = true;
if (values[i] < 0) negative = true;
}
// Return error if values does not contain at least one positive value and one negative value
if (!positive || !negative) return '#NUM!';
// Initialize guess and resultRate
guess = typeof guess === 'undefined' ? 0.1 : guess;
let resultRate = guess;
// Set maximum epsilon for end of iteration
let epsMax = 1e-10;
// Set maximum number of iterations
let iterMax = 50;
// Implement Newton's method
let newRate, epsRate, resultValue;
let iteration = 0;
let contLoop = true;
do {
resultValue = irrResult(values, dates, resultRate);
newRate = resultRate - resultValue / irrResultDeriv(values, dates, resultRate);
epsRate = Math.abs(newRate - resultRate);
resultRate = newRate;
contLoop = epsRate > epsMax && Math.abs(resultValue) > epsMax;
} while (contLoop && ++iteration < iterMax);
if (contLoop) return '#NUM!';
// Return internal rate of return
return resultRate;
}
function IRR(values) {
// Calculates the resulting amount
const irrResult = function(values, dates, rate) {
const r = rate + 1;
let result = values[0];
for (let i = 1; i < values.length; i++) {
result += values[i] / Math.pow(r, (dates[i] - dates[0]) / 365);
}
return result;
};
// Calculates the first derivation
const irrResultDeriv = function(values, dates, rate) {
const r = rate + 1;
let result = 0;
for (var i = 1; i < values.length; i++) {
var frac = (dates[i] - dates[0]) / 365;
result -= (frac * values[i]) / Math.pow(r, frac + 1);
}
return result;
};
// Initialize dates and check that values contains at least one positive value and one negative value
let dates = [];
let positive = false;
let negative = false;
for (let i = 0; i < values.length; i++) {
dates[i] = i === 0 ? 0 : dates[i - 1] + 365;
if (values[i] > 0) positive = true;
if (values[i] < 0) negative = true;
}
// Return error if values does not contain at least one positive value and one negative value
if (!positive || !negative) return '#NUM!';
// Initialize guess and resultRate
// This value of guess is from Enhanced Newton-Raphson Algorithm
const arrSum = values => values.reduce((a, b) => a + b, 0);
// 參考至 https://www.ijeat.org/wp-content/uploads/papers/v8i3S/C10810283S19.pdf
let guess = Math.pow(arrSum(values) / values[0], 1 / ((values.length - 1) / 2 + 1)) - 1;
let resultRate = guess ? guess : 1e-8;
// Set maximum epsilon for end of iteration
let epsMax = 1e-10;
// Set maximum number of iterations
let iterMax = 50;
// Implement Newton's method
let newRate, epsRate, resultValue;
let iteration = 0;
let contLoop = true;
do {
resultValue = irrResult(values, dates, resultRate);
newRate = resultRate - resultValue / irrResultDeriv(values, dates, resultRate);
epsRate = Math.abs(newRate - resultRate);
resultRate = newRate;
contLoop = epsRate > epsMax && Math.abs(resultValue) > epsMax;
} while (contLoop && ++iteration < iterMax);
if (contLoop) return '#NUM!';
// Return internal rate of return
return resultRate;
}