Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/numpy/lib/financial.py : 26%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Some simple financial calculations
3patterned after spreadsheet computations.
5There is some complexity in each function
6so that the functions behave like ufuncs with
7broadcasting and being able to be called with scalars
8or arrays (or other sequences).
10Functions support the :class:`decimal.Decimal` type unless
11otherwise stated.
12"""
13import warnings
14from decimal import Decimal
15import functools
17import numpy as np
18from numpy.core import overrides
21_depmsg = ("numpy.{name} is deprecated and will be removed from NumPy 1.20. "
22 "Use numpy_financial.{name} instead "
23 "(https://pypi.org/project/numpy-financial/).")
25array_function_dispatch = functools.partial(
26 overrides.array_function_dispatch, module='numpy')
29__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate',
30 'irr', 'npv', 'mirr']
32_when_to_num = {'end':0, 'begin':1,
33 'e':0, 'b':1,
34 0:0, 1:1,
35 'beginning':1,
36 'start':1,
37 'finish':0}
39def _convert_when(when):
40 #Test to see if when has already been converted to ndarray
41 #This will happen if one function calls another, for example ppmt
42 if isinstance(when, np.ndarray):
43 return when
44 try:
45 return _when_to_num[when]
46 except (KeyError, TypeError):
47 return [_when_to_num[x] for x in when]
50def _fv_dispatcher(rate, nper, pmt, pv, when=None):
51 warnings.warn(_depmsg.format(name='fv'),
52 DeprecationWarning, stacklevel=3)
53 return (rate, nper, pmt, pv)
56@array_function_dispatch(_fv_dispatcher)
57def fv(rate, nper, pmt, pv, when='end'):
58 """
59 Compute the future value.
61 .. deprecated:: 1.18
63 `fv` is deprecated; for details, see NEP 32 [1]_.
64 Use the corresponding function in the numpy-financial library,
65 https://pypi.org/project/numpy-financial.
67 Given:
68 * a present value, `pv`
69 * an interest `rate` compounded once per period, of which
70 there are
71 * `nper` total
72 * a (fixed) payment, `pmt`, paid either
73 * at the beginning (`when` = {'begin', 1}) or the end
74 (`when` = {'end', 0}) of each period
76 Return:
77 the value at the end of the `nper` periods
79 Parameters
80 ----------
81 rate : scalar or array_like of shape(M, )
82 Rate of interest as decimal (not per cent) per period
83 nper : scalar or array_like of shape(M, )
84 Number of compounding periods
85 pmt : scalar or array_like of shape(M, )
86 Payment
87 pv : scalar or array_like of shape(M, )
88 Present value
89 when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
90 When payments are due ('begin' (1) or 'end' (0)).
91 Defaults to {'end', 0}.
93 Returns
94 -------
95 out : ndarray
96 Future values. If all input is scalar, returns a scalar float. If
97 any input is array_like, returns future values for each input element.
98 If multiple inputs are array_like, they all must have the same shape.
100 Notes
101 -----
102 The future value is computed by solving the equation::
104 fv +
105 pv*(1+rate)**nper +
106 pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
108 or, when ``rate == 0``::
110 fv + pv + pmt * nper == 0
112 References
113 ----------
114 .. [1] NumPy Enhancement Proposal (NEP) 32,
115 https://numpy.org/neps/nep-0032-remove-financial-functions.html
116 .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
117 Open Document Format for Office Applications (OpenDocument)v1.2,
118 Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
119 Pre-Draft 12. Organization for the Advancement of Structured Information
120 Standards (OASIS). Billerica, MA, USA. [ODT Document].
121 Available:
122 http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
123 OpenDocument-formula-20090508.odt
126 Examples
127 --------
128 What is the future value after 10 years of saving $100 now, with
129 an additional monthly savings of $100. Assume the interest rate is
130 5% (annually) compounded monthly?
132 >>> np.fv(0.05/12, 10*12, -100, -100)
133 15692.928894335748
135 By convention, the negative sign represents cash flow out (i.e. money not
136 available today). Thus, saving $100 a month at 5% annual interest leads
137 to $15,692.93 available to spend in 10 years.
139 If any input is array_like, returns an array of equal shape. Let's
140 compare different interest rates from the example above.
142 >>> a = np.array((0.05, 0.06, 0.07))/12
143 >>> np.fv(a, 10*12, -100, -100)
144 array([ 15692.92889434, 16569.87435405, 17509.44688102]) # may vary
146 """
147 when = _convert_when(when)
148 (rate, nper, pmt, pv, when) = map(np.asarray, [rate, nper, pmt, pv, when])
149 temp = (1+rate)**nper
150 fact = np.where(rate == 0, nper,
151 (1 + rate*when)*(temp - 1)/rate)
152 return -(pv*temp + pmt*fact)
155def _pmt_dispatcher(rate, nper, pv, fv=None, when=None):
156 warnings.warn(_depmsg.format(name='pmt'),
157 DeprecationWarning, stacklevel=3)
158 return (rate, nper, pv, fv)
161@array_function_dispatch(_pmt_dispatcher)
162def pmt(rate, nper, pv, fv=0, when='end'):
163 """
164 Compute the payment against loan principal plus interest.
166 .. deprecated:: 1.18
168 `pmt` is deprecated; for details, see NEP 32 [1]_.
169 Use the corresponding function in the numpy-financial library,
170 https://pypi.org/project/numpy-financial.
172 Given:
173 * a present value, `pv` (e.g., an amount borrowed)
174 * a future value, `fv` (e.g., 0)
175 * an interest `rate` compounded once per period, of which
176 there are
177 * `nper` total
178 * and (optional) specification of whether payment is made
179 at the beginning (`when` = {'begin', 1}) or the end
180 (`when` = {'end', 0}) of each period
182 Return:
183 the (fixed) periodic payment.
185 Parameters
186 ----------
187 rate : array_like
188 Rate of interest (per period)
189 nper : array_like
190 Number of compounding periods
191 pv : array_like
192 Present value
193 fv : array_like, optional
194 Future value (default = 0)
195 when : {{'begin', 1}, {'end', 0}}, {string, int}
196 When payments are due ('begin' (1) or 'end' (0))
198 Returns
199 -------
200 out : ndarray
201 Payment against loan plus interest. If all input is scalar, returns a
202 scalar float. If any input is array_like, returns payment for each
203 input element. If multiple inputs are array_like, they all must have
204 the same shape.
206 Notes
207 -----
208 The payment is computed by solving the equation::
210 fv +
211 pv*(1 + rate)**nper +
212 pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
214 or, when ``rate == 0``::
216 fv + pv + pmt * nper == 0
218 for ``pmt``.
220 Note that computing a monthly mortgage payment is only
221 one use for this function. For example, pmt returns the
222 periodic deposit one must make to achieve a specified
223 future balance given an initial deposit, a fixed,
224 periodically compounded interest rate, and the total
225 number of periods.
227 References
228 ----------
229 .. [1] NumPy Enhancement Proposal (NEP) 32,
230 https://numpy.org/neps/nep-0032-remove-financial-functions.html
231 .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
232 Open Document Format for Office Applications (OpenDocument)v1.2,
233 Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
234 Pre-Draft 12. Organization for the Advancement of Structured Information
235 Standards (OASIS). Billerica, MA, USA. [ODT Document].
236 Available:
237 http://www.oasis-open.org/committees/documents.php
238 ?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
240 Examples
241 --------
242 What is the monthly payment needed to pay off a $200,000 loan in 15
243 years at an annual interest rate of 7.5%?
245 >>> np.pmt(0.075/12, 12*15, 200000)
246 -1854.0247200054619
248 In order to pay-off (i.e., have a future-value of 0) the $200,000 obtained
249 today, a monthly payment of $1,854.02 would be required. Note that this
250 example illustrates usage of `fv` having a default value of 0.
252 """
253 when = _convert_when(when)
254 (rate, nper, pv, fv, when) = map(np.array, [rate, nper, pv, fv, when])
255 temp = (1 + rate)**nper
256 mask = (rate == 0)
257 masked_rate = np.where(mask, 1, rate)
258 fact = np.where(mask != 0, nper,
259 (1 + masked_rate*when)*(temp - 1)/masked_rate)
260 return -(fv + pv*temp) / fact
263def _nper_dispatcher(rate, pmt, pv, fv=None, when=None):
264 warnings.warn(_depmsg.format(name='nper'),
265 DeprecationWarning, stacklevel=3)
266 return (rate, pmt, pv, fv)
269@array_function_dispatch(_nper_dispatcher)
270def nper(rate, pmt, pv, fv=0, when='end'):
271 """
272 Compute the number of periodic payments.
274 .. deprecated:: 1.18
276 `nper` is deprecated; for details, see NEP 32 [1]_.
277 Use the corresponding function in the numpy-financial library,
278 https://pypi.org/project/numpy-financial.
280 :class:`decimal.Decimal` type is not supported.
282 Parameters
283 ----------
284 rate : array_like
285 Rate of interest (per period)
286 pmt : array_like
287 Payment
288 pv : array_like
289 Present value
290 fv : array_like, optional
291 Future value
292 when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
293 When payments are due ('begin' (1) or 'end' (0))
295 Notes
296 -----
297 The number of periods ``nper`` is computed by solving the equation::
299 fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate*((1+rate)**nper-1) = 0
301 but if ``rate = 0`` then::
303 fv + pv + pmt*nper = 0
305 References
306 ----------
307 .. [1] NumPy Enhancement Proposal (NEP) 32,
308 https://numpy.org/neps/nep-0032-remove-financial-functions.html
310 Examples
311 --------
312 If you only had $150/month to pay towards the loan, how long would it take
313 to pay-off a loan of $8,000 at 7% annual interest?
315 >>> print(np.round(np.nper(0.07/12, -150, 8000), 5))
316 64.07335
318 So, over 64 months would be required to pay off the loan.
320 The same analysis could be done with several different interest rates
321 and/or payments and/or total amounts to produce an entire table.
323 >>> np.nper(*(np.ogrid[0.07/12: 0.08/12: 0.01/12,
324 ... -150 : -99 : 50 ,
325 ... 8000 : 9001 : 1000]))
326 array([[[ 64.07334877, 74.06368256],
327 [108.07548412, 127.99022654]],
328 [[ 66.12443902, 76.87897353],
329 [114.70165583, 137.90124779]]])
331 """
332 when = _convert_when(when)
333 (rate, pmt, pv, fv, when) = map(np.asarray, [rate, pmt, pv, fv, when])
335 use_zero_rate = False
336 with np.errstate(divide="raise"):
337 try:
338 z = pmt*(1+rate*when)/rate
339 except FloatingPointError:
340 use_zero_rate = True
342 if use_zero_rate:
343 return (-fv + pv) / pmt
344 else:
345 A = -(fv + pv)/(pmt+0)
346 B = np.log((-fv+z) / (pv+z))/np.log(1+rate)
347 return np.where(rate == 0, A, B)
350def _ipmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
351 warnings.warn(_depmsg.format(name='ipmt'),
352 DeprecationWarning, stacklevel=3)
353 return (rate, per, nper, pv, fv)
356@array_function_dispatch(_ipmt_dispatcher)
357def ipmt(rate, per, nper, pv, fv=0, when='end'):
358 """
359 Compute the interest portion of a payment.
361 .. deprecated:: 1.18
363 `ipmt` is deprecated; for details, see NEP 32 [1]_.
364 Use the corresponding function in the numpy-financial library,
365 https://pypi.org/project/numpy-financial.
367 Parameters
368 ----------
369 rate : scalar or array_like of shape(M, )
370 Rate of interest as decimal (not per cent) per period
371 per : scalar or array_like of shape(M, )
372 Interest paid against the loan changes during the life or the loan.
373 The `per` is the payment period to calculate the interest amount.
374 nper : scalar or array_like of shape(M, )
375 Number of compounding periods
376 pv : scalar or array_like of shape(M, )
377 Present value
378 fv : scalar or array_like of shape(M, ), optional
379 Future value
380 when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
381 When payments are due ('begin' (1) or 'end' (0)).
382 Defaults to {'end', 0}.
384 Returns
385 -------
386 out : ndarray
387 Interest portion of payment. If all input is scalar, returns a scalar
388 float. If any input is array_like, returns interest payment for each
389 input element. If multiple inputs are array_like, they all must have
390 the same shape.
392 See Also
393 --------
394 ppmt, pmt, pv
396 Notes
397 -----
398 The total payment is made up of payment against principal plus interest.
400 ``pmt = ppmt + ipmt``
402 References
403 ----------
404 .. [1] NumPy Enhancement Proposal (NEP) 32,
405 https://numpy.org/neps/nep-0032-remove-financial-functions.html
407 Examples
408 --------
409 What is the amortization schedule for a 1 year loan of $2500 at
410 8.24% interest per year compounded monthly?
412 >>> principal = 2500.00
414 The 'per' variable represents the periods of the loan. Remember that
415 financial equations start the period count at 1!
417 >>> per = np.arange(1*12) + 1
418 >>> ipmt = np.ipmt(0.0824/12, per, 1*12, principal)
419 >>> ppmt = np.ppmt(0.0824/12, per, 1*12, principal)
421 Each element of the sum of the 'ipmt' and 'ppmt' arrays should equal
422 'pmt'.
424 >>> pmt = np.pmt(0.0824/12, 1*12, principal)
425 >>> np.allclose(ipmt + ppmt, pmt)
426 True
428 >>> fmt = '{0:2d} {1:8.2f} {2:8.2f} {3:8.2f}'
429 >>> for payment in per:
430 ... index = payment - 1
431 ... principal = principal + ppmt[index]
432 ... print(fmt.format(payment, ppmt[index], ipmt[index], principal))
433 1 -200.58 -17.17 2299.42
434 2 -201.96 -15.79 2097.46
435 3 -203.35 -14.40 1894.11
436 4 -204.74 -13.01 1689.37
437 5 -206.15 -11.60 1483.22
438 6 -207.56 -10.18 1275.66
439 7 -208.99 -8.76 1066.67
440 8 -210.42 -7.32 856.25
441 9 -211.87 -5.88 644.38
442 10 -213.32 -4.42 431.05
443 11 -214.79 -2.96 216.26
444 12 -216.26 -1.49 -0.00
446 >>> interestpd = np.sum(ipmt)
447 >>> np.round(interestpd, 2)
448 -112.98
450 """
451 when = _convert_when(when)
452 rate, per, nper, pv, fv, when = np.broadcast_arrays(rate, per, nper,
453 pv, fv, when)
454 total_pmt = pmt(rate, nper, pv, fv, when)
455 ipmt = _rbl(rate, per, total_pmt, pv, when)*rate
456 try:
457 ipmt = np.where(when == 1, ipmt/(1 + rate), ipmt)
458 ipmt = np.where(np.logical_and(when == 1, per == 1), 0, ipmt)
459 except IndexError:
460 pass
461 return ipmt
464def _rbl(rate, per, pmt, pv, when):
465 """
466 This function is here to simply have a different name for the 'fv'
467 function to not interfere with the 'fv' keyword argument within the 'ipmt'
468 function. It is the 'remaining balance on loan' which might be useful as
469 its own function, but is easily calculated with the 'fv' function.
470 """
471 return fv(rate, (per - 1), pmt, pv, when)
474def _ppmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
475 warnings.warn(_depmsg.format(name='ppmt'),
476 DeprecationWarning, stacklevel=3)
477 return (rate, per, nper, pv, fv)
480@array_function_dispatch(_ppmt_dispatcher)
481def ppmt(rate, per, nper, pv, fv=0, when='end'):
482 """
483 Compute the payment against loan principal.
485 .. deprecated:: 1.18
487 `ppmt` is deprecated; for details, see NEP 32 [1]_.
488 Use the corresponding function in the numpy-financial library,
489 https://pypi.org/project/numpy-financial.
491 Parameters
492 ----------
493 rate : array_like
494 Rate of interest (per period)
495 per : array_like, int
496 Amount paid against the loan changes. The `per` is the period of
497 interest.
498 nper : array_like
499 Number of compounding periods
500 pv : array_like
501 Present value
502 fv : array_like, optional
503 Future value
504 when : {{'begin', 1}, {'end', 0}}, {string, int}
505 When payments are due ('begin' (1) or 'end' (0))
507 See Also
508 --------
509 pmt, pv, ipmt
511 References
512 ----------
513 .. [1] NumPy Enhancement Proposal (NEP) 32,
514 https://numpy.org/neps/nep-0032-remove-financial-functions.html
516 """
517 total = pmt(rate, nper, pv, fv, when)
518 return total - ipmt(rate, per, nper, pv, fv, when)
521def _pv_dispatcher(rate, nper, pmt, fv=None, when=None):
522 warnings.warn(_depmsg.format(name='pv'),
523 DeprecationWarning, stacklevel=3)
524 return (rate, nper, nper, pv, fv)
527@array_function_dispatch(_pv_dispatcher)
528def pv(rate, nper, pmt, fv=0, when='end'):
529 """
530 Compute the present value.
532 .. deprecated:: 1.18
534 `pv` is deprecated; for details, see NEP 32 [1]_.
535 Use the corresponding function in the numpy-financial library,
536 https://pypi.org/project/numpy-financial.
538 Given:
539 * a future value, `fv`
540 * an interest `rate` compounded once per period, of which
541 there are
542 * `nper` total
543 * a (fixed) payment, `pmt`, paid either
544 * at the beginning (`when` = {'begin', 1}) or the end
545 (`when` = {'end', 0}) of each period
547 Return:
548 the value now
550 Parameters
551 ----------
552 rate : array_like
553 Rate of interest (per period)
554 nper : array_like
555 Number of compounding periods
556 pmt : array_like
557 Payment
558 fv : array_like, optional
559 Future value
560 when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
561 When payments are due ('begin' (1) or 'end' (0))
563 Returns
564 -------
565 out : ndarray, float
566 Present value of a series of payments or investments.
568 Notes
569 -----
570 The present value is computed by solving the equation::
572 fv +
573 pv*(1 + rate)**nper +
574 pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0
576 or, when ``rate = 0``::
578 fv + pv + pmt * nper = 0
580 for `pv`, which is then returned.
582 References
583 ----------
584 .. [1] NumPy Enhancement Proposal (NEP) 32,
585 https://numpy.org/neps/nep-0032-remove-financial-functions.html
586 .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
587 Open Document Format for Office Applications (OpenDocument)v1.2,
588 Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
589 Pre-Draft 12. Organization for the Advancement of Structured Information
590 Standards (OASIS). Billerica, MA, USA. [ODT Document].
591 Available:
592 http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
593 OpenDocument-formula-20090508.odt
595 Examples
596 --------
597 What is the present value (e.g., the initial investment)
598 of an investment that needs to total $15692.93
599 after 10 years of saving $100 every month? Assume the
600 interest rate is 5% (annually) compounded monthly.
602 >>> np.pv(0.05/12, 10*12, -100, 15692.93)
603 -100.00067131625819
605 By convention, the negative sign represents cash flow out
606 (i.e., money not available today). Thus, to end up with
607 $15,692.93 in 10 years saving $100 a month at 5% annual
608 interest, one's initial deposit should also be $100.
610 If any input is array_like, ``pv`` returns an array of equal shape.
611 Let's compare different interest rates in the example above:
613 >>> a = np.array((0.05, 0.04, 0.03))/12
614 >>> np.pv(a, 10*12, -100, 15692.93)
615 array([ -100.00067132, -649.26771385, -1273.78633713]) # may vary
617 So, to end up with the same $15692.93 under the same $100 per month
618 "savings plan," for annual interest rates of 4% and 3%, one would
619 need initial investments of $649.27 and $1273.79, respectively.
621 """
622 when = _convert_when(when)
623 (rate, nper, pmt, fv, when) = map(np.asarray, [rate, nper, pmt, fv, when])
624 temp = (1+rate)**nper
625 fact = np.where(rate == 0, nper, (1+rate*when)*(temp-1)/rate)
626 return -(fv + pmt*fact)/temp
628# Computed with Sage
629# (y + (r + 1)^n*x + p*((r + 1)^n - 1)*(r*w + 1)/r)/(n*(r + 1)^(n - 1)*x -
630# p*((r + 1)^n - 1)*(r*w + 1)/r^2 + n*p*(r + 1)^(n - 1)*(r*w + 1)/r +
631# p*((r + 1)^n - 1)*w/r)
633def _g_div_gp(r, n, p, x, y, w):
634 t1 = (r+1)**n
635 t2 = (r+1)**(n-1)
636 return ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) /
637 (n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r +
638 p*(t1 - 1)*w/r))
641def _rate_dispatcher(nper, pmt, pv, fv, when=None, guess=None, tol=None,
642 maxiter=None):
643 warnings.warn(_depmsg.format(name='rate'),
644 DeprecationWarning, stacklevel=3)
645 return (nper, pmt, pv, fv)
648# Use Newton's iteration until the change is less than 1e-6
649# for all values or a maximum of 100 iterations is reached.
650# Newton's rule is
651# r_{n+1} = r_{n} - g(r_n)/g'(r_n)
652# where
653# g(r) is the formula
654# g'(r) is the derivative with respect to r.
655@array_function_dispatch(_rate_dispatcher)
656def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100):
657 """
658 Compute the rate of interest per period.
660 .. deprecated:: 1.18
662 `rate` is deprecated; for details, see NEP 32 [1]_.
663 Use the corresponding function in the numpy-financial library,
664 https://pypi.org/project/numpy-financial.
666 Parameters
667 ----------
668 nper : array_like
669 Number of compounding periods
670 pmt : array_like
671 Payment
672 pv : array_like
673 Present value
674 fv : array_like
675 Future value
676 when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
677 When payments are due ('begin' (1) or 'end' (0))
678 guess : Number, optional
679 Starting guess for solving the rate of interest, default 0.1
680 tol : Number, optional
681 Required tolerance for the solution, default 1e-6
682 maxiter : int, optional
683 Maximum iterations in finding the solution
685 Notes
686 -----
687 The rate of interest is computed by iteratively solving the
688 (non-linear) equation::
690 fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate * ((1+rate)**nper - 1) = 0
692 for ``rate``.
694 References
695 ----------
696 .. [1] NumPy Enhancement Proposal (NEP) 32,
697 https://numpy.org/neps/nep-0032-remove-financial-functions.html
698 .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
699 Open Document Format for Office Applications (OpenDocument)v1.2,
700 Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
701 Pre-Draft 12. Organization for the Advancement of Structured Information
702 Standards (OASIS). Billerica, MA, USA. [ODT Document].
703 Available:
704 http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
705 OpenDocument-formula-20090508.odt
707 """
708 when = _convert_when(when)
709 default_type = Decimal if isinstance(pmt, Decimal) else float
711 # Handle casting defaults to Decimal if/when pmt is a Decimal and
712 # guess and/or tol are not given default values
713 if guess is None:
714 guess = default_type('0.1')
716 if tol is None:
717 tol = default_type('1e-6')
719 (nper, pmt, pv, fv, when) = map(np.asarray, [nper, pmt, pv, fv, when])
721 rn = guess
722 iterator = 0
723 close = False
724 while (iterator < maxiter) and not close:
725 rnp1 = rn - _g_div_gp(rn, nper, pmt, pv, fv, when)
726 diff = abs(rnp1-rn)
727 close = np.all(diff < tol)
728 iterator += 1
729 rn = rnp1
730 if not close:
731 # Return nan's in array of the same shape as rn
732 return np.nan + rn
733 else:
734 return rn
737def _irr_dispatcher(values):
738 warnings.warn(_depmsg.format(name='irr'),
739 DeprecationWarning, stacklevel=3)
740 return (values,)
743@array_function_dispatch(_irr_dispatcher)
744def irr(values):
745 """
746 Return the Internal Rate of Return (IRR).
748 .. deprecated:: 1.18
750 `irr` is deprecated; for details, see NEP 32 [1]_.
751 Use the corresponding function in the numpy-financial library,
752 https://pypi.org/project/numpy-financial.
754 This is the "average" periodically compounded rate of return
755 that gives a net present value of 0.0; for a more complete explanation,
756 see Notes below.
758 :class:`decimal.Decimal` type is not supported.
760 Parameters
761 ----------
762 values : array_like, shape(N,)
763 Input cash flows per time period. By convention, net "deposits"
764 are negative and net "withdrawals" are positive. Thus, for
765 example, at least the first element of `values`, which represents
766 the initial investment, will typically be negative.
768 Returns
769 -------
770 out : float
771 Internal Rate of Return for periodic input values.
773 Notes
774 -----
775 The IRR is perhaps best understood through an example (illustrated
776 using np.irr in the Examples section below). Suppose one invests 100
777 units and then makes the following withdrawals at regular (fixed)
778 intervals: 39, 59, 55, 20. Assuming the ending value is 0, one's 100
779 unit investment yields 173 units; however, due to the combination of
780 compounding and the periodic withdrawals, the "average" rate of return
781 is neither simply 0.73/4 nor (1.73)^0.25-1. Rather, it is the solution
782 (for :math:`r`) of the equation:
784 .. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2}
785 + \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0
787 In general, for `values` :math:`= [v_0, v_1, ... v_M]`,
788 irr is the solution of the equation: [2]_
790 .. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0
792 References
793 ----------
794 .. [1] NumPy Enhancement Proposal (NEP) 32,
795 https://numpy.org/neps/nep-0032-remove-financial-functions.html
796 .. [2] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
797 Addison-Wesley, 2003, pg. 348.
799 Examples
800 --------
801 >>> round(np.irr([-100, 39, 59, 55, 20]), 5)
802 0.28095
803 >>> round(np.irr([-100, 0, 0, 74]), 5)
804 -0.0955
805 >>> round(np.irr([-100, 100, 0, -7]), 5)
806 -0.0833
807 >>> round(np.irr([-100, 100, 0, 7]), 5)
808 0.06206
809 >>> round(np.irr([-5, 10.5, 1, -8, 1]), 5)
810 0.0886
812 """
813 # `np.roots` call is why this function does not support Decimal type.
814 #
815 # Ultimately Decimal support needs to be added to np.roots, which has
816 # greater implications on the entire linear algebra module and how it does
817 # eigenvalue computations.
818 res = np.roots(values[::-1])
819 mask = (res.imag == 0) & (res.real > 0)
820 if not mask.any():
821 return np.nan
822 res = res[mask].real
823 # NPV(rate) = 0 can have more than one solution so we return
824 # only the solution closest to zero.
825 rate = 1/res - 1
826 rate = rate.item(np.argmin(np.abs(rate)))
827 return rate
830def _npv_dispatcher(rate, values):
831 warnings.warn(_depmsg.format(name='npv'),
832 DeprecationWarning, stacklevel=3)
833 return (values,)
836@array_function_dispatch(_npv_dispatcher)
837def npv(rate, values):
838 """
839 Returns the NPV (Net Present Value) of a cash flow series.
841 .. deprecated:: 1.18
843 `npv` is deprecated; for details, see NEP 32 [1]_.
844 Use the corresponding function in the numpy-financial library,
845 https://pypi.org/project/numpy-financial.
847 Parameters
848 ----------
849 rate : scalar
850 The discount rate.
851 values : array_like, shape(M, )
852 The values of the time series of cash flows. The (fixed) time
853 interval between cash flow "events" must be the same as that for
854 which `rate` is given (i.e., if `rate` is per year, then precisely
855 a year is understood to elapse between each cash flow event). By
856 convention, investments or "deposits" are negative, income or
857 "withdrawals" are positive; `values` must begin with the initial
858 investment, thus `values[0]` will typically be negative.
860 Returns
861 -------
862 out : float
863 The NPV of the input cash flow series `values` at the discount
864 `rate`.
866 Warnings
867 --------
868 ``npv`` considers a series of cashflows starting in the present (t = 0).
869 NPV can also be defined with a series of future cashflows, paid at the
870 end, rather than the start, of each period. If future cashflows are used,
871 the first cashflow `values[0]` must be zeroed and added to the net
872 present value of the future cashflows. This is demonstrated in the
873 examples.
875 Notes
876 -----
877 Returns the result of: [2]_
879 .. math :: \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}}
881 References
882 ----------
883 .. [1] NumPy Enhancement Proposal (NEP) 32,
884 https://numpy.org/neps/nep-0032-remove-financial-functions.html
885 .. [2] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
886 Addison-Wesley, 2003, pg. 346.
888 Examples
889 --------
890 Consider a potential project with an initial investment of $40 000 and
891 projected cashflows of $5 000, $8 000, $12 000 and $30 000 at the end of
892 each period discounted at a rate of 8% per period. To find the project's
893 net present value:
895 >>> rate, cashflows = 0.08, [-40_000, 5_000, 8_000, 12_000, 30_000]
896 >>> np.npv(rate, cashflows).round(5)
897 3065.22267
899 It may be preferable to split the projected cashflow into an initial
900 investment and expected future cashflows. In this case, the value of
901 the initial cashflow is zero and the initial investment is later added
902 to the future cashflows net present value:
904 >>> initial_cashflow = cashflows[0]
905 >>> cashflows[0] = 0
906 >>> np.round(np.npv(rate, cashflows) + initial_cashflow, 5)
907 3065.22267
909 """
910 values = np.asarray(values)
911 return (values / (1+rate)**np.arange(0, len(values))).sum(axis=0)
914def _mirr_dispatcher(values, finance_rate, reinvest_rate):
915 warnings.warn(_depmsg.format(name='mirr'),
916 DeprecationWarning, stacklevel=3)
917 return (values,)
920@array_function_dispatch(_mirr_dispatcher)
921def mirr(values, finance_rate, reinvest_rate):
922 """
923 Modified internal rate of return.
925 .. deprecated:: 1.18
927 `mirr` is deprecated; for details, see NEP 32 [1]_.
928 Use the corresponding function in the numpy-financial library,
929 https://pypi.org/project/numpy-financial.
931 Parameters
932 ----------
933 values : array_like
934 Cash flows (must contain at least one positive and one negative
935 value) or nan is returned. The first value is considered a sunk
936 cost at time zero.
937 finance_rate : scalar
938 Interest rate paid on the cash flows
939 reinvest_rate : scalar
940 Interest rate received on the cash flows upon reinvestment
942 Returns
943 -------
944 out : float
945 Modified internal rate of return
947 References
948 ----------
949 .. [1] NumPy Enhancement Proposal (NEP) 32,
950 https://numpy.org/neps/nep-0032-remove-financial-functions.html
951 """
952 values = np.asarray(values)
953 n = values.size
955 # Without this explicit cast the 1/(n - 1) computation below
956 # becomes a float, which causes TypeError when using Decimal
957 # values.
958 if isinstance(finance_rate, Decimal):
959 n = Decimal(n)
961 pos = values > 0
962 neg = values < 0
963 if not (pos.any() and neg.any()):
964 return np.nan
965 numer = np.abs(npv(reinvest_rate, values*pos))
966 denom = np.abs(npv(finance_rate, values*neg))
967 return (numer/denom)**(1/(n - 1))*(1 + reinvest_rate) - 1