IRR and NPV in Mathematica

If you work in finance, you probably compute net present values (NPVs) and internal rates of return (IRRs) from time to time. As of version 7, Mathematica does not have built-in functions for these. There are add-on libraries that one might buy but it seems wrong to have to pay for something that is both so simple and so important. I have tried to convince Wolfram to add functions for computing these to the standard libraries, but thus far without success. So I will provide sample code here for anybody looking to do these things in Mathematica.

Generally when working with financial data series, I prefer to use data objects that have an identifying header rather than just raw data. In the long run, it makes life much simpler. In a later post I will explain this in more detail and give examples. For this post, I will not use that technique, and will show how to complete the calculations of NPV and IRR in Mathematica for a simple list of {date/datum} pairs.

First, since we are going to be using Mathematica’s date functions, and my sample dates are in “Month/Day/Year” format, we had better shut off some warnings:


Now a function that takes a list of dates and a fixed annual discount rate, and returns a discount factor for each date.

sternDiscountFactors[dateList_, r_] := Module[{absDates, firstDate},
absDates = Map[AbsoluteTime[#] &, dateList];
firstDate = Min[absDates];
Transpose[{dateList, Map[1/(1 + r)^DateDifference[firstDate, #, "Year"][[1]] &, absDates]}]]

For an example of how this works, run
In[]:= sternDiscountFactors[{"1/1/2001", "1/1/2002", "1/1/2005", "1/10/2005"}, .05]

Out[]= {{"1/1/2001", 1.}, {"1/1/2002", 0.952381}, {"1/1/2005", 0.822702}, {"1/10/2005", 0.821713}}

Then we need a function for computing the net present value of a cash flow, given a fixed annual discount rate. Basically, it takes the dot product of vectors representing the discount factor on each date and the net payment on that date.

sternNetPV[dateAndCashFlowList_, r_] :=
Module[{cashflows, discountfactors},
cashflows = Transpose[dateAndCashFlowList][[2]];
discountfactors =
Transpose[sternDiscountFactors[Transpose[dateAndCashFlowList][[1]], r]][[2]];

Here is some sample data that we will use to test the NPV function and, in a minute, the IRR function:

testFlow = {{"1/1/2001", -1}, {"1/1/2002", .3}, {"1/1/2005", .4}, {"1/10/2005", .5}};

You can then test the NPV function with
In[]:= sternNetPV[testFlow, .05]

Out[]= 0.0256519

Computing the internal rate of return is now simple:

sternIrr[dateAndCashFlowList_] :=
Module[{eqn, r}, eqn = sternNetPV[dateAndCashFlowList, r] == 0; FindRoot[eqn, {r, .1}]]

and this can be tested with
In[]:= sternIrr[testFlow]

Out[]={r$3479 -> 0.0584316}

Aquí tiene. In real world applications, one would not typically rely on a fixed annual discount rate, and the NPV function would in most important contexts use a yield curve instead.

Installing WordPress on, the 2010 edition provides a software installation kit that will do this automatically, but they charge $3/month for access, which seems silly for free software. You can install WordPress yourself in a few minutes. These guidelines follow those from eHow, but updated for the current state of things.

  1. Download the WordPress blog software. It will be delivered in a .zip file, which you will need to unzip.
  2. Inside the resulting folder, locate the wp-config-sample.php file and rename it to wp-config.php. Open this file in TextEdit (Mac), Notepad (PC), or another text editor.
  3. Log in to your Pair Networks account to create a new database for your WordPress installation.  Go to the Account Control Center, then to “Database Management,” “Create a New Database”.
  4. Assign a name to your new database. It is best to choose a name that will be easily identifiable if you plan to have multiple databases. Access level “local” and “monthly” optimization should be fine. Then click on the “Add Database” button. You will be brought to the New Database Details screen. Copy the server name, user name for full access, and the password.
  5. In the wp-config.php file that you have opened in your text editor, set the DB_NAME, DB_USER, DB_PASSWORD, and DB_HOST variables (the last of those is the server name over at pair, probably something like  All of these must be exact matches to your database setup at You should also take this opportunity to assign unique phrases to the various authentication unique keys and salts in the wp-config file.
  6. Connect to your web server via FTP and upload all of the WordPress files, including the wp-config.php to the desired location on your account. If you upload them to then people will later be able to reach your blog by going to that exact address.
  7. Start the WordPress installation PHP script by pointing your web browser to your domain/installation directory, followed by /wp-admin/install.php. Follow the on-screen prompts and the WordPress installation on your account will be complete. If it can’t log in, try going back to the database management screen, “Change A Password,” and give a new password to your main database user account. Enter this new password into your wp-config file, upload the fixed wp-config file back to the server, and try again.

Number of Radios vs. the Number of Notified Mental Defectives

I found this amusing dataset in high school while trying to use a horrid statistical package (version 1 of DataDesk, I think). To the naive eye, it looks like evidence that radios drive people mad, or did so back in the England of the 1920s and ’30s. The units are millions of radio licenses issued in the U.K. vs. number of “notified mental defectives” per 10,000 of estimated population. The correlation coefficient is 0.99 and the P-value is on the order of 10^-10. There are a number of lessons we can learn from this — correlation does not prove causation, how to do labels by each point in Mathematica using the Epilog command, and to remember to shut off your radio.

How do we make such a graph?

First, our data:
masterlist = {{1924, 1.35, 8}, {1925, 0.196, 8}, {1926, 2.27, 9}, {1927, 2.483, 10}, {1928, 2.73, 11}, {1929, 3.091, 11}, {1930, 3.647, 12}, {1931, 4.62, 16}, {1932, 5.497, 18}, {1933, 6.26, 19}, {1934,  7.012, 20}, {1935, 7.618, 21}, {1936, 8.131, 22}, {1937, 8.593, 23}};

You can make a quick table of this data with
TableHeadings -> {None, {"\nYear", "\nRadios", "Mental\nDefectives"}}]

For the purpose of graphing the relationship between radios and mental defectives, we’ll want to separate the data from the yearly labels. First, the data:

justData = Transpose[{Transpose[masterlist][[2]], Transpose[masterlist][[3]]}];

The labels are going to be included in the graph using the Epilog[] command. This can be done at the time we run the Plot[] command but I find it easier to run it first for clarity and ease of debugging.

dateEpilog =
Map[Text[#[[1]], #[[2]]] &,
Transpose[{Map[ToString[#] &, Range[1924, 1937]],
Transpose[Transpose[justData] + {0, 1}]}]];

Then we can do the graph, including the Epilog we just constructed to label the points:

dotplot = ListPlot[justData, Epilog -> dateEpilog];

We could call it complete here, though I prefer to show the regression line on the same axes as the points. We’ll determine that line with the Fit[] command, then graph it, and combine it with the dotplot using the Show[] command.

defectiveFit = Fit[justData, {1, x}, x];

Show[dotplot, Plot[defectiveFit, {x, 0, 9}, PlotStyle -> Orange],
AxesLabel -> {"Radios", "Mental Defectives"},
PlotLabel -> "Correlation does not mean causation\nin the U.K."]

This gives us the graph seen at the top of this post — data nicely labeled, with the regression line shown. Sometimes it’s best to leave the PlotMarkers blank and just use the labels (the years in this case) as markers, Edward Tufte style. The hard part is getting the Epilog right, as that puts the labels in the right places. I hope this example has been useful.

How strong is the relationship between the number of radios and the number of mental defectives? In old versions of Mathematica, this was answered by loading the LinearRegression package and using the Regress[] command. In modern versions, we do it like this:

linearmodel = LinearModelFit[justData, x, x];

You can get Pearson’s correlation coefficition with the Correlation[] command. It’s about 0.99. Credit where credit is due, this data seems to have been originally compiled, and offered as an illustration of spurious correlation in “An Introduction to the Theory of Statistics” by G. E. Yule and M. G. Kendall in the early 20th century.


“The combination of precise formulas with highly imprecise assumptions can be used to establish, or rather to justify, practically any value one wishes…Calculus…[gives] speculation the deceptive guise of investment.”

—Benjamin Graham, 1949