1
-
2
1
from decimal import Decimal
2
+ import math
3
3
4
4
# Don't use 'import numpy as np', to avoid accidentally testing
5
5
# the versions in numpy instead of numpy_financial.
6
6
import numpy
7
7
from numpy .testing import (
8
- assert_ , assert_almost_equal , assert_allclose , assert_equal , assert_raises
8
+ assert_ , assert_almost_equal , assert_allclose , assert_equal
9
9
)
10
10
import pytest
11
11
@@ -90,35 +90,6 @@ def test_pmt_decimal(self):
90
90
assert_equal (res [1 ][0 ], tgt [1 ][0 ])
91
91
assert_equal (res [1 ][1 ], tgt [1 ][1 ])
92
92
93
- def test_ppmt (self ):
94
- assert_equal (numpy .round (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 ), 2 ), - 710.25 )
95
-
96
- def test_ppmt_decimal (self ):
97
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
98
- Decimal ('60' ), Decimal ('55000' )),
99
- Decimal ('-710.2541257864217612489830917' ))
100
-
101
- # Two tests showing how Decimal is actually getting at a more exact result
102
- # .23 / 12 does not come out nicely as a float but does as a decimal
103
- def test_ppmt_special_rate (self ):
104
- assert_equal (numpy .round (npf .ppmt (0.23 / 12 , 1 , 60 , 10000000000 ), 8 ),
105
- - 90238044.232277036 )
106
-
107
- def test_ppmt_special_rate_decimal (self ):
108
- # When rounded out to 8 decimal places like the float based test,
109
- # this should not equal the same value as the float, substituted
110
- # for the decimal
111
- def raise_error_because_not_equal ():
112
- assert_equal (
113
- round (npf .ppmt (Decimal ('0.23' ) / Decimal ('12' ), 1 , 60 ,
114
- Decimal ('10000000000' )), 8 ),
115
- Decimal ('-90238044.232277036' ))
116
-
117
- assert_raises (AssertionError , raise_error_because_not_equal )
118
- assert_equal (npf .ppmt (Decimal ('0.23' ) / Decimal ('12' ), 1 , 60 ,
119
- Decimal ('10000000000' )),
120
- Decimal ('-90238044.2322778884413969909' ))
121
-
122
93
def test_npv (self ):
123
94
assert_almost_equal (
124
95
npf .npv (0.05 , [- 15000 , 1500 , 2500 , 3500 , 4500 , 6000 ]),
@@ -191,15 +162,6 @@ def test_when(self):
191
162
assert_equal (npf .pmt (0.08 / 12 , 5 * 12 , 15000. , 0 , 0 ),
192
163
npf .pmt (0.08 / 12 , 5 * 12 , 15000. , 0 , 'end' ))
193
164
194
- # begin
195
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 1 ),
196
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'begin' ))
197
- # end
198
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 ),
199
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'end' ))
200
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 0 ),
201
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'end' ))
202
-
203
165
# begin
204
166
assert_equal (npf .nper (0.075 , - 2000 , 0 , 100000. , 1 ),
205
167
npf .nper (0.075 , - 2000 , 0 , 100000. , 'begin' ))
@@ -243,86 +205,10 @@ def test_decimal_with_when(self):
243
205
npf .pv (Decimal ('0.07' ), Decimal ('20' ), Decimal ('12000' ),
244
206
Decimal ('0' ), 'end' ))
245
207
246
- # begin
247
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
248
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
249
- Decimal ('0' ), Decimal ('1' )),
250
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
251
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
252
- Decimal ('0' ), 'begin' ))
253
- # end
254
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
255
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
256
- Decimal ('0' )),
257
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
258
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
259
- Decimal ('0' ), 'end' ))
260
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
261
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
262
- Decimal ('0' ), Decimal ('0' )),
263
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
264
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
265
- Decimal ('0' ), 'end' ))
266
-
267
- # begin
268
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ),
269
- Decimal ('1' ), Decimal ('60' ), Decimal ('55000' ),
270
- Decimal ('0' ), Decimal ('1' )),
271
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
272
- Decimal ('60' ), Decimal ('55000' ),
273
- Decimal ('0' ), 'begin' ))
274
- # end
275
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
276
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' )),
277
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
278
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
279
- 'end' ))
280
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
281
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
282
- Decimal ('0' )),
283
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
284
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
285
- 'end' ))
286
-
287
208
def test_broadcast (self ):
288
209
assert_almost_equal (npf .nper (0.075 , - 2000 , 0 , 100000. , [0 , 1 ]),
289
210
[21.5449442 , 20.76156441 ], 4 )
290
211
291
- assert_almost_equal (npf .ppmt (0.1 / 12 , list (range (5 )), 24 , 2000 ),
292
- [numpy .nan , - 75.62318601 , - 76.25337923 ,
293
- - 76.88882405 , - 77.52956425 ], 4 )
294
-
295
- assert_almost_equal (npf .ppmt (0.1 / 12 , list (range (5 )), 24 , 2000 , 0 ,
296
- [0 , 0 , 1 , 'end' , 'begin' ]),
297
- [numpy .nan , - 75.62318601 , - 75.62318601 ,
298
- - 76.88882405 , - 76.88882405 ], 4 )
299
-
300
- def test_broadcast_decimal (self ):
301
- # Use almost equal because precision is tested in the explicit tests,
302
- # this test is to ensure broadcast with Decimal is not broken.
303
- assert_almost_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ),
304
- list (range (1 , 5 )), Decimal ('24' ),
305
- Decimal ('2000' )),
306
- [Decimal ('-75.62318601' ),
307
- Decimal ('-76.25337923' ), Decimal ('-76.88882405' ),
308
- Decimal ('-77.52956425' )], 4 )
309
-
310
- result = npf .ppmt (
311
- Decimal ('0.1' ) / Decimal ('12' ),
312
- list (range (1 , 5 )),
313
- Decimal ('24' ),
314
- Decimal ('2000' ),
315
- Decimal ('0' ),
316
- [Decimal ('0' ), Decimal ('1' ), 'end' , 'begin' ]
317
- )
318
- desired = [
319
- Decimal ('-75.62318601' ),
320
- Decimal ('-75.62318601' ),
321
- Decimal ('-76.88882405' ),
322
- Decimal ('-76.88882405' )
323
- ]
324
- assert_almost_equal (result , desired , decimal = 4 )
325
-
326
212
327
213
class TestNper :
328
214
def test_basic_values (self ):
@@ -348,6 +234,129 @@ def test_no_interest(self):
348
234
assert_ (npf .nper (0 , - 100 , 1000 ) == 10 )
349
235
350
236
237
+ class TestPpmt :
238
+ def test_float (self ):
239
+ assert_allclose (
240
+ npf .ppmt (0.1 / 12 , 1 , 60 , 55000 ),
241
+ - 710.25 ,
242
+ rtol = 1e-4
243
+ )
244
+
245
+ def test_decimal (self ):
246
+ result = npf .ppmt (
247
+ Decimal ('0.1' ) / Decimal ('12' ),
248
+ Decimal ('1' ),
249
+ Decimal ('60' ),
250
+ Decimal ('55000' )
251
+ )
252
+ assert_equal (
253
+ result ,
254
+ Decimal ('-710.2541257864217612489830917' ),
255
+ )
256
+
257
+ @pytest .mark .parametrize ('when' , [1 , 'begin' ])
258
+ def test_when_is_begin (self , when ):
259
+ assert_allclose (
260
+ npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , when ),
261
+ - 1158.929712 , # Computed using Google Sheet's PPMT
262
+ rtol = 1e-9 ,
263
+ )
264
+
265
+ @pytest .mark .parametrize ('when' , [None , 0 , 'end' ])
266
+ def test_when_is_end (self , when ):
267
+ args = (0.1 / 12 , 1 , 60 , 55000 , 0 )
268
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
269
+ assert_allclose (
270
+ result ,
271
+ - 710.254126 , # Computed using Google Sheet's PPMT
272
+ rtol = 1e-9 ,
273
+ )
274
+
275
+ @pytest .mark .parametrize ('when' , [Decimal ('1' ), 'begin' ])
276
+ def test_when_is_begin_decimal (self , when ):
277
+ result = npf .ppmt (
278
+ Decimal ('0.08' ) / Decimal ('12' ),
279
+ Decimal ('1' ),
280
+ Decimal ('60' ),
281
+ Decimal ('15000.' ),
282
+ Decimal ('0' ),
283
+ when
284
+ )
285
+ assert_almost_equal (
286
+ result ,
287
+ Decimal ('-302.131703' ), # Computed using Google Sheet's PPMT
288
+ decimal = 5 ,
289
+ )
290
+
291
+ @pytest .mark .parametrize ('when' , [None , Decimal ('0' ), 'end' ])
292
+ def test_when_is_end_decimal (self , when ):
293
+ args = (
294
+ Decimal ('0.08' ) / Decimal ('12' ),
295
+ Decimal ('1' ),
296
+ Decimal ('60' ),
297
+ Decimal ('15000.' ),
298
+ Decimal ('0' )
299
+ )
300
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
301
+ assert_almost_equal (
302
+ result ,
303
+ Decimal ('-204.145914' ), # Computed using Google Sheet's PPMT
304
+ decimal = 5 ,
305
+ )
306
+
307
+ @pytest .mark .parametrize ('args' , [
308
+ (0.1 / 12 , 0 , 60 , 15000 ),
309
+ (Decimal ('0.012' ), Decimal ('0' ), Decimal ('60' ), Decimal ('15000' ))
310
+ ])
311
+ def test_invalid_per (self , args ):
312
+ # Note that math.isnan() handles Decimal NaN correctly.
313
+ assert math .isnan (npf .ppmt (* args ))
314
+
315
+ @pytest .mark .parametrize ('when, desired' , [
316
+ (
317
+ None ,
318
+ [- 75.62318601 , - 76.25337923 , - 76.88882405 , - 77.52956425 ],
319
+ ), (
320
+ [0 , 1 , 'end' , 'begin' ],
321
+ [- 75.62318601 , - 75.62318601 , - 76.88882405 , - 76.88882405 ],
322
+ )
323
+ ])
324
+ def test_broadcast (self , when , desired ):
325
+ args = (0.1 / 12 , numpy .arange (1 , 5 ), 24 , 2000 , 0 )
326
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
327
+ assert_allclose (result , desired , rtol = 1e-5 )
328
+
329
+ @pytest .mark .parametrize ('when, desired' , [
330
+ (
331
+ None ,
332
+ [
333
+ Decimal ('-75.62318601' ),
334
+ Decimal ('-76.25337923' ),
335
+ Decimal ('-76.88882405' ),
336
+ Decimal ('-77.52956425' )
337
+ ],
338
+ ), (
339
+ [Decimal ('0' ), Decimal ('1' ), 'end' , 'begin' ],
340
+ [
341
+ Decimal ('-75.62318601' ),
342
+ Decimal ('-75.62318601' ),
343
+ Decimal ('-76.88882405' ),
344
+ Decimal ('-76.88882405' )
345
+ ]
346
+ )
347
+ ])
348
+ def test_broadcast_decimal (self , when , desired ):
349
+ args = (
350
+ Decimal ('0.1' ) / Decimal ('12' ),
351
+ numpy .arange (1 , 5 ),
352
+ Decimal ('24' ),
353
+ Decimal ('2000' ),
354
+ Decimal ('0' )
355
+ )
356
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
357
+ assert_almost_equal (result , desired , decimal = 8 )
358
+
359
+
351
360
class TestIpmt :
352
361
def test_float (self ):
353
362
assert_allclose (
@@ -372,7 +381,6 @@ def test_when_is_end(self, when):
372
381
result = npf .ipmt (0.1 / 12 , 1 , 24 , 2000 , 0 , when )
373
382
assert_allclose (result , - 16.666667 , rtol = 1e-6 )
374
383
375
-
376
384
@pytest .mark .parametrize ('when' , [Decimal ('1' ), 'begin' ])
377
385
def test_when_is_begin_decimal (self , when ):
378
386
result = npf .ipmt (
0 commit comments