summaryrefslogtreecommitdiff
path: root/numpy/lib/financial.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/lib/financial.py')
-rw-r--r--numpy/lib/financial.py128
1 files changed, 94 insertions, 34 deletions
diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py
index 0ff46b280..bac276bb7 100644
--- a/numpy/lib/financial.py
+++ b/numpy/lib/financial.py
@@ -1,10 +1,9 @@
# Some simple financial calculations
# patterned after spreadsheet computations.
-from numpy import log, where
import numpy as np
-__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate', 'irr', 'npv',
- 'mirr']
+__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate',
+ 'irr', 'npv', 'mirr']
_when_to_num = {'end':0, 'begin':1,
'e':0, 'b':1,
@@ -15,6 +14,14 @@ _when_to_num = {'end':0, 'begin':1,
eqstr = """
+ nper / (1 + rate*when) \ / nper \
+ fv + pv*(1+rate) + pmt*|-------------------|*| (1+rate) - 1 | = 0
+ \ rate / \ /
+
+ fv + pv + pmt * nper = 0 (when rate == 0)
+
+where (all can be scalars or sequences)
+
Parameters
----------
rate :
@@ -26,50 +33,101 @@ eqstr = """
pv :
Present value
fv :
- Future value
+ Future value
when :
When payments are due ('begin' (1) or 'end' (0))
- nper / (1 + rate*when) \ / nper \
- fv + pv*(1+rate) + pmt*|-------------------|*| (1+rate) - 1 | = 0
- \ rate / \ /
-
- fv + pv + pmt * nper = 0 (when rate == 0)
"""
+def _convert_when(when):
+ try:
+ return _when_to_num[when]
+ except KeyError:
+ return [_when_to_num[x] for x in when]
+
+
def fv(rate, nper, pmt, pv, when='end'):
"""future value computed by solving the equation
-
- %s
- """ % eqstr
- when = _when_to_num[when]
+ """
+ when = _convert_when(when)
+ rate, nper, pmt, pv, when = map(np.asarray, [rate, nper, pmt, pv, when])
temp = (1+rate)**nper
- fact = where(rate==0.0, nper, (1+rate*when)*(temp-1)/rate)
+ 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)
+fv.__doc__ += eqstr + """
+Example
+--------
+
+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?
+
+>>> 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.
+"""
def pmt(rate, nper, pv, fv=0, when='end'):
"""Payment computed by solving the equation
-
- %s
- """ % eqstr
- when = _when_to_num[when]
+ """
+ when = _convert_when(when)
+ rate, nper, pv, fv, when = map(np.asarray, [rate, nper, pv, fv, when])
temp = (1+rate)**nper
- fact = where(rate==0.0, nper, (1+rate*when)*(temp-1)/rate)
+ 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
+pmt.__doc__ += eqstr + """
+Example
+-------
+
+What would the monthly payment need to be to pay off a $200,000 loan in 15
+ years at an annual interest rate of 7.5%?
+
+>>> 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.
+"""
def nper(rate, pmt, pv, fv=0, when='end'):
"""Number of periods found by solving the equation
-
- %s
- """ % eqstr
- when = _when_to_num[when]
+ """
+ when = _convert_when(when)
+ rate, pmt, pv, fv, when = map(np.asarray, [rate, pmt, pv, fv, when])
try:
z = pmt*(1.0+rate*when)/rate
except ZeroDivisionError:
z = 0.0
A = -(fv + pv)/(pmt+0.0)
- B = (log(fv-z) - log(pv-z))/log(1.0+rate)
- return where(rate==0.0, A, B) + 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
+nper.__doc__ += eqstr + """
+Example
+-------
+
+If you only had $150 to spend as payment, how long would it take to pay-off
+ a loan of $8,000 at 7% annual interest?
+
+>>> nper(0.07/12, -150, 8000)
+64.073348770661852
+
+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.
+
+>>> nper(*(ogrid[0.06/12:0.071/12:0.005/12, -100:-201:50, 6000:8000:1000]))
+
+"""
def ipmt(rate, per, nper, pv, fv=0.0, when='end'):
raise NotImplementedError
@@ -80,13 +138,15 @@ def ppmt(rate, per, nper, pv, fv=0.0, when='end'):
def pv(rate, nper, pmt, fv=0.0, when='end'):
"""Number of periods found by solving the equation
-
- %s
- """ % eqstr
- when = _when_to_num[when]
+ """
+ when = _convert_when(when)
+ rate, nper, pmt, fv, when = map(np.asarray, [rate, nper, pmt, fv, when])
temp = (1+rate)**nper
- fact = where(rate == 0.0, nper, (1+rate*when)*(temp-1)/rate)
+ 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
+pv.__doc__ += eqstr
# Computed with Sage
# (y + (r + 1)^n*x + p*((r + 1)^n - 1)*(r*w + 1)/r)/(n*(r + 1)^(n - 1)*x - p*((r + 1)^n - 1)*(r*w + 1)/r^2 + n*p*(r + 1)^(n - 1)*(r*w + 1)/r + p*((r + 1)^n - 1)*w/r)
@@ -105,10 +165,9 @@ def _g_div_gp(r, n, p, x, y, w):
# g'(r) is the derivative with respect to r.
def rate(nper, pmt, pv, fv, when='end', guess=0.10, tol=1e-6, maxiter=100):
"""Number of periods found by solving the equation
-
- %s
- """ % eqstr
- when = _when_to_num[when]
+ """
+ when = _convert_when(when)
+ nper, pmt, pv, fv, when = map(np.asarray, [nper, pmt, pv, fv, when])
rn = guess
iter = 0
close = False
@@ -123,6 +182,7 @@ def rate(nper, pmt, pv, fv, when='end', guess=0.10, tol=1e-6, maxiter=100):
return np.nan + rn
else:
return rn
+rate.__doc__ += eqstr
def irr(values):
"""Internal Rate of Return