Package `financial` for Golang: The Math Behind the IRR function
At skyline.ai, IRR is one of our many target variables when using big data from the real estate world in order to predict a real estate investment’s potential profitability.
Because we write some of our code using the Go programming language, we looked for financial library in Go, similar to NumPy’s financial functions available in Python, and were surprised that we couldn’t find any. So we set out to implement package financial in Go, and while we were at it, discovered that computing the IRR metric is kind of fun — and a lot more interesting than what one may assume. So we decided to write this post explaining how we did it.
IRR, or “internal rate of return”, is a well-known metric in the investment world. Given a project’s financial details — the initial down payment and the expected cash flows across the years, IRR provides a somewhat credible benchmark of the investment’s profitability.
In the real estate investment world, IRR is especially useful, because computing the “real” annual yield at the end of the project can be not as straightforward as it may seem. A typical real estate investment includes a down payment (initial investment to acquire the property / pay for the loan), period cash flows (income from rent) and, most importantly, there is usually an exit strategy — we plan to sell the property at a higher cost than what we paid for it. For this, IRR is a great benchmark to look at when comparing different potential investments.
NPV (Net Present Value) Intuition
To understand IRR, one must first understand NPV (“net present value”). The main idea with NPV is that a dollar earned today is more valuable than a dollar earned in a future time (because, for example, if we had the money today, we could have invested it and capitalize).
The idea of NPV is quite intuitive when you think about it. Assuming your salary is $120,000 per year, how would you feel if your employer paid it all in advance at the beginning of the year? That’s obviously worth more than getting it in monthly $10,000 batches, right?
The formula to compute NPV tries translate our profit at the end of the investment period to today’s dollars. It does so by assuming a “discount rate” — an interest rate that will be used to eat up from our returns, to compensate for the potential gains we might have otherwise had. There are many ways to determine this rate and in some cases, if there’s a loan involved, it is common practice to set this rate to equal the interest rate of the loan.
The NPV is given by the following equation:
r: the discount rate (for example, 4.5%)
N: the number of cash flows (for example, if we invest for a period of 4 years, and we want to consider annual cash flows, this number would be 4)
C-n: the n-th cash flow (for example, when n= 0, if we made a net profit of $100,000 during the first year, this would be the number)
Put in simple words: we reduce our cash flow from each year, where the longer we have to wait to see the money, the real cash flow is further reduced (mathematically this occurs because we put the discount rate to the power of the period).
If there’s an initial investment involved (as is usually the case with real estate investments), we subtract that from the result given by the above formula to get our NPV.
Intuitively, IRR is given by answering the following question with regards to NPV: “What is the discount rate that if used, the project would break-even with the same cash inflows?”
In other words, we are trying to find the discount rate that will reduce our profit from this investment to zero (even though we are getting incoming cash flow every year).
Mathematically, IRR is given by setting the NPV formula to 0 and solving for the discount rate.
In mathematical terms, this is a polynomial of degree n. Solving this for r means finding the roots of the polynomial. If we plot this function, the roots are where the function’s curve intercepts with the X axis (or r in this case), producing a zero value for Y.
How does one go about solving this equation? Well, it turns out that there is no analytical solution, only numerical ones. Searching the web yields several brute force approaches (this and this), which perform a scan of all possible for r values in certain precision to try to find a value close enough to zero.
He was a busy guy, Sir Issac Newtown. The following simple to understand method may be used to find the roots of a polynomial, numerically.
The idea is this: we start with a guess value for irr (can be a random number) this is the supposed root — we call it x0. We then define x1 (the next candidate suspected as the root) as the following:
Repeating this process iteratively can bring us closer and closer to the root, if it exists. How does this work?
Let’s break it down to steps:
Our initial case is moving from x1 to x2 (or x0 to x1 for that matter). The initial value for x1 was set to the value above (the value for the initial x, called “the guess”, can be random). f(x1) is depicted by the black point. As we can see it has a positive value. The derivative f’(x1) is positive as well, since the slope of the tangent line (the red in the figure above) at this point is positive (the function is climbing upwards).
Therefore the expression f(x1) / f’(x1) is positive, and since x1 is positive as well, the expression x1-f(x1)/f’(x1) yields an x2 which is smaller than x1 — this is where the tangent line intercepts the X axis in the figure above.
What happens next (x2 to x3)? Well, just about the same, we keep getting a smaller value for out next x:
Now it gets interesting: since f(x3) is negative (curve below y = 0) and the slope of the tangent is still positive (the curve of the function is still at a climbing position), the expression f(x3)/f’(x3) is negative! so x4 = x3-f(x3)/f’(x3) ends up being larger then x3 (contrary to the previous cases).
And, as you can see, x4 is getting closer to the root (where our curve intercepts the x axis).
Finally, x5 gives us a really good estimation / solution for the root (note it’s little to none distance from the actual root):
Here is the entire process animated:
Deriving the NPV function
Cool, so Newton-Rahpson can help us find the root of the polynomial NPV, but we need to compute NPV’s first derivative in order to use it.
Well, using some basic maths, we can compute NPV’ as follows, where
c = the period cash flow
x = is the discount rate we want to get (the irr value in the case NPV = 0)
n = the index of the period (the first year, second year, etc.)
IRR algorithm implementation in Go
Given all of the above, it is pretty straightforward to implement a function to compute IRR. The following is our Go implementation. It follows the method signature introduced by NumPy’s implementation, where the input to the function is an array typically comprised out of the initial investment as the first value and the period cash flows as the rest:
A few notes
- Since a polynomial may have more than a single root, it is actually possible to have more than one solution for IRR. The following publication argues that in such cases, the largest value for IRR is the best: Choosing the Right solution of iRR equation to measure investment success
- There are certain criteria under which the algorithm may not converge. Those are based on the assumptions in the mathematical proof of quadric convergence and things like choosing a really bad initial guess. Read more about this on the Newton’s method Wikipedia page.
- Feel free to help us complete the financial package for Go, we currently only have NPV and IRR: https://github.com/orcaman/financial