IRR
IRR (Internal Rate of Return)
假設:
(1) 現在資產價值(PV)=100
(2) 十年後的未來資產價值(FV)=121.8994
(3) 利率(rate) R= 2%
(4) 期數(nper) n=10 (年)
(5) 十年後的末來值:FV= PV x [(1+R) ^n] = 100 x [(1+2%) ^10] =121.8994元
(6) 現值 :PV = FV / [(1+R)^n] = 121.8994 / [(1+2%) ^10]= 100
所以:
已知本金為100元及十年後的定存本利和為121.8994元,但不知道定存利率為多少,就以用 IRR 來做計算出定存利率的值。
用程式計算:
IRR = Math.round((Math.pow(121.899/100, 1/10) - 1) * 100)
及為Math.round((Math.pow(投資結束後資金總和/原始投入資金, 1/投資總年數) - 1) * 100)
Math.pow(x, y)為 x的y次方,所以轉換為10分之1次方,然後因為原本100 * (1.02 ** 10) ,所以會有
121.899/100
最後面
- 1) * 100)
的原因是要把 1.02 轉換為 2%,方便看。
Math.round 為化整,四捨五入
參考:https://www.moneysmart.tw/articles/%E8%B2%B7%E5%84%B2%E8%93%84%E9%9A%AA%E5%85%88%E6%87%82-irr/
較複雜的公式
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;
}
e.g. 第一年投入25,之後每年的利息分別為,2,3,3,3最後一年退出時賣出30
IRR([-25,2,3,3,3,30]) = 0.12258040492894852 = 12.26%
e.g. 投入三年,第一年投入10元,之後三年的利息均得到2元,利率及為20%。
IRR([-10,2,2,12]) = 0.2
但上面的公式還是會有不準確的時候
參考 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;
加強版
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;
}
Last updated