diff options
author | tim cera <tcera@sjrwmd.com> | 2012-01-28 21:09:03 -0500 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2012-02-12 11:46:20 -0700 |
commit | 015cada57ddd00d866e2a8ef396f83582c192884 (patch) | |
tree | 9650a416ef39ac0c4814dfb6bd497b1a9ea12491 | |
parent | ca258fc430fbcba6a3824dd3834f8e14259a62c8 (diff) | |
download | numpy-015cada57ddd00d866e2a8ef396f83582c192884.tar.gz |
Added ipmt (interest portion of payment) and ppmt (principal portion of payment) functions. Added doctests and unit tests.
-rw-r--r-- | numpy/lib/financial.py | 72 | ||||
-rw-r--r-- | numpy/lib/tests/test_financial.py | 15 |
2 files changed, 73 insertions, 14 deletions
diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py index 861892b63..d686aeca2 100644 --- a/numpy/lib/financial.py +++ b/numpy/lib/financial.py @@ -277,7 +277,7 @@ def nper(rate, pmt, pv, fv=0, when='end'): def ipmt(rate, per, nper, pv, fv=0.0, when='end'): """ - Not implemented. Compute the payment portion for loan interest. + Compute the interest portion of a payment. Parameters ---------- @@ -314,14 +314,71 @@ def ipmt(rate, per, nper, pv, fv=0.0, when='end'): ``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) + >>> interestpd + -112.98308424136215 + """ - total = pmt(rate, nper, pv, fv, when) - # Now, compute the nth step in the amortization - raise NotImplementedError + when = _convert_when(when) + if when == 1 and per == 1: + return 0.0 + total_pmt = pmt(rate, nper, pv, fv, when) + ipmt = _rbl(rate, per, total_pmt, pv, when)*rate + if when == 1: + return ipmt/(1 + rate) + 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'): """ - Not implemented. Compute the payment against loan principal. + Compute the payment against loan principal. Parameters ---------- @@ -655,3 +712,8 @@ def mirr(values, finance_rate, reinvest_rate): numer = np.abs(npv(reinvest_rate, values*pos))*(1 + reinvest_rate) denom = np.abs(npv(finance_rate, values*neg))*(1 + finance_rate) return (numer/denom)**(1.0/(n - 1))*(1 + reinvest_rate) - 1 + +if __name__ == '__main__': + import doctest + import numpy as np + doctest.testmod(verbose=True) diff --git a/numpy/lib/tests/test_financial.py b/numpy/lib/tests/test_financial.py index f3143049f..ba6846bf0 100644 --- a/numpy/lib/tests/test_financial.py +++ b/numpy/lib/tests/test_financial.py @@ -23,6 +23,12 @@ class TestFinancial(TestCase): assert_almost_equal(np.pmt(0.08/12,5*12,15000), -304.146, 3) + def test_ppmt(self): + np.round(np.ppmt(0.1/12,1,60,55000),2) == 710.25 + + def test_ipmt(self): + np.round(np.ipmt(0.1/12,1,24,2000),2) == 16.67 + def test_nper(self): assert_almost_equal(np.nper(0.075,-2000,0,100000.), 21.54, 2) @@ -49,14 +55,5 @@ class TestFinancial(TestCase): assert_(np.isnan(np.mirr(val, 0.10, 0.12))) - -def test_unimplemented(): - # np.round(np.ppmt(0.1/12,1,60,55000),2) == 710.25 - assert_raises(NotImplementedError, np.ppmt, 0.1/12, 1, 60, 55000) - - # np.round(np.ipmt(0.1/12,1,24,2000),2) == 16.67 - assert_raises(NotImplementedError, np.ipmt, 0.1/12, 1, 24, 2000) - - if __name__ == "__main__": run_module_suite() |