3

How can I implement MS Excel's "IRR()" formula in PHP?

I tried the algorithm mentioned in this page but the results were not accurate and it was really slow.

Tomas Gonzalez
  • 1,124
  • 15
  • 33

3 Answers3

5

After investigating a while, I ended up with the function copied below.

It is based on this question.

function IRR($investment, $flow, $precision = 0.001) {
    $min = 0;
    $max = 1;
    $net_present_value = 1;
    while(abs($net_present_value - $investment) > $precision) {
        $net_present_value = 0;
        $guess = ($min + $max) / 2;
        foreach ($flow as $period => $cashflow) {
            $net_present_value += $cashflow / (1 + $guess) ** ($period + 1);
        }
        if ($net_present_value - $investment > 0) {
            $min = $guess;
        } else {
            $max = $guess;
        }
    }
    return $guess * 100;
}
Tomas Gonzalez
  • 1,124
  • 15
  • 33
  • 4
    You could always have taken a look at the [implementation in PHPExcel](https://github.com/PHPOffice/PHPExcel/blob/1.8/Classes/PHPExcel/Calculation/Financial.php#L1329) – Mark Baker Jul 21 '17 at 21:34
  • How to handle infinite loop when the sum of all cashflow is less than the investment amount? – Dipendra Gurung Apr 03 '19 at 07:29
  • 1
    PHPExcel is archived, got to https://github.com/PHPOffice/PhpSpreadsheet instead – roelleor Feb 18 '20 at 08:45
  • It works well when the cash flows are same or greater then the initial investment. But when we have cash flows less than the initial investment the calculation results in infinity. How to handle infinite loop when the sum of all cashflow is less than the investment amount? – Sudhanshu Dec 10 '21 at 19:41
2

This is modified from Tomas's answer. It stops the infinite loop by a check at the start to make sure cashflow is greater than investment. I have also increased the precision and run it a maximum of 20 times.

private function IRR($investment, $flow, $precision = 0.000001) {

    if (array_sum($flow) < $investment):
        return 0;
    endif;
    $maxIterations = 20;
    $i =0;
    if (is_array($flow)):
        $min = 0;
        $max = 1;
        $net_present_value = 1;
        while ((abs($net_present_value - $investment) > $precision)&& ($i < $maxIterations)) {
            $net_present_value = 0;
            $guess = ($min + $max) / 2;
            foreach ($flow as $period => $cashflow) {
                $net_present_value += $cashflow / (1 + $guess) ** ($period + 1);
            }
            if ($net_present_value - $investment > 0) {
                $min = $guess;
            } else {
                $max = $guess;
            }
            $i++;
        }
        return $guess * 100;
    else:
        return 0;
    endif;
}
JayTee
  • 21
  • 5
  • What if we want to display the IRR in -ve if the sum of cash flows are less than the initial investment? The example calculator here works well but not sure about the code or logic behind the calculation. https://www.thecalculatorsite.com/finance/calculators/irr-calculator.php – Sudhanshu Dec 10 '21 at 19:44
0
 function IRR($values, $guess = 0.1) {
    $maxIterations = 100;
    $tolerance = 0.00001;

    $count = count($values);

    $positive = false;
    $negative = false;
    for ($i = 0; $i < $count; $i++) {
        if ($values[$i] > 0) {
            $positive = true;
       } else {
            $negative = true;
       }
    }

    if (!$positive || !$negative) {
        return null;
    }

    $guess = ($guess == 0) ? 0.1 : $guess;

    for ($i = 0; $i < $maxIterations; $i++) {
        $npv = 0;
        $dnpv = 0;

        for ($j = 0; $j < $count; $j++) {
            $npv += $values[$j] / pow(1 + $guess, $j);
            $dnpv -= $j * $values[$j] / pow(1 + $guess, $j + 1);
        }

        $newGuess = $guess - $npv / $dnpv;

        if (abs($newGuess - $guess) < $tolerance) {
            return $newGuess;
        }

        $guess = $newGuess;
    }
    enter code here
    return null;
}
  • Use this function to calculate IRR, $values is an array of (net discounted cashflows) $values=[-3352742,776707.83698604,1465063.8057571,1342415.8828797,1482113.9169774,1619033.6479796,1738870.9054615] the Result of IRR=IRR($values,0.01)*100=30.469% – Fatma AlShawaf Mar 14 '23 at 12:16