# 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/>

## 較複雜的公式

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://easonwang.gitbook.io/finance/irr.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
