BUG: npf.pmt() algorithm future value sign is flipped.
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 409
- Forks
- 98
- Avg merge
- 10h 43m
- Merged PRs (30d)
- 12
Description
Describe the issue:
When calculating the payment required to end with a remaining open balance, aka with a final_value, the calculated payments are larger than the payments required for a achieving final_value=0.
Workaround is inputting the final_value in a flipped state.
In the current state, if a positive pv means a outstanding loan, a negative fv means a remaining outstanding debt; whilst a positive fv implies having 'overpaid' the loan. This is confusing.
Either the algorithm is wrong, and the sign should be flipped; or the documentation should be updated to clarify that pv and fv signs have opposite meaning.
Reproduce the code example:
import numpy_financial as npf
interest_rate = 0.05 / 12
principal_loan = 200_000
compounding_periods = 360
payment_value_fv0 = npf.pmt(
interest_rate,
compounding_periods,
principal_loan,
0,
)
payment_value_fv50 = npf.pmt(
interest_rate,
compounding_periods,
principal_loan,
50_000,
)
payment_value_fvn50 = npf.pmt(
interest_rate,
compounding_periods,
principal_loan,
-50_000,
)
print("{:.2f}".format(payment_value_fv50))
print("{:.2f}".format(payment_value_fv0))
print("{:.2f}".format(payment_value_fvn50))
assert abs(payment_value_fv50) < abs(payment_value_fv0),\
"Payment with remaining balance should be lower than fully paying off loan, but found {:.2f} > {:.2f}".format(abs(payment_value_fv50),abs(payment_value_fv0))
Error message:
-1133.72
-1073.64
-1013.57
Traceback (most recent call last):
File "[...]/debugPmt.py", line 28, in <module>
assert abs(payment_value_fv50) < abs(payment_value_fv0),\
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Payment with remaining balance should be lower than fully paying off loan, but found 1133.72 > 1073.64
Runtime information:
2.1.1
3.12.6 (main, Sep 9 2024, 00:00:00) [GCC 14.2.1 20240801 (Red Hat 14.2.1-1)]
[{'numpy_version': '2.1.1',
'python': '3.12.6 (main, Sep 9 2024, 00:00:00) [GCC 14.2.1 20240801 (Red '
'Hat 14.2.1-1)]',
'uname': uname_result(system='Linux', node='[...]', release='6.10.9-200.fc40.x86_64', version='#1 SMP PREEMPT_DYNAMIC Sun Sep 8 17:23:55 UTC 2024', machine='x86_64')},
{'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
'found': ['SSSE3',
'SSE41',
'POPCNT',
'SSE42',
'AVX',
'F16C',
'FMA3',
'AVX2'],
'not_found': ['AVX512F',
'AVX512CD',
'AVX512_KNL',
'AVX512_KNM',
'AVX512_SKX',
'AVX512_CLX',
'AVX512_CNL',
'AVX512_ICL']}},
{'architecture': 'Haswell',
'filepath': '/home/[...]/.local/lib/python3.12/site-packages/numpy.libs/libscipy_openblas64_-ff651d7f.so',
'internal_api': 'openblas',
'num_threads': 8,
'prefix': 'libscipy_openblas',
'threading_layer': 'pthreads',
'user_api': 'blas',
'version': '0.3.27'}]
None
Context for the issue:
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The report names the npf.pmt() entry point but no source file or test. Start by reproducing the provided future-value cases, then inspect the implementation and project tests to determine whether the sign convention is wrong or needs documentation. Done means resolving that choice and validating the reported payment comparisons.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- numpy, python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100