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