|
"""Some simple financial calculations |
|
|
|
patterned after spreadsheet computations. |
|
|
|
There is some complexity in each function |
|
so that the functions behave like ufuncs with |
|
broadcasting and being able to be called with scalars |
|
or arrays (or other sequences). |
|
|
|
""" |
|
from __future__ import division, absolute_import, print_function |
|
|
|
import numpy as np |
|
|
|
__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate', |
|
'irr', 'npv', 'mirr'] |
|
|
|
_when_to_num = {'end':0, 'begin':1, |
|
'e':0, 'b':1, |
|
0:0, 1:1, |
|
'beginning':1, |
|
'start':1, |
|
'finish':0} |
|
|
|
def _convert_when(when): |
|
|
|
|
|
if isinstance(when, np.ndarray): |
|
return when |
|
try: |
|
return _when_to_num[when] |
|
except (KeyError, TypeError): |
|
return [_when_to_num[x] for x in when] |
|
|
|
|
|
def fv(rate, nper, pmt, pv, when='end'): |
|
""" |
|
Compute the future value. |
|
|
|
Given: |
|
* a present value, `pv` |
|
* an interest `rate` compounded once per period, of which |
|
there are |
|
* `nper` total |
|
* a (fixed) payment, `pmt`, paid either |
|
* at the beginning (`when` = {'begin', 1}) or the end |
|
(`when` = {'end', 0}) of each period |
|
|
|
Return: |
|
the value at the end of the `nper` periods |
|
|
|
Parameters |
|
---------- |
|
rate : scalar or array_like of shape(M, ) |
|
Rate of interest as decimal (not per cent) per period |
|
nper : scalar or array_like of shape(M, ) |
|
Number of compounding periods |
|
pmt : scalar or array_like of shape(M, ) |
|
Payment |
|
pv : scalar or array_like of shape(M, ) |
|
Present value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional |
|
When payments are due ('begin' (1) or 'end' (0)). |
|
Defaults to {'end', 0}. |
|
|
|
Returns |
|
------- |
|
out : ndarray |
|
Future values. If all input is scalar, returns a scalar float. If |
|
any input is array_like, returns future values for each input element. |
|
If multiple inputs are array_like, they all must have the same shape. |
|
|
|
Notes |
|
----- |
|
The future value is computed by solving the equation:: |
|
|
|
fv + |
|
pv*(1+rate)**nper + |
|
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0 |
|
|
|
or, when ``rate == 0``:: |
|
|
|
fv + pv + pmt * nper == 0 |
|
|
|
References |
|
---------- |
|
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). |
|
Open Document Format for Office Applications (OpenDocument)v1.2, |
|
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version, |
|
Pre-Draft 12. Organization for the Advancement of Structured Information |
|
Standards (OASIS). Billerica, MA, USA. [ODT Document]. |
|
Available: |
|
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula |
|
OpenDocument-formula-20090508.odt |
|
|
|
Examples |
|
-------- |
|
What is the future value after 10 years of saving $100 now, with |
|
an additional monthly savings of $100. Assume the interest rate is |
|
5% (annually) compounded monthly? |
|
|
|
>>> np.fv(0.05/12, 10*12, -100, -100) |
|
15692.928894335748 |
|
|
|
By convention, the negative sign represents cash flow out (i.e. money not |
|
available today). Thus, saving $100 a month at 5% annual interest leads |
|
to $15,692.93 available to spend in 10 years. |
|
|
|
If any input is array_like, returns an array of equal shape. Let's |
|
compare different interest rates from the example above. |
|
|
|
>>> a = np.array((0.05, 0.06, 0.07))/12 |
|
>>> np.fv(a, 10*12, -100, -100) |
|
array([ 15692.92889434, 16569.87435405, 17509.44688102]) |
|
|
|
""" |
|
when = _convert_when(when) |
|
(rate, nper, pmt, pv, when) = map(np.asarray, [rate, nper, pmt, pv, when]) |
|
temp = (1+rate)**nper |
|
miter = np.broadcast(rate, nper, pmt, pv, when) |
|
zer = np.zeros(miter.shape) |
|
fact = np.where(rate == zer, nper + zer, |
|
(1 + rate*when)*(temp - 1)/rate + zer) |
|
return -(pv*temp + pmt*fact) |
|
|
|
def pmt(rate, nper, pv, fv=0, when='end'): |
|
""" |
|
Compute the payment against loan principal plus interest. |
|
|
|
Given: |
|
* a present value, `pv` (e.g., an amount borrowed) |
|
* a future value, `fv` (e.g., 0) |
|
* an interest `rate` compounded once per period, of which |
|
there are |
|
* `nper` total |
|
* and (optional) specification of whether payment is made |
|
at the beginning (`when` = {'begin', 1}) or the end |
|
(`when` = {'end', 0}) of each period |
|
|
|
Return: |
|
the (fixed) periodic payment. |
|
|
|
Parameters |
|
---------- |
|
rate : array_like |
|
Rate of interest (per period) |
|
nper : array_like |
|
Number of compounding periods |
|
pv : array_like |
|
Present value |
|
fv : array_like (optional) |
|
Future value (default = 0) |
|
when : {{'begin', 1}, {'end', 0}}, {string, int} |
|
When payments are due ('begin' (1) or 'end' (0)) |
|
|
|
Returns |
|
------- |
|
out : ndarray |
|
Payment against loan plus interest. If all input is scalar, returns a |
|
scalar float. If any input is array_like, returns payment for each |
|
input element. If multiple inputs are array_like, they all must have |
|
the same shape. |
|
|
|
Notes |
|
----- |
|
The payment is computed by solving the equation:: |
|
|
|
fv + |
|
pv*(1 + rate)**nper + |
|
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0 |
|
|
|
or, when ``rate == 0``:: |
|
|
|
fv + pv + pmt * nper == 0 |
|
|
|
for ``pmt``. |
|
|
|
Note that computing a monthly mortgage payment is only |
|
one use for this function. For example, pmt returns the |
|
periodic deposit one must make to achieve a specified |
|
future balance given an initial deposit, a fixed, |
|
periodically compounded interest rate, and the total |
|
number of periods. |
|
|
|
References |
|
---------- |
|
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). |
|
Open Document Format for Office Applications (OpenDocument)v1.2, |
|
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version, |
|
Pre-Draft 12. Organization for the Advancement of Structured Information |
|
Standards (OASIS). Billerica, MA, USA. [ODT Document]. |
|
Available: |
|
http://www.oasis-open.org/committees/documents.php |
|
?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt |
|
|
|
Examples |
|
-------- |
|
What is the monthly payment needed to pay off a $200,000 loan in 15 |
|
years at an annual interest rate of 7.5%? |
|
|
|
>>> np.pmt(0.075/12, 12*15, 200000) |
|
-1854.0247200054619 |
|
|
|
In order to pay-off (i.e., have a future-value of 0) the $200,000 obtained |
|
today, a monthly payment of $1,854.02 would be required. Note that this |
|
example illustrates usage of `fv` having a default value of 0. |
|
|
|
""" |
|
when = _convert_when(when) |
|
(rate, nper, pv, fv, when) = map(np.asarray, [rate, nper, pv, fv, when]) |
|
temp = (1+rate)**nper |
|
miter = np.broadcast(rate, nper, pv, fv, when) |
|
zer = np.zeros(miter.shape) |
|
fact = np.where(rate == zer, nper + zer, |
|
(1 + rate*when)*(temp - 1)/rate + zer) |
|
return -(fv + pv*temp) / fact |
|
|
|
def nper(rate, pmt, pv, fv=0, when='end'): |
|
""" |
|
Compute the number of periodic payments. |
|
|
|
Parameters |
|
---------- |
|
rate : array_like |
|
Rate of interest (per period) |
|
pmt : array_like |
|
Payment |
|
pv : array_like |
|
Present value |
|
fv : array_like, optional |
|
Future value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional |
|
When payments are due ('begin' (1) or 'end' (0)) |
|
|
|
Notes |
|
----- |
|
The number of periods ``nper`` is computed by solving the equation:: |
|
|
|
fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate*((1+rate)**nper-1) = 0 |
|
|
|
but if ``rate = 0`` then:: |
|
|
|
fv + pv + pmt*nper = 0 |
|
|
|
Examples |
|
-------- |
|
If you only had $150/month to pay towards the loan, how long would it take |
|
to pay-off a loan of $8,000 at 7% annual interest? |
|
|
|
>>> print round(np.nper(0.07/12, -150, 8000), 5) |
|
64.07335 |
|
|
|
So, over 64 months would be required to pay off the loan. |
|
|
|
The same analysis could be done with several different interest rates |
|
and/or payments and/or total amounts to produce an entire table. |
|
|
|
>>> np.nper(*(np.ogrid[0.07/12: 0.08/12: 0.01/12, |
|
... -150 : -99 : 50 , |
|
... 8000 : 9001 : 1000])) |
|
array([[[ 64.07334877, 74.06368256], |
|
[ 108.07548412, 127.99022654]], |
|
[[ 66.12443902, 76.87897353], |
|
[ 114.70165583, 137.90124779]]]) |
|
|
|
""" |
|
when = _convert_when(when) |
|
(rate, pmt, pv, fv, when) = map(np.asarray, [rate, pmt, pv, fv, when]) |
|
|
|
use_zero_rate = False |
|
with np.errstate(divide="raise"): |
|
try: |
|
z = pmt*(1.0+rate*when)/rate |
|
except FloatingPointError: |
|
use_zero_rate = True |
|
|
|
if use_zero_rate: |
|
return (-fv + pv) / (pmt + 0.0) |
|
else: |
|
A = -(fv + pv)/(pmt+0.0) |
|
B = np.log((-fv+z) / (pv+z))/np.log(1.0+rate) |
|
miter = np.broadcast(rate, pmt, pv, fv, when) |
|
zer = np.zeros(miter.shape) |
|
return np.where(rate == zer, A + zer, B + zer) + 0.0 |
|
|
|
def ipmt(rate, per, nper, pv, fv=0.0, when='end'): |
|
""" |
|
Compute the interest portion of a payment. |
|
|
|
Parameters |
|
---------- |
|
rate : scalar or array_like of shape(M, ) |
|
Rate of interest as decimal (not per cent) per period |
|
per : scalar or array_like of shape(M, ) |
|
Interest paid against the loan changes during the life or the loan. |
|
The `per` is the payment period to calculate the interest amount. |
|
nper : scalar or array_like of shape(M, ) |
|
Number of compounding periods |
|
pv : scalar or array_like of shape(M, ) |
|
Present value |
|
fv : scalar or array_like of shape(M, ), optional |
|
Future value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional |
|
When payments are due ('begin' (1) or 'end' (0)). |
|
Defaults to {'end', 0}. |
|
|
|
Returns |
|
------- |
|
out : ndarray |
|
Interest portion of payment. If all input is scalar, returns a scalar |
|
float. If any input is array_like, returns interest payment for each |
|
input element. If multiple inputs are array_like, they all must have |
|
the same shape. |
|
|
|
See Also |
|
-------- |
|
ppmt, pmt, pv |
|
|
|
Notes |
|
----- |
|
The total payment is made up of payment against principal plus interest. |
|
|
|
``pmt = ppmt + ipmt`` |
|
|
|
Examples |
|
-------- |
|
What is the amortization schedule for a 1 year loan of $2500 at |
|
8.24% interest per year compounded monthly? |
|
|
|
>>> principal = 2500.00 |
|
|
|
The 'per' variable represents the periods of the loan. Remember that |
|
financial equations start the period count at 1! |
|
|
|
>>> per = np.arange(1*12) + 1 |
|
>>> ipmt = np.ipmt(0.0824/12, per, 1*12, principal) |
|
>>> ppmt = np.ppmt(0.0824/12, per, 1*12, principal) |
|
|
|
Each element of the sum of the 'ipmt' and 'ppmt' arrays should equal |
|
'pmt'. |
|
|
|
>>> pmt = np.pmt(0.0824/12, 1*12, principal) |
|
>>> np.allclose(ipmt + ppmt, pmt) |
|
True |
|
|
|
>>> fmt = '{0:2d} {1:8.2f} {2:8.2f} {3:8.2f}' |
|
>>> for payment in per: |
|
... index = payment - 1 |
|
... principal = principal + ppmt[index] |
|
... print fmt.format(payment, ppmt[index], ipmt[index], principal) |
|
1 -200.58 -17.17 2299.42 |
|
2 -201.96 -15.79 2097.46 |
|
3 -203.35 -14.40 1894.11 |
|
4 -204.74 -13.01 1689.37 |
|
5 -206.15 -11.60 1483.22 |
|
6 -207.56 -10.18 1275.66 |
|
7 -208.99 -8.76 1066.67 |
|
8 -210.42 -7.32 856.25 |
|
9 -211.87 -5.88 644.38 |
|
10 -213.32 -4.42 431.05 |
|
11 -214.79 -2.96 216.26 |
|
12 -216.26 -1.49 -0.00 |
|
|
|
>>> interestpd = np.sum(ipmt) |
|
>>> np.round(interestpd, 2) |
|
-112.98 |
|
|
|
""" |
|
when = _convert_when(when) |
|
rate, per, nper, pv, fv, when = np.broadcast_arrays(rate, per, nper, |
|
pv, fv, when) |
|
total_pmt = pmt(rate, nper, pv, fv, when) |
|
ipmt = _rbl(rate, per, total_pmt, pv, when)*rate |
|
try: |
|
ipmt = np.where(when == 1, ipmt/(1 + rate), ipmt) |
|
ipmt = np.where(np.logical_and(when == 1, per == 1), 0.0, ipmt) |
|
except IndexError: |
|
pass |
|
return ipmt |
|
|
|
def _rbl(rate, per, pmt, pv, when): |
|
""" |
|
This function is here to simply have a different name for the 'fv' |
|
function to not interfere with the 'fv' keyword argument within the 'ipmt' |
|
function. It is the 'remaining balance on loan' which might be useful as |
|
it's own function, but is easily calculated with the 'fv' function. |
|
""" |
|
return fv(rate, (per - 1), pmt, pv, when) |
|
|
|
def ppmt(rate, per, nper, pv, fv=0.0, when='end'): |
|
""" |
|
Compute the payment against loan principal. |
|
|
|
Parameters |
|
---------- |
|
rate : array_like |
|
Rate of interest (per period) |
|
per : array_like, int |
|
Amount paid against the loan changes. The `per` is the period of |
|
interest. |
|
nper : array_like |
|
Number of compounding periods |
|
pv : array_like |
|
Present value |
|
fv : array_like, optional |
|
Future value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int} |
|
When payments are due ('begin' (1) or 'end' (0)) |
|
|
|
See Also |
|
-------- |
|
pmt, pv, ipmt |
|
|
|
""" |
|
total = pmt(rate, nper, pv, fv, when) |
|
return total - ipmt(rate, per, nper, pv, fv, when) |
|
|
|
def pv(rate, nper, pmt, fv=0.0, when='end'): |
|
""" |
|
Compute the present value. |
|
|
|
Given: |
|
* a future value, `fv` |
|
* an interest `rate` compounded once per period, of which |
|
there are |
|
* `nper` total |
|
* a (fixed) payment, `pmt`, paid either |
|
* at the beginning (`when` = {'begin', 1}) or the end |
|
(`when` = {'end', 0}) of each period |
|
|
|
Return: |
|
the value now |
|
|
|
Parameters |
|
---------- |
|
rate : array_like |
|
Rate of interest (per period) |
|
nper : array_like |
|
Number of compounding periods |
|
pmt : array_like |
|
Payment |
|
fv : array_like, optional |
|
Future value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional |
|
When payments are due ('begin' (1) or 'end' (0)) |
|
|
|
Returns |
|
------- |
|
out : ndarray, float |
|
Present value of a series of payments or investments. |
|
|
|
Notes |
|
----- |
|
The present value is computed by solving the equation:: |
|
|
|
fv + |
|
pv*(1 + rate)**nper + |
|
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0 |
|
|
|
or, when ``rate = 0``:: |
|
|
|
fv + pv + pmt * nper = 0 |
|
|
|
for `pv`, which is then returned. |
|
|
|
References |
|
---------- |
|
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). |
|
Open Document Format for Office Applications (OpenDocument)v1.2, |
|
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version, |
|
Pre-Draft 12. Organization for the Advancement of Structured Information |
|
Standards (OASIS). Billerica, MA, USA. [ODT Document]. |
|
Available: |
|
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula |
|
OpenDocument-formula-20090508.odt |
|
|
|
Examples |
|
-------- |
|
What is the present value (e.g., the initial investment) |
|
of an investment that needs to total $15692.93 |
|
after 10 years of saving $100 every month? Assume the |
|
interest rate is 5% (annually) compounded monthly. |
|
|
|
>>> np.pv(0.05/12, 10*12, -100, 15692.93) |
|
-100.00067131625819 |
|
|
|
By convention, the negative sign represents cash flow out |
|
(i.e., money not available today). Thus, to end up with |
|
$15,692.93 in 10 years saving $100 a month at 5% annual |
|
interest, one's initial deposit should also be $100. |
|
|
|
If any input is array_like, ``pv`` returns an array of equal shape. |
|
Let's compare different interest rates in the example above: |
|
|
|
>>> a = np.array((0.05, 0.04, 0.03))/12 |
|
>>> np.pv(a, 10*12, -100, 15692.93) |
|
array([ -100.00067132, -649.26771385, -1273.78633713]) |
|
|
|
So, to end up with the same $15692.93 under the same $100 per month |
|
"savings plan," for annual interest rates of 4% and 3%, one would |
|
need initial investments of $649.27 and $1273.79, respectively. |
|
|
|
""" |
|
when = _convert_when(when) |
|
(rate, nper, pmt, fv, when) = map(np.asarray, [rate, nper, pmt, fv, when]) |
|
temp = (1+rate)**nper |
|
miter = np.broadcast(rate, nper, pmt, fv, when) |
|
zer = np.zeros(miter.shape) |
|
fact = np.where(rate == zer, nper+zer, (1+rate*when)*(temp-1)/rate+zer) |
|
return -(fv + pmt*fact)/temp |
|
|
|
|
|
|
|
|
|
|
|
|
|
def _g_div_gp(r, n, p, x, y, w): |
|
t1 = (r+1)**n |
|
t2 = (r+1)**(n-1) |
|
return ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) / |
|
(n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r + |
|
p*(t1 - 1)*w/r)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rate(nper, pmt, pv, fv, when='end', guess=0.10, tol=1e-6, maxiter=100): |
|
""" |
|
Compute the rate of interest per period. |
|
|
|
Parameters |
|
---------- |
|
nper : array_like |
|
Number of compounding periods |
|
pmt : array_like |
|
Payment |
|
pv : array_like |
|
Present value |
|
fv : array_like |
|
Future value |
|
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional |
|
When payments are due ('begin' (1) or 'end' (0)) |
|
guess : float, optional |
|
Starting guess for solving the rate of interest |
|
tol : float, optional |
|
Required tolerance for the solution |
|
maxiter : int, optional |
|
Maximum iterations in finding the solution |
|
|
|
Notes |
|
----- |
|
The rate of interest is computed by iteratively solving the |
|
(non-linear) equation:: |
|
|
|
fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate * ((1+rate)**nper - 1) = 0 |
|
|
|
for ``rate``. |
|
|
|
References |
|
---------- |
|
Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). Open Document |
|
Format for Office Applications (OpenDocument)v1.2, Part 2: Recalculated |
|
Formula (OpenFormula) Format - Annotated Version, Pre-Draft 12. |
|
Organization for the Advancement of Structured Information Standards |
|
(OASIS). Billerica, MA, USA. [ODT Document]. Available: |
|
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula |
|
OpenDocument-formula-20090508.odt |
|
|
|
""" |
|
when = _convert_when(when) |
|
(nper, pmt, pv, fv, when) = map(np.asarray, [nper, pmt, pv, fv, when]) |
|
rn = guess |
|
iter = 0 |
|
close = False |
|
while (iter < maxiter) and not close: |
|
rnp1 = rn - _g_div_gp(rn, nper, pmt, pv, fv, when) |
|
diff = abs(rnp1-rn) |
|
close = np.all(diff < tol) |
|
iter += 1 |
|
rn = rnp1 |
|
if not close: |
|
|
|
return np.nan + rn |
|
else: |
|
return rn |
|
|
|
def irr(values): |
|
""" |
|
Return the Internal Rate of Return (IRR). |
|
|
|
This is the "average" periodically compounded rate of return |
|
that gives a net present value of 0.0; for a more complete explanation, |
|
see Notes below. |
|
|
|
Parameters |
|
---------- |
|
values : array_like, shape(N,) |
|
Input cash flows per time period. By convention, net "deposits" |
|
are negative and net "withdrawals" are positive. Thus, for |
|
example, at least the first element of `values`, which represents |
|
the initial investment, will typically be negative. |
|
|
|
Returns |
|
------- |
|
out : float |
|
Internal Rate of Return for periodic input values. |
|
|
|
Notes |
|
----- |
|
The IRR is perhaps best understood through an example (illustrated |
|
using np.irr in the Examples section below). Suppose one invests 100 |
|
units and then makes the following withdrawals at regular (fixed) |
|
intervals: 39, 59, 55, 20. Assuming the ending value is 0, one's 100 |
|
unit investment yields 173 units; however, due to the combination of |
|
compounding and the periodic withdrawals, the "average" rate of return |
|
is neither simply 0.73/4 nor (1.73)^0.25-1. Rather, it is the solution |
|
(for :math:`r`) of the equation: |
|
|
|
.. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2} |
|
+ \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0 |
|
|
|
In general, for `values` :math:`= [v_0, v_1, ... v_M]`, |
|
irr is the solution of the equation: [G]_ |
|
|
|
.. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0 |
|
|
|
References |
|
---------- |
|
.. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed., |
|
Addison-Wesley, 2003, pg. 348. |
|
|
|
Examples |
|
-------- |
|
>>> round(irr([-100, 39, 59, 55, 20]), 5) |
|
0.28095 |
|
>>> round(irr([-100, 0, 0, 74]), 5) |
|
-0.0955 |
|
>>> round(irr([-100, 100, 0, -7]), 5) |
|
-0.0833 |
|
>>> round(irr([-100, 100, 0, 7]), 5) |
|
0.06206 |
|
>>> round(irr([-5, 10.5, 1, -8, 1]), 5) |
|
0.0886 |
|
|
|
(Compare with the Example given for numpy.lib.financial.npv) |
|
|
|
""" |
|
res = np.roots(values[::-1]) |
|
mask = (res.imag == 0) & (res.real > 0) |
|
if res.size == 0: |
|
return np.nan |
|
res = res[mask].real |
|
|
|
|
|
rate = 1.0/res - 1 |
|
rate = rate.item(np.argmin(np.abs(rate))) |
|
return rate |
|
|
|
def npv(rate, values): |
|
""" |
|
Returns the NPV (Net Present Value) of a cash flow series. |
|
|
|
Parameters |
|
---------- |
|
rate : scalar |
|
The discount rate. |
|
values : array_like, shape(M, ) |
|
The values of the time series of cash flows. The (fixed) time |
|
interval between cash flow "events" must be the same as that for |
|
which `rate` is given (i.e., if `rate` is per year, then precisely |
|
a year is understood to elapse between each cash flow event). By |
|
convention, investments or "deposits" are negative, income or |
|
"withdrawals" are positive; `values` must begin with the initial |
|
investment, thus `values[0]` will typically be negative. |
|
|
|
Returns |
|
------- |
|
out : float |
|
The NPV of the input cash flow series `values` at the discount |
|
`rate`. |
|
|
|
Notes |
|
----- |
|
Returns the result of: [G]_ |
|
|
|
.. math :: \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}} |
|
|
|
References |
|
---------- |
|
.. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed., |
|
Addison-Wesley, 2003, pg. 346. |
|
|
|
Examples |
|
-------- |
|
>>> np.npv(0.281,[-100, 39, 59, 55, 20]) |
|
-0.0084785916384548798 |
|
|
|
(Compare with the Example given for numpy.lib.financial.irr) |
|
|
|
""" |
|
values = np.asarray(values) |
|
return (values / (1+rate)**np.arange(0, len(values))).sum(axis=0) |
|
|
|
def mirr(values, finance_rate, reinvest_rate): |
|
""" |
|
Modified internal rate of return. |
|
|
|
Parameters |
|
---------- |
|
values : array_like |
|
Cash flows (must contain at least one positive and one negative |
|
value) or nan is returned. The first value is considered a sunk |
|
cost at time zero. |
|
finance_rate : scalar |
|
Interest rate paid on the cash flows |
|
reinvest_rate : scalar |
|
Interest rate received on the cash flows upon reinvestment |
|
|
|
Returns |
|
------- |
|
out : float |
|
Modified internal rate of return |
|
|
|
""" |
|
values = np.asarray(values, dtype=np.double) |
|
n = values.size |
|
pos = values > 0 |
|
neg = values < 0 |
|
if not (pos.any() and neg.any()): |
|
return np.nan |
|
numer = np.abs(npv(reinvest_rate, values*pos)) |
|
denom = np.abs(npv(finance_rate, values*neg)) |
|
return (numer/denom)**(1.0/(n - 1))*(1 + reinvest_rate) - 1 |
|
|