diff options
Diffstat (limited to 'numpy/lib/financial.py')
-rw-r--r-- | numpy/lib/financial.py | 128 |
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 |