financial.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. """Some simple financial calculations
  2. patterned after spreadsheet computations.
  3. There is some complexity in each function
  4. so that the functions behave like ufuncs with
  5. broadcasting and being able to be called with scalars
  6. or arrays (or other sequences).
  7. Functions support the :class:`decimal.Decimal` type unless
  8. otherwise stated.
  9. """
  10. from __future__ import division, absolute_import, print_function
  11. from decimal import Decimal
  12. import functools
  13. import numpy as np
  14. from numpy.core import overrides
  15. array_function_dispatch = functools.partial(
  16. overrides.array_function_dispatch, module='numpy')
  17. __all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate',
  18. 'irr', 'npv', 'mirr']
  19. _when_to_num = {'end':0, 'begin':1,
  20. 'e':0, 'b':1,
  21. 0:0, 1:1,
  22. 'beginning':1,
  23. 'start':1,
  24. 'finish':0}
  25. def _convert_when(when):
  26. #Test to see if when has already been converted to ndarray
  27. #This will happen if one function calls another, for example ppmt
  28. if isinstance(when, np.ndarray):
  29. return when
  30. try:
  31. return _when_to_num[when]
  32. except (KeyError, TypeError):
  33. return [_when_to_num[x] for x in when]
  34. def _fv_dispatcher(rate, nper, pmt, pv, when=None):
  35. return (rate, nper, pmt, pv)
  36. @array_function_dispatch(_fv_dispatcher)
  37. def fv(rate, nper, pmt, pv, when='end'):
  38. """
  39. Compute the future value.
  40. Given:
  41. * a present value, `pv`
  42. * an interest `rate` compounded once per period, of which
  43. there are
  44. * `nper` total
  45. * a (fixed) payment, `pmt`, paid either
  46. * at the beginning (`when` = {'begin', 1}) or the end
  47. (`when` = {'end', 0}) of each period
  48. Return:
  49. the value at the end of the `nper` periods
  50. Parameters
  51. ----------
  52. rate : scalar or array_like of shape(M, )
  53. Rate of interest as decimal (not per cent) per period
  54. nper : scalar or array_like of shape(M, )
  55. Number of compounding periods
  56. pmt : scalar or array_like of shape(M, )
  57. Payment
  58. pv : scalar or array_like of shape(M, )
  59. Present value
  60. when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
  61. When payments are due ('begin' (1) or 'end' (0)).
  62. Defaults to {'end', 0}.
  63. Returns
  64. -------
  65. out : ndarray
  66. Future values. If all input is scalar, returns a scalar float. If
  67. any input is array_like, returns future values for each input element.
  68. If multiple inputs are array_like, they all must have the same shape.
  69. Notes
  70. -----
  71. The future value is computed by solving the equation::
  72. fv +
  73. pv*(1+rate)**nper +
  74. pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
  75. or, when ``rate == 0``::
  76. fv + pv + pmt * nper == 0
  77. References
  78. ----------
  79. .. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
  80. Open Document Format for Office Applications (OpenDocument)v1.2,
  81. Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
  82. Pre-Draft 12. Organization for the Advancement of Structured Information
  83. Standards (OASIS). Billerica, MA, USA. [ODT Document].
  84. Available:
  85. http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
  86. OpenDocument-formula-20090508.odt
  87. Examples
  88. --------
  89. What is the future value after 10 years of saving $100 now, with
  90. an additional monthly savings of $100. Assume the interest rate is
  91. 5% (annually) compounded monthly?
  92. >>> np.fv(0.05/12, 10*12, -100, -100)
  93. 15692.928894335748
  94. By convention, the negative sign represents cash flow out (i.e. money not
  95. available today). Thus, saving $100 a month at 5% annual interest leads
  96. to $15,692.93 available to spend in 10 years.
  97. If any input is array_like, returns an array of equal shape. Let's
  98. compare different interest rates from the example above.
  99. >>> a = np.array((0.05, 0.06, 0.07))/12
  100. >>> np.fv(a, 10*12, -100, -100)
  101. array([ 15692.92889434, 16569.87435405, 17509.44688102])
  102. """
  103. when = _convert_when(when)
  104. (rate, nper, pmt, pv, when) = map(np.asarray, [rate, nper, pmt, pv, when])
  105. temp = (1+rate)**nper
  106. fact = np.where(rate == 0, nper,
  107. (1 + rate*when)*(temp - 1)/rate)
  108. return -(pv*temp + pmt*fact)
  109. def _pmt_dispatcher(rate, nper, pv, fv=None, when=None):
  110. return (rate, nper, pv, fv)
  111. @array_function_dispatch(_pmt_dispatcher)
  112. def pmt(rate, nper, pv, fv=0, when='end'):
  113. """
  114. Compute the payment against loan principal plus interest.
  115. Given:
  116. * a present value, `pv` (e.g., an amount borrowed)
  117. * a future value, `fv` (e.g., 0)
  118. * an interest `rate` compounded once per period, of which
  119. there are
  120. * `nper` total
  121. * and (optional) specification of whether payment is made
  122. at the beginning (`when` = {'begin', 1}) or the end
  123. (`when` = {'end', 0}) of each period
  124. Return:
  125. the (fixed) periodic payment.
  126. Parameters
  127. ----------
  128. rate : array_like
  129. Rate of interest (per period)
  130. nper : array_like
  131. Number of compounding periods
  132. pv : array_like
  133. Present value
  134. fv : array_like, optional
  135. Future value (default = 0)
  136. when : {{'begin', 1}, {'end', 0}}, {string, int}
  137. When payments are due ('begin' (1) or 'end' (0))
  138. Returns
  139. -------
  140. out : ndarray
  141. Payment against loan plus interest. If all input is scalar, returns a
  142. scalar float. If any input is array_like, returns payment for each
  143. input element. If multiple inputs are array_like, they all must have
  144. the same shape.
  145. Notes
  146. -----
  147. The payment is computed by solving the equation::
  148. fv +
  149. pv*(1 + rate)**nper +
  150. pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
  151. or, when ``rate == 0``::
  152. fv + pv + pmt * nper == 0
  153. for ``pmt``.
  154. Note that computing a monthly mortgage payment is only
  155. one use for this function. For example, pmt returns the
  156. periodic deposit one must make to achieve a specified
  157. future balance given an initial deposit, a fixed,
  158. periodically compounded interest rate, and the total
  159. number of periods.
  160. References
  161. ----------
  162. .. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
  163. Open Document Format for Office Applications (OpenDocument)v1.2,
  164. Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
  165. Pre-Draft 12. Organization for the Advancement of Structured Information
  166. Standards (OASIS). Billerica, MA, USA. [ODT Document].
  167. Available:
  168. http://www.oasis-open.org/committees/documents.php
  169. ?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
  170. Examples
  171. --------
  172. What is the monthly payment needed to pay off a $200,000 loan in 15
  173. years at an annual interest rate of 7.5%?
  174. >>> np.pmt(0.075/12, 12*15, 200000)
  175. -1854.0247200054619
  176. In order to pay-off (i.e., have a future-value of 0) the $200,000 obtained
  177. today, a monthly payment of $1,854.02 would be required. Note that this
  178. example illustrates usage of `fv` having a default value of 0.
  179. """
  180. when = _convert_when(when)
  181. (rate, nper, pv, fv, when) = map(np.array, [rate, nper, pv, fv, when])
  182. temp = (1 + rate)**nper
  183. mask = (rate == 0)
  184. masked_rate = np.where(mask, 1, rate)
  185. fact = np.where(mask != 0, nper,
  186. (1 + masked_rate*when)*(temp - 1)/masked_rate)
  187. return -(fv + pv*temp) / fact
  188. def _nper_dispatcher(rate, pmt, pv, fv=None, when=None):
  189. return (rate, pmt, pv, fv)
  190. @array_function_dispatch(_nper_dispatcher)
  191. def nper(rate, pmt, pv, fv=0, when='end'):
  192. """
  193. Compute the number of periodic payments.
  194. :class:`decimal.Decimal` type is not supported.
  195. Parameters
  196. ----------
  197. rate : array_like
  198. Rate of interest (per period)
  199. pmt : array_like
  200. Payment
  201. pv : array_like
  202. Present value
  203. fv : array_like, optional
  204. Future value
  205. when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
  206. When payments are due ('begin' (1) or 'end' (0))
  207. Notes
  208. -----
  209. The number of periods ``nper`` is computed by solving the equation::
  210. fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate*((1+rate)**nper-1) = 0
  211. but if ``rate = 0`` then::
  212. fv + pv + pmt*nper = 0
  213. Examples
  214. --------
  215. If you only had $150/month to pay towards the loan, how long would it take
  216. to pay-off a loan of $8,000 at 7% annual interest?
  217. >>> print(round(np.nper(0.07/12, -150, 8000), 5))
  218. 64.07335
  219. So, over 64 months would be required to pay off the loan.
  220. The same analysis could be done with several different interest rates
  221. and/or payments and/or total amounts to produce an entire table.
  222. >>> np.nper(*(np.ogrid[0.07/12: 0.08/12: 0.01/12,
  223. ... -150 : -99 : 50 ,
  224. ... 8000 : 9001 : 1000]))
  225. array([[[ 64.07334877, 74.06368256],
  226. [ 108.07548412, 127.99022654]],
  227. [[ 66.12443902, 76.87897353],
  228. [ 114.70165583, 137.90124779]]])
  229. """
  230. when = _convert_when(when)
  231. (rate, pmt, pv, fv, when) = map(np.asarray, [rate, pmt, pv, fv, when])
  232. use_zero_rate = False
  233. with np.errstate(divide="raise"):
  234. try:
  235. z = pmt*(1+rate*when)/rate
  236. except FloatingPointError:
  237. use_zero_rate = True
  238. if use_zero_rate:
  239. return (-fv + pv) / pmt
  240. else:
  241. A = -(fv + pv)/(pmt+0)
  242. B = np.log((-fv+z) / (pv+z))/np.log(1+rate)
  243. return np.where(rate == 0, A, B)
  244. def _ipmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
  245. return (rate, per, nper, pv, fv)
  246. @array_function_dispatch(_ipmt_dispatcher)
  247. def ipmt(rate, per, nper, pv, fv=0, when='end'):
  248. """
  249. Compute the interest portion of a payment.
  250. Parameters
  251. ----------
  252. rate : scalar or array_like of shape(M, )
  253. Rate of interest as decimal (not per cent) per period
  254. per : scalar or array_like of shape(M, )
  255. Interest paid against the loan changes during the life or the loan.
  256. The `per` is the payment period to calculate the interest amount.
  257. nper : scalar or array_like of shape(M, )
  258. Number of compounding periods
  259. pv : scalar or array_like of shape(M, )
  260. Present value
  261. fv : scalar or array_like of shape(M, ), optional
  262. Future value
  263. when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
  264. When payments are due ('begin' (1) or 'end' (0)).
  265. Defaults to {'end', 0}.
  266. Returns
  267. -------
  268. out : ndarray
  269. Interest portion of payment. If all input is scalar, returns a scalar
  270. float. If any input is array_like, returns interest payment for each
  271. input element. If multiple inputs are array_like, they all must have
  272. the same shape.
  273. See Also
  274. --------
  275. ppmt, pmt, pv
  276. Notes
  277. -----
  278. The total payment is made up of payment against principal plus interest.
  279. ``pmt = ppmt + ipmt``
  280. Examples
  281. --------
  282. What is the amortization schedule for a 1 year loan of $2500 at
  283. 8.24% interest per year compounded monthly?
  284. >>> principal = 2500.00
  285. The 'per' variable represents the periods of the loan. Remember that
  286. financial equations start the period count at 1!
  287. >>> per = np.arange(1*12) + 1
  288. >>> ipmt = np.ipmt(0.0824/12, per, 1*12, principal)
  289. >>> ppmt = np.ppmt(0.0824/12, per, 1*12, principal)
  290. Each element of the sum of the 'ipmt' and 'ppmt' arrays should equal
  291. 'pmt'.
  292. >>> pmt = np.pmt(0.0824/12, 1*12, principal)
  293. >>> np.allclose(ipmt + ppmt, pmt)
  294. True
  295. >>> fmt = '{0:2d} {1:8.2f} {2:8.2f} {3:8.2f}'
  296. >>> for payment in per:
  297. ... index = payment - 1
  298. ... principal = principal + ppmt[index]
  299. ... print(fmt.format(payment, ppmt[index], ipmt[index], principal))
  300. 1 -200.58 -17.17 2299.42
  301. 2 -201.96 -15.79 2097.46
  302. 3 -203.35 -14.40 1894.11
  303. 4 -204.74 -13.01 1689.37
  304. 5 -206.15 -11.60 1483.22
  305. 6 -207.56 -10.18 1275.66
  306. 7 -208.99 -8.76 1066.67
  307. 8 -210.42 -7.32 856.25
  308. 9 -211.87 -5.88 644.38
  309. 10 -213.32 -4.42 431.05
  310. 11 -214.79 -2.96 216.26
  311. 12 -216.26 -1.49 -0.00
  312. >>> interestpd = np.sum(ipmt)
  313. >>> np.round(interestpd, 2)
  314. -112.98
  315. """
  316. when = _convert_when(when)
  317. rate, per, nper, pv, fv, when = np.broadcast_arrays(rate, per, nper,
  318. pv, fv, when)
  319. total_pmt = pmt(rate, nper, pv, fv, when)
  320. ipmt = _rbl(rate, per, total_pmt, pv, when)*rate
  321. try:
  322. ipmt = np.where(when == 1, ipmt/(1 + rate), ipmt)
  323. ipmt = np.where(np.logical_and(when == 1, per == 1), 0, ipmt)
  324. except IndexError:
  325. pass
  326. return ipmt
  327. def _rbl(rate, per, pmt, pv, when):
  328. """
  329. This function is here to simply have a different name for the 'fv'
  330. function to not interfere with the 'fv' keyword argument within the 'ipmt'
  331. function. It is the 'remaining balance on loan' which might be useful as
  332. it's own function, but is easily calculated with the 'fv' function.
  333. """
  334. return fv(rate, (per - 1), pmt, pv, when)
  335. def _ppmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
  336. return (rate, per, nper, pv, fv)
  337. @array_function_dispatch(_ppmt_dispatcher)
  338. def ppmt(rate, per, nper, pv, fv=0, when='end'):
  339. """
  340. Compute the payment against loan principal.
  341. Parameters
  342. ----------
  343. rate : array_like
  344. Rate of interest (per period)
  345. per : array_like, int
  346. Amount paid against the loan changes. The `per` is the period of
  347. interest.
  348. nper : array_like
  349. Number of compounding periods
  350. pv : array_like
  351. Present value
  352. fv : array_like, optional
  353. Future value
  354. when : {{'begin', 1}, {'end', 0}}, {string, int}
  355. When payments are due ('begin' (1) or 'end' (0))
  356. See Also
  357. --------
  358. pmt, pv, ipmt
  359. """
  360. total = pmt(rate, nper, pv, fv, when)
  361. return total - ipmt(rate, per, nper, pv, fv, when)
  362. def _pv_dispatcher(rate, nper, pmt, fv=None, when=None):
  363. return (rate, nper, nper, pv, fv)
  364. @array_function_dispatch(_pv_dispatcher)
  365. def pv(rate, nper, pmt, fv=0, when='end'):
  366. """
  367. Compute the present value.
  368. Given:
  369. * a future value, `fv`
  370. * an interest `rate` compounded once per period, of which
  371. there are
  372. * `nper` total
  373. * a (fixed) payment, `pmt`, paid either
  374. * at the beginning (`when` = {'begin', 1}) or the end
  375. (`when` = {'end', 0}) of each period
  376. Return:
  377. the value now
  378. Parameters
  379. ----------
  380. rate : array_like
  381. Rate of interest (per period)
  382. nper : array_like
  383. Number of compounding periods
  384. pmt : array_like
  385. Payment
  386. fv : array_like, optional
  387. Future value
  388. when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
  389. When payments are due ('begin' (1) or 'end' (0))
  390. Returns
  391. -------
  392. out : ndarray, float
  393. Present value of a series of payments or investments.
  394. Notes
  395. -----
  396. The present value is computed by solving the equation::
  397. fv +
  398. pv*(1 + rate)**nper +
  399. pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0
  400. or, when ``rate = 0``::
  401. fv + pv + pmt * nper = 0
  402. for `pv`, which is then returned.
  403. References
  404. ----------
  405. .. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
  406. Open Document Format for Office Applications (OpenDocument)v1.2,
  407. Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
  408. Pre-Draft 12. Organization for the Advancement of Structured Information
  409. Standards (OASIS). Billerica, MA, USA. [ODT Document].
  410. Available:
  411. http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
  412. OpenDocument-formula-20090508.odt
  413. Examples
  414. --------
  415. What is the present value (e.g., the initial investment)
  416. of an investment that needs to total $15692.93
  417. after 10 years of saving $100 every month? Assume the
  418. interest rate is 5% (annually) compounded monthly.
  419. >>> np.pv(0.05/12, 10*12, -100, 15692.93)
  420. -100.00067131625819
  421. By convention, the negative sign represents cash flow out
  422. (i.e., money not available today). Thus, to end up with
  423. $15,692.93 in 10 years saving $100 a month at 5% annual
  424. interest, one's initial deposit should also be $100.
  425. If any input is array_like, ``pv`` returns an array of equal shape.
  426. Let's compare different interest rates in the example above:
  427. >>> a = np.array((0.05, 0.04, 0.03))/12
  428. >>> np.pv(a, 10*12, -100, 15692.93)
  429. array([ -100.00067132, -649.26771385, -1273.78633713])
  430. So, to end up with the same $15692.93 under the same $100 per month
  431. "savings plan," for annual interest rates of 4% and 3%, one would
  432. need initial investments of $649.27 and $1273.79, respectively.
  433. """
  434. when = _convert_when(when)
  435. (rate, nper, pmt, fv, when) = map(np.asarray, [rate, nper, pmt, fv, when])
  436. temp = (1+rate)**nper
  437. fact = np.where(rate == 0, nper, (1+rate*when)*(temp-1)/rate)
  438. return -(fv + pmt*fact)/temp
  439. # Computed with Sage
  440. # (y + (r + 1)^n*x + p*((r + 1)^n - 1)*(r*w + 1)/r)/(n*(r + 1)^(n - 1)*x -
  441. # p*((r + 1)^n - 1)*(r*w + 1)/r^2 + n*p*(r + 1)^(n - 1)*(r*w + 1)/r +
  442. # p*((r + 1)^n - 1)*w/r)
  443. def _g_div_gp(r, n, p, x, y, w):
  444. t1 = (r+1)**n
  445. t2 = (r+1)**(n-1)
  446. return ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) /
  447. (n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r +
  448. p*(t1 - 1)*w/r))
  449. def _rate_dispatcher(nper, pmt, pv, fv, when=None, guess=None, tol=None,
  450. maxiter=None):
  451. return (nper, pmt, pv, fv)
  452. # Use Newton's iteration until the change is less than 1e-6
  453. # for all values or a maximum of 100 iterations is reached.
  454. # Newton's rule is
  455. # r_{n+1} = r_{n} - g(r_n)/g'(r_n)
  456. # where
  457. # g(r) is the formula
  458. # g'(r) is the derivative with respect to r.
  459. @array_function_dispatch(_rate_dispatcher)
  460. def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100):
  461. """
  462. Compute the rate of interest per period.
  463. Parameters
  464. ----------
  465. nper : array_like
  466. Number of compounding periods
  467. pmt : array_like
  468. Payment
  469. pv : array_like
  470. Present value
  471. fv : array_like
  472. Future value
  473. when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
  474. When payments are due ('begin' (1) or 'end' (0))
  475. guess : Number, optional
  476. Starting guess for solving the rate of interest, default 0.1
  477. tol : Number, optional
  478. Required tolerance for the solution, default 1e-6
  479. maxiter : int, optional
  480. Maximum iterations in finding the solution
  481. Notes
  482. -----
  483. The rate of interest is computed by iteratively solving the
  484. (non-linear) equation::
  485. fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate * ((1+rate)**nper - 1) = 0
  486. for ``rate``.
  487. References
  488. ----------
  489. Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). Open Document
  490. Format for Office Applications (OpenDocument)v1.2, Part 2: Recalculated
  491. Formula (OpenFormula) Format - Annotated Version, Pre-Draft 12.
  492. Organization for the Advancement of Structured Information Standards
  493. (OASIS). Billerica, MA, USA. [ODT Document]. Available:
  494. http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
  495. OpenDocument-formula-20090508.odt
  496. """
  497. when = _convert_when(when)
  498. default_type = Decimal if isinstance(pmt, Decimal) else float
  499. # Handle casting defaults to Decimal if/when pmt is a Decimal and
  500. # guess and/or tol are not given default values
  501. if guess is None:
  502. guess = default_type('0.1')
  503. if tol is None:
  504. tol = default_type('1e-6')
  505. (nper, pmt, pv, fv, when) = map(np.asarray, [nper, pmt, pv, fv, when])
  506. rn = guess
  507. iterator = 0
  508. close = False
  509. while (iterator < maxiter) and not close:
  510. rnp1 = rn - _g_div_gp(rn, nper, pmt, pv, fv, when)
  511. diff = abs(rnp1-rn)
  512. close = np.all(diff < tol)
  513. iterator += 1
  514. rn = rnp1
  515. if not close:
  516. # Return nan's in array of the same shape as rn
  517. return np.nan + rn
  518. else:
  519. return rn
  520. def _irr_dispatcher(values):
  521. return (values,)
  522. @array_function_dispatch(_irr_dispatcher)
  523. def irr(values):
  524. """
  525. Return the Internal Rate of Return (IRR).
  526. This is the "average" periodically compounded rate of return
  527. that gives a net present value of 0.0; for a more complete explanation,
  528. see Notes below.
  529. :class:`decimal.Decimal` type is not supported.
  530. Parameters
  531. ----------
  532. values : array_like, shape(N,)
  533. Input cash flows per time period. By convention, net "deposits"
  534. are negative and net "withdrawals" are positive. Thus, for
  535. example, at least the first element of `values`, which represents
  536. the initial investment, will typically be negative.
  537. Returns
  538. -------
  539. out : float
  540. Internal Rate of Return for periodic input values.
  541. Notes
  542. -----
  543. The IRR is perhaps best understood through an example (illustrated
  544. using np.irr in the Examples section below). Suppose one invests 100
  545. units and then makes the following withdrawals at regular (fixed)
  546. intervals: 39, 59, 55, 20. Assuming the ending value is 0, one's 100
  547. unit investment yields 173 units; however, due to the combination of
  548. compounding and the periodic withdrawals, the "average" rate of return
  549. is neither simply 0.73/4 nor (1.73)^0.25-1. Rather, it is the solution
  550. (for :math:`r`) of the equation:
  551. .. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2}
  552. + \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0
  553. In general, for `values` :math:`= [v_0, v_1, ... v_M]`,
  554. irr is the solution of the equation: [G]_
  555. .. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0
  556. References
  557. ----------
  558. .. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
  559. Addison-Wesley, 2003, pg. 348.
  560. Examples
  561. --------
  562. >>> round(irr([-100, 39, 59, 55, 20]), 5)
  563. 0.28095
  564. >>> round(irr([-100, 0, 0, 74]), 5)
  565. -0.0955
  566. >>> round(irr([-100, 100, 0, -7]), 5)
  567. -0.0833
  568. >>> round(irr([-100, 100, 0, 7]), 5)
  569. 0.06206
  570. >>> round(irr([-5, 10.5, 1, -8, 1]), 5)
  571. 0.0886
  572. (Compare with the Example given for numpy.lib.financial.npv)
  573. """
  574. # `np.roots` call is why this function does not support Decimal type.
  575. #
  576. # Ultimately Decimal support needs to be added to np.roots, which has
  577. # greater implications on the entire linear algebra module and how it does
  578. # eigenvalue computations.
  579. res = np.roots(values[::-1])
  580. mask = (res.imag == 0) & (res.real > 0)
  581. if not mask.any():
  582. return np.nan
  583. res = res[mask].real
  584. # NPV(rate) = 0 can have more than one solution so we return
  585. # only the solution closest to zero.
  586. rate = 1/res - 1
  587. rate = rate.item(np.argmin(np.abs(rate)))
  588. return rate
  589. def _npv_dispatcher(rate, values):
  590. return (values,)
  591. @array_function_dispatch(_npv_dispatcher)
  592. def npv(rate, values):
  593. """
  594. Returns the NPV (Net Present Value) of a cash flow series.
  595. Parameters
  596. ----------
  597. rate : scalar
  598. The discount rate.
  599. values : array_like, shape(M, )
  600. The values of the time series of cash flows. The (fixed) time
  601. interval between cash flow "events" must be the same as that for
  602. which `rate` is given (i.e., if `rate` is per year, then precisely
  603. a year is understood to elapse between each cash flow event). By
  604. convention, investments or "deposits" are negative, income or
  605. "withdrawals" are positive; `values` must begin with the initial
  606. investment, thus `values[0]` will typically be negative.
  607. Returns
  608. -------
  609. out : float
  610. The NPV of the input cash flow series `values` at the discount
  611. `rate`.
  612. Notes
  613. -----
  614. Returns the result of: [G]_
  615. .. math :: \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}}
  616. References
  617. ----------
  618. .. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
  619. Addison-Wesley, 2003, pg. 346.
  620. Examples
  621. --------
  622. >>> np.npv(0.281,[-100, 39, 59, 55, 20])
  623. -0.0084785916384548798
  624. (Compare with the Example given for numpy.lib.financial.irr)
  625. """
  626. values = np.asarray(values)
  627. return (values / (1+rate)**np.arange(0, len(values))).sum(axis=0)
  628. def _mirr_dispatcher(values, finance_rate, reinvest_rate):
  629. return (values,)
  630. @array_function_dispatch(_mirr_dispatcher)
  631. def mirr(values, finance_rate, reinvest_rate):
  632. """
  633. Modified internal rate of return.
  634. Parameters
  635. ----------
  636. values : array_like
  637. Cash flows (must contain at least one positive and one negative
  638. value) or nan is returned. The first value is considered a sunk
  639. cost at time zero.
  640. finance_rate : scalar
  641. Interest rate paid on the cash flows
  642. reinvest_rate : scalar
  643. Interest rate received on the cash flows upon reinvestment
  644. Returns
  645. -------
  646. out : float
  647. Modified internal rate of return
  648. """
  649. values = np.asarray(values)
  650. n = values.size
  651. # Without this explicit cast the 1/(n - 1) computation below
  652. # becomes a float, which causes TypeError when using Decimal
  653. # values.
  654. if isinstance(finance_rate, Decimal):
  655. n = Decimal(n)
  656. pos = values > 0
  657. neg = values < 0
  658. if not (pos.any() and neg.any()):
  659. return np.nan
  660. numer = np.abs(npv(reinvest_rate, values*pos))
  661. denom = np.abs(npv(finance_rate, values*neg))
  662. return (numer/denom)**(1/(n - 1))*(1 + reinvest_rate) - 1