Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPV function return wrong value #10877

Closed
S-Azimi opened this issue Apr 10, 2018 · 12 comments · Fixed by #14508
Closed

NPV function return wrong value #10877

S-Azimi opened this issue Apr 10, 2018 · 12 comments · Fixed by #14508

Comments

@S-Azimi
Copy link

S-Azimi commented Apr 10, 2018

numpy.npv returns wrong value.

@tylerjereddy
Copy link
Contributor

What is wrong with the returned value? I re-implemented the function described in the docstring in pure Python and I get the exact same result as NumPy.

Perhaps this is a reference to the previously-fixed issue where the summation indexing was off by 1, if you are using an older version of NumPy?

@S-Azimi
Copy link
Author

S-Azimi commented Apr 19, 2018 via email

@mattip
Copy link
Member

mattip commented Apr 19, 2018

@S-Azimi please submit a code sample that demonstrates the problem, here is a framework

from __future__ import print_function
import sys
import numpy as np
print(np.__version__)
print(sys.version)
a = np.array(....<fill in what you need here>...)
rate = <your rate>
print(np.npv(rate,a))

then tell us what you expected vs. what you got

@S-Azimi
Copy link
Author

S-Azimi commented Apr 19, 2018 via email

@joelowj
Copy link

joelowj commented May 8, 2019

@tylerjereddy, what was the reason for npv to change from (values / (1+rate)**np.arange(1, len(values) + 1)).sum(axis=0) to (values / (1+rate)**np.arange(0, len(values))).sum(axis=0)? In finance, most of the time, when we are calculating npv, the first cashflow is always in the period t =1 instead of assuming it being in the current period.

@tylerjereddy
Copy link
Contributor

@joelowj I believe the reason was for compliance with the literature cited in the docstring. Are you suggesting that the equation cited from "Principles of Managerial Finance" is not correct?

It looks like the code was modified to start the summation at t=0 for compliance with the equation in the docstring.

I'm definitely not an expert nor the author of the code change though.

@joelowj
Copy link

joelowj commented May 8, 2019

@tylerjereddy, thanks for the response. I am not suggesting that the current implementation is wrong but more curious on the rationale behind the switch. From a practitioner standpoint, excel and some of the npv calculations are using the initial implementation (values / (1+rate)**np.arange(1, len(values) + 1)).sum(axis=0). And of course, this would definitely not match what is given in the docstring as the correct solution.

If we are solely interested in yielding the solution in the docstring, the previous implementation did not subtract the initial cash outlay, a coarse implementation such as (values[1:] / (1+rate)**np.arange(1, len(values[1:]) + 1)).sum(axis=0) - values[0] will yield the solution in the docstring.

@seberg
Copy link
Member

seberg commented May 8, 2019

@joelowj you would have to read these: #649 and #3346 probably. There is a reason most core devs do not like financial much and would prefer it outside of numpy…. Most of us do not use them, so it is hard to make clear decisions of what is right or wrong. It would really be better to have a package providing these outside of numpy (and with newer python versions, we could give an indefinite DeprecationWarning suggesting to use such a package instead). But I would not be surprised if there are simply two definitions in use here?

@Kai-Striega
Copy link
Member

Kai-Striega commented Jul 16, 2019

I did my BSc in Financial Maths so I'll try to clarify the finance part a little. Note that I'm not a practitioner nor am I involved with the original changes.

Are you suggesting that the equation cited from "Principles of Managerial Finance" is not correct? - @tylerjereddy

Starting with t=0 is the technically correct definition.

Starting with t=1 calculates the NPV of future cashflows. However, there is no guarantee that all cashflows must occur in the future. E.g. when taking out a loan the first cashflow will occur in t0 with repayments made from t1 onwards.

When written using summation notation the definition is almost always wrong. For example both Wikipedia and Investopedia write their definition with t=1. Then do their examples starting with t=0.

The problem comes that Excel (the defacto tool for finance) calculates the values of future cashflows only. This is wrong. I see this as a bug, but, "it's a feature, not a bug", right? Anyway, every business school teaches NPV uses Excel so now we're stuck with it.

NPV Background
The NPV calculates today's value of a series of cash flows accounting for the time value of money. The time value of money states the value of a fixed amount of money is worth more now than it is in the future, due to it's earning potential. I.e. if you have $1000 now you could invest it, and receive some additional return, which you cannot (simply) do this with money earnt in the future.

Difference in usage
An investment usually involves an initial purchase of the investment (a negative cash flow) followed by a series of (hopefully) positive cashflows at the end of each period. Taking example 2 from Excel's NPV documentation gives a cashflow of {-40,000, 8000, 9200, 10000, 12000, 14500}.

This makes sense in some contexts, e.g. if you want to start a small business you would estimate the costs payable right now and how much you expect to earn each year. Practitioners often have a slightly different usage, e.g. someone offers you an investment paying {8000, 9200, 10000, 12000, 14500} at the end of each year, how much should I pay right now (in t0) for it such that I'm not being ripped off?

NPV and IRR congruence
This explains ghosts comment in #639.

The internal rate of return is the discount rate required such that the net present value is 0. Mathematically the leads to the identity NPV(IRR(cashflows), cashflows) = 0. NumPy's NPV and IRR functions currently maintain this identity, while (at the time) Excel did not [1]. Using the data from example 2 from Excel's NPV docs:

>>> import numpy as np; np.__version__
>>> cashflows = np.array([0, -10000, 8000, 9200, 10000, 12000, 14500])
>>> np.npv(np.irr(cashflows), cashflows)
4.37694325228e-12

@seberg
Copy link
Member

seberg commented Jul 16, 2019

@Kai-Striega anything you specirfically would suggest here? IIRC we already changed it once, I would rather put a big warning in the docs than changing it again if both definitions are used quite a bit (or excel is the only reason for the other one)?

IT would also be nice if we could finally add a pointer: Please use package xy instead of the numpy financial functions.

@Kai-Striega
Copy link
Member

Kai-Striega commented Jul 17, 2019

anything you specirfically would suggest here?

I suggest keeping it as is. Starting from t=0 is the definition and maintains the IRR identity.

Doing a survey of common programs it looks like spreadsheeting software (Excel, LibreOffice Calc, Google Sheets) follow Excels definition while most dedicated libraries (QuantLib, MatLab, R's FinancialMath) follow the technical definition.

I would rather put a big warning in the docs than changing it again

As NPV deals with $$$ and changing it could seriously affect a user's models. I think to keep it as is with some clarification is the best way forward.

if both definitions are used quite a bit (or excel is the only reason for the other one)?

I think the alternative definition occurs because of Excel with Excel being the de-facto standard in (non-quant) finance and them getting it wrong.

IT would also be nice if we could finally add a pointer: Please use package xy instead of the numpy financial functions.

This doesn't really exist in Python. The best alternative I can think of would be QuantLib, but that's overkill for such simple functions.

@joelowj
Copy link

joelowj commented Jul 17, 2019

@Kai-Striega thanks for the comprehensive explanation on this matter. Based on my observation, there are more people picking up python to do some finance-related calculation than before. This way of calculating might not be intuitive to some of them since most of them would be more familiar with Excel. I agree with @Kai-Striega & @seberg that we should stick to the current method used in numpy and provide a warning in the docs to indicate that this approach would be different from some of the commercial software.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants