> For the complete documentation index, see [llms.txt](https://easonwang.gitbook.io/finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://easonwang.gitbook.io/finance/irr.md).

# 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/](https://www.moneysmart.tw/articles/買儲蓄險先懂-irr/)

## 較複雜的公式

```javascript
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> 新增了加強版的算法

```javascript
let guess = Math.pow(arrSum(values) / values[0], 1 / ((values.length - 1) / 2 + 1)) - 1;
```

加強版

```javascript
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;
}
```
