# [Numpy-svn] r4960 - in trunk/numpy/lib: . tests

numpy-svn@scip... numpy-svn@scip...
Fri Apr 4 01:11:27 CDT 2008

```Author: oliphant
Date: 2008-04-04 01:11:24 -0500 (Fri, 04 Apr 2008)
New Revision: 4960

trunk/numpy/lib/financial.py
trunk/numpy/lib/tests/test_financial.py
Modified:
trunk/numpy/lib/io.py
Log:
Add fromregex function (needs more testing) and some simple spreadsheet-like financial calculations.

===================================================================
--- trunk/numpy/lib/financial.py	2008-04-03 20:44:22 UTC (rev 4959)
+++ trunk/numpy/lib/financial.py	2008-04-04 06:11:24 UTC (rev 4960)
@@ -0,0 +1,151 @@
+# Some simple financial calculations
+from numpy import log, where
+import numpy as np
+
+__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate', 'irr', 'npv']
+
+_when_to_num = {'end':0, 'begin':1,
+                'e':0, 'b':1,
+                0:0, 1:1,
+                'beginning':1,
+                'start':1,
+                'finish':0}
+
+eqstr = """
+
+    Parameters
+    ----------
+    rate :
+        Rate of interest (per period)
+    nper :
+        Number of compounding periods
+    pmt :
+        Payment
+    pv :
+        Present value
+    fv :
+        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 fv(rate, nper, pmt, pv, when='end'):
+    """future value computed by solving the equation
+
+    %s
+    """ % eqstr
+    when = _when_to_num[when]
+    temp = (1+rate)**nper
+    fact = where(rate==0.0, nper, (1+rate*when)*(temp-1)/rate)
+    return -(pv*temp + pmt*fact)
+
+def pmt(rate, nper, pv, fv=0, when='end'):
+    """Payment computed by solving the equation
+
+    %s
+    """ % eqstr
+    when = _when_to_num[when]
+    temp = (1+rate)**nper
+    fact = where(rate==0.0, nper, (1+rate*when)*(temp-1)/rate)
+    return -(fv + pv*temp) / fact
+
+def nper(rate, pmt, pv, fv=0, when='end'):
+    """Number of periods found by solving the equation
+
+    %s
+    """ % eqstr
+    when = _when_to_num[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
+
+def ipmt(rate, per, nper, pv, fv=0.0, when='end'):
+    raise NotImplementedError
+
+
+def ppmt(rate, per, nper, pv, fv=0.0, when='end'):
+    raise NotImplementedError
+
+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]
+    temp = (1+rate)**nper
+    fact = where(rate == 0.0, nper, (1+rate*when)*(temp-1)/rate)
+    return -(fv + pmt*fact)/temp
+
+# 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)
+
+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)
+
+# Use Newton's iteration until the change is less than 1e-6
+#  for all values or a maximum of 100 iterations is reached.
+#  Newton's rule is
+#  r_{n+1} = r_{n} - g(r_n)/g'(r_n)
+#     where
+#  g(r) is the formula
+#  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]
+    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 nan's in array of the same shape as rn
+        return np.nan + rn
+    else:
+        return rn
+
+def irr(values):
+    """Internal Rate of Return
+
+    This is the rate of return that gives a net present value of 0.0
+
+    npv(irr(values), values) == 0.0
+    """
+    res = np.roots(values[::-1])
+    # Find the root(s) between 0 and 1
+    mask = (res.imag == 0) & (res.real > 0) & (res.real <= 1)
+    if res.size == 0:
+        return np.nan
+    rate = 1.0/res - 1
+    if rate.size == 1:
+        rate = rate.item()
+    return rate
+
+def npv(rate, values):
+    """Net Present Value
+
+    sum ( values_k / (1+rate)**k, k = 1..n)
+    """
+    values = np.asarray(values)
+    return (values / (1+rate)**np.arange(1,len(values)+1)).sum(axis=0)
+
+

Property changes on: trunk/numpy/lib/financial.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native

Modified: trunk/numpy/lib/io.py
===================================================================
--- trunk/numpy/lib/io.py	2008-04-03 20:44:22 UTC (rev 4959)
+++ trunk/numpy/lib/io.py	2008-04-04 06:11:24 UTC (rev 4960)
@@ -3,6 +3,7 @@
'save', 'savez',
'packbits', 'unpackbits',
+           'fromregex',
'DataSource']

import numpy as np
@@ -361,3 +362,24 @@

if origShape is not None:
X.shape = origShape
+
+import re
+def fromregex(file, regexp, **kwds):
+    """Construct a record array from a text file, using regular-expressions parsing.
+
+    Groups in the regular exespression are converted to fields.
+    """
+        file = open(file,'r')
+    if not hasattr(regexp, 'match'):
+        regexp = re.compile(regexp)
+
+    dtypelist = []
+    for key, value in kwds.values():
+        dtypelist.append((key, value))
+    format = np.dtype(dtypelist)
+    output = array(seq, dtype=format)
+    return output
+
+

===================================================================
--- trunk/numpy/lib/tests/test_financial.py	2008-04-03 20:44:22 UTC (rev 4959)
+++ trunk/numpy/lib/tests/test_financial.py	2008-04-04 06:11:24 UTC (rev 4960)
@@ -0,0 +1,34 @@
+"""
+from numpy.lib.financial import *
+
+>>> rate(10,0,-3500,10000)
+0.11069085371426901
+
+>>> irr([-150000, 15000, 25000, 35000, 45000, 60000])
+0.052432888859414106
+
+>>> pv(0.07,20,12000,0)
+-127128.17094619398
+
+>>> fv(0.075, 20, -2000,0,0)
+86609.362673042924
+
+>>> pmt(0.08/12,5*12,15000)
+-304.14591432620773
+
+>>> nper(0.075,-2000,0,100000.)
+21.544944197323336
+
+>>> npv(0.05,[-15000,1500,2500,3500,4500,6000])
+117.04271900089589
+
+"""
+
+from numpy.testing import *
+import numpy as np
+
+class TestDocs(NumpyTestCase):
+    def check_doctests(self): return self.rundocs()
+
+if __name__ == "__main__":
+    NumpyTest().run()

Property changes on: trunk/numpy/lib/tests/test_financial.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native

```