Finding internal rate of return (IRR) In investing, internal rate of return (IRR), the continuously compounded rate of return economically equivalent to a specified series of cashflows, is often a valuable concept.

Your challenge is to demonstrate how to compute IRR in the language of your choice in as few bytes as possible, subject to the following conditions:


Your code should accept arbitrary cashflows, subject only to the condition that the initial cashflow is negative.
You can assume that the cashflow has already been assigned to a variable f (use some other variable name if 'f' is a command name in your language).
Assume cashflow is specified as a series of (date, datum) pairs, in whatever format is most convenient for your language. This challenge is about the IRR computation, not parsing the input.
All functions built into your language are allowed except IRR() or the equivalent, if your language has it, because that's not interesting.
Output should be a real number (thus, 0.14, not "14%").


The solution requires numerical root-finding, and different methods and starting conditions will find slightly different answers. For the purposes of the contest, if you're within 0.001 of the answer reached by Excel's XIRR function, you're close enough.

Example 1:

f={{{2001, 1, 1}, -1}, {{2002, 1, 1}, .3}, {{2005, 1, 1}, .4}, {{2005, 1, 10}, .5}};

0.0584316


Example 2:

f = {{{2011, 1, 1}, -1}, {{2012, 2, 1}, -.3}, {{2015, 3, 1}, .4}, {{2015,3,15},.01}, {{2015, 4, 10}, .8}};

-0.2455921


Example 3:

f = {{{2011, 1, 1}, -1}, {{2012, 2, 1}, 3.3}, {{2015, 3, 1}, 5.4}, {{2015,3,15}, 6.01}, {{2015, 4, 10}, 17.8}};

2.4823336


More information available at http://en.wikipedia.org/wiki/Internal_rate_of_return
Maxima, 149

load(mnewton)$y(d):=?encode\-universal\-time(0,0,0,d[4],d[3],d[2])/31536000$mnewton(f[1][1]+sum(f[i][1]*(1+r)^(y(f[1])-y(f[i])),i,2,length(f)),r,.1);


This code has a bug where some payments might be off by 1/24 day (1 hour). This bug happens if your local time zone moves in or out of daylight-saving time. To fix this bug, add ,0 (2 characters) after d[2].

First set f to a list of lists in the form [[flow, year, month, day], ...]. Then paste this code at Maxima's prompt. The answer comes in the form [[r = float]]. If you want the float by itself, use part(%[1][1],2);

Example 1:

(%i150) f : [[-1, 2001, 1, 1], [.3, 2002, 1, 1], [.4, 2005, 1, 1],
             [.5, 2005, 1, 10]]$

(%i151) load(mnewton)$y(d):=?encode\-universal\-time(0,0,0,d[4],d[3],d[2])/31536000$mnewton(sum(f[i][1]*(1+r)^(y(f[1])-y(f[i])),i,1,length(f)),r,.1);
(%o153)                   [[r = .058394251994029284]]


Example 2:

(%i154) f : [[-1, 2011, 1, 1], [-.3, 2012, 2, 1], [.4, 2015, 3, 1],
             [.01, 2015, 3, 15], [.8, 2015, 4, 10]]$

(%i155) load(mnewton)$y(d):=?encode\-universal\-time(0,0,0,d[4],d[3],d[2])/31536000$mnewton(sum(f[i][1]*(1+r)^(y(f[1])-y(f[i])),i,1,length(f)),r,.1);
(%o157)                  [[r = - .017843072768412977]]


Example 3:

(%i158) f : [[-1, 2011, 1, 1], [3.3, 2012, 2, 1], [5.4, 2015, 3, 1],
             [6.01, 2015, 3, 15], [17.8, 2015, 4, 10]]$

(%i159) load(mnewton)$y(d):=?encode\-universal\-time(0,0,0,d[4],d[3],d[2])/31536000$mnewton(sum(f[i][1]*(1+r)^(y(f[1])-y(f[i])),i,1,length(f)),r,.1);
(%o161)                   [[r = 2.4823712861605407]]


My time zone is America/New_York. Because of the daylight-saving bug, other time zones might give slightly different answers.

Ungolfed

load(mnewton)$

/*
Returns the number of 365-day periods since the epoch, when called as
year([year, month, day]).
*/
year(date):=
?encode\-universal\-time(
  /* s, m, h, day, month, year, time zone */
  0, 0, 0, date[3], date[2], date[1], 0) /
31536000 /* seconds in 365 days */$

/*
Finds a numerical approximation for the internal rate of return for a
list of cash flows on a list of dates.  The dates must be a list of
lists in the form

    [[year, month, day], [year, month, day], ...]

The first date in the list is the present date for calculating the
present value of each cash flow.  Returns the rate for each 365-day
period.
*/
xirr(flows, dates):=
part(
  /* Solve for rate where net present value = 0. */
  mnewton(
    sum(
      /* present value of flows[i] on dates[i] */
      flows[i] * (1 + rate)^(year(dates[1]) - year(dates[i])),
      i, 1, length(flows)),
    rate  /* solve for rate */,
    .1    /* initial guess */)
  [1][1], /* extract 1st solution, 1st variable */
  2       /* value in variable = value */)$


Here xirr(flows, dates) is a function, but the golfed version only has an expression that looks at f.  The golfed version also removes the part call and adds the daylight-saving bug.