I hesitate to even call this a milestone. We needed something simple to flesh out how the Calculation structure works. I’ve written rates of return so often I could almost do it in my sleep. It took about a week, with much of it being spent perusing my library of rate of return books, looking for new formula tricks (there weren't any).
This time, I used Mathematica to take the iterative guessing process out to a 6th degree polynomial. I don't think it's any more accurate but the code certainly looks impressive--pages of nothing but complicated, error-prone formulas, although there shouldn't be any errors since Mathematica did all the work. I cut my teeth at dbCAMS by debugging and rewriting their IRR formula when I was still on the support team. And I've rewritten it from scratch several times at other companies. The first time I wrote it completely from scratch it took me more than a month to perfect it, and it involved solving polynomials by hand. So I'm pretty pleased at how quickly we were able to do it this time.
The internal rate of return is a funny number, because it's more of a concept, not a real concrete number. You're essentially looking for a daily value that approximates what would have happened if there were no cash flows. The more data points you have, the tougher the formula gets, until it essentially becomes unsolvable. If we had a Mathematica library attached to our code base, we could probably solve each one like an algebra problem, but we don't. So we have to use an iterative guessing process to arrive at the number. And since these are non-linear formulas, there's no guarantee that it will ever arrive at a number. Many accounts actually have more than one correct IRR number--strange but true.
We added an alternative solving method based on the modified secant method. It seems to be more reliable than my polynomial method, which has problems when the returns get really large or small. So we hit the polynomial method first, which is extremely fast but sometimes can't find an IRR. And if the polynomial method doesn't find an answer, it tries the secant method.
One neat thing has to do with the interface structure itself. Different objects in the system are able to express themselves as ICalculate objects, all of which have start/end values and cash flows. Any ICalculate object can be fed into the return calculations and eventually, into numerous other types of calculations (value, average account size, amount invested during period, etc.). So we write a calculation once to the ICalculate object, then just about everything in the system can use that calculation. Securities, assets, accounts, composites, portfolios, households, etc.