Cent-accurate mortgage amortization for Python, validated against published CFPB and Fannie Mae examples
Project description
mortgagemath
Cent-accurate mortgage amortization for Python. Validated against CFPB regulatory disclosures, Fannie Mae GSE servicing guides, the Reg Z Sample H-14 ARM, the FHLBB Federal Home Loan Bank Review of March 1935, and 30+ open-licensed and modern copyrighted textbook worked examples — every committed fixture cell reproduces its source value to the cent. Decimal end-to-end; no runtime dependencies beyond the Python standard library.
Why mortgagemath?
Most mortgage libraries get the closed-form payment right but
diverge from real lender statements by 1–4 cents per row. The
discrepancy compounds over the schedule, breaks reconciliation
against an actual bank statement, and makes audit work painful.
mortgagemath is built around the rounding and accounting
conventions actual lenders use:
- Decimal arithmetic end-to-end (no float drift)
- Configurable rounding for the periodic payment and per-row
interest (
ROUND_UP,ROUND_HALF_UP,ROUND_HALF_EVEN) - Two balance-tracking modes —
ROUND_EACH(US lender statements) andCARRY_PRECISION(Excel / graduate CRE textbooks) - Both day-count conventions — 30/360 (residential) and Actual/360 (commercial)
- Non-monthly compounding and cadence — Canadian Interest
Act §6 (
j_2), effective-annual, weekly through annual - Adjustable-rate mortgages with rate schedules, optional payment caps, and capitalized negative amortization
- Exact zero ending balance — the final row trues up so the schedule lands at $0.00
- 36 cell-for-cell validated fixtures auto-discovered by
pytest
Installation
pip install mortgagemath
Requires Python 3.11+. Zero runtime dependencies.
To verify a fresh install reproduces the same reference values the test suite validates:
python -m mortgagemath
This recomputes a CFPB sample Closing Disclosure, the Goldstein §10.3 Example 1 carry-precision schedule, and the Fannie Mae §1103 Tier 2 SARM monthly payment plus balloon-at-term. Exits 0 if every value matches the published source exactly.
Quick example
The CFPB's Closing Disclosure Sample H-25(B) — $162,000 at 3.875% for 30 years — from the command line:
mortgagemath schedule --principal 162000 --rate 3.875 --term-months 360 \
--payment-rounding ROUND_HALF_UP --interest-rounding ROUND_HALF_UP \
--format csv
The same loan from Python:
from decimal import Decimal
from mortgagemath import (
LoanParams, PaymentRounding,
periodic_payment, amortization_schedule,
)
loan = LoanParams(
principal=Decimal("162000.00"),
annual_rate=Decimal("3.875"),
term_months=360,
payment_rounding=PaymentRounding.ROUND_HALF_UP,
interest_rounding=PaymentRounding.ROUND_HALF_UP,
)
print(periodic_payment(loan)) # Decimal("761.78")
sched = amortization_schedule(loan)
print(sched[1].interest) # Decimal("523.13")
print(sched[1].principal) # Decimal("238.65")
print(sched[-1].balance) # Decimal("0.00") exact closure
For Canadian j_2 mortgages, US ARMs (with rate caps and payment caps), commercial Actual/360 with balloon, and the FHLBB 1935 given-payment convention, see the Worked examples vignette.
What's validated
36 fully published amortization tables from government regulatory documents, GSE servicing guides, and academic textbooks, exercised by a test suite of more than 300 tests that runs on every push and every release. Every committed fixture cell reproduces its source value to the cent; on the small number of historical sources that themselves contain an internal arithmetic typo (e.g., two rows of the Geltner CRE example), the divergent rows are documented rather than forced into the corpus. The sources span:
- Regulatory disclosures — CFPB Sample H-25(B); 12 CFR Part 1026 Appendix H Sample H-14 (the 1982–1996 1/1 ARM with periodic and lifetime caps, traced through the actual CMT history)
- GSE servicing guides — Fannie Mae Multifamily §1103 Tier 2 SARM ($25 M / 5.5% / 10-year term on 30-year amortization, Actual/360)
- Federal authorities — FHLBB Federal Home Loan Bank Review, March 1935 — Direct-Reduction Plan A
- Textbooks — OpenStax Contemporary Mathematics, Geltner et al. CRE Analysis, Skinner Mathematical Theory of Investment (1913), Arcones SOA Exam FM Manual, Goldstein Finite Mathematics, eCampus Ontario Mathematics of Finance, Olivier Business Math, Las Positas Math for Liberal Arts, Mississippi State Extension Service
- Synthetic boundary cases for half-cent rounding modes
See the Validation
vignette for the full
36-fixture × 8-parameter matrix and bibliography, generated
directly from the fixture [source] blocks.
Documentation
| Resource | Audience |
|---|---|
| Read the Docs | Installation, quickstart, full API reference, changelog |
| At a glance | 60-second orientation |
| Validation | Audit / risk review — full fixture matrix + bibliography |
| Worked examples | Picking the right configuration by country and loan type |
| History | Academic context — institutional and mathematical history of the level-payment mortgage |
| HTML site | Vignettes with navigation and search |
Reporting a discrepancy
Found a published example or a real lender statement that
mortgagemath doesn't reproduce to the cent? Two paths:
- Reporters / users — open an issue using the Mortgage
example doesn't match
template. Paste the published values; no
pytestneeded. - Contributors — add a paired TOML + CSV fixture under
tests/schedules/. Seetests/schedules/README.mdfor the schema and contribution workflow.
For unrelated bugs or feature requests, use the Bug or feature request template.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mortgagemath-0.6.1.tar.gz.
File metadata
- Download URL: mortgagemath-0.6.1.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd097f2f7787346d1877180fbaaaf9322786e1f675163c0a9d12eada909967c1
|
|
| MD5 |
c9c40fc9d160d7dcda951b0eaaae2125
|
|
| BLAKE2b-256 |
6e473ce0a1f2f7725c7408af54c96c8d03bb48464951ab29b8dfff22b3b589b7
|
File details
Details for the file mortgagemath-0.6.1-py3-none-any.whl.
File metadata
- Download URL: mortgagemath-0.6.1-py3-none-any.whl
- Upload date:
- Size: 24.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
945850856492c9e2bc928c198ed15bfc0ef6f66a099b2a1f6acdda6ceea0e553
|
|
| MD5 |
78f222abfe56bee4cf694b79175c3058
|
|
| BLAKE2b-256 |
90cb5207bbeff846c331df183af520369fb2c39fed807256ac2507cd94b7fab8
|