Skip to main content

mortgagemath logo

mortgagemath

tests

coverage PyPI License: MIT PyPI Downloads Documentation

Cent-accurate mortgage amortization for Python. Every payment, interest charge, and balance is computed with Decimal arithmetic and validated against 46 published worked examples from government regulators, bank servicing guides, and academic textbooks across six countries. Zero runtime dependencies.

Why mortgagemath?

Most mortgage libraries get the monthly payment right but diverge from real lender statements by 1–4 cents per row. That drift compounds over the schedule, breaks reconciliation against actual bank statements, and makes audit work painful. mortgagemath is built around the rounding and accounting conventions that actual lenders use:

  • Decimal arithmetic end-to-end (no float drift)
  • Configurable rounding — ROUND_UP, ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN
  • Two balance-tracking modes — ROUND_EACH (US lender statements) and CARRY_PRECISION (Excel / CRE textbooks)
  • Both day-count conventions — 30/360 and Actual/360
  • International compounding — monthly (US), semi-annual (Canadian Interest Act j₂), and effective-annual
  • Flexible payment frequency — monthly, bi-weekly, weekly, quarterly, semi-monthly, or annual
  • Adjustable-rate mortgages with rate schedules, payment caps, and negative amortization
  • Interest-only periods with automatic recast
  • Flat per-period fees for French assurance emprunteur and similar insurance loadings
  • Currency unit precision — Decimal("0.01") for cents or Decimal("1") for yen/won
  • Exact zero ending balance — the final row trues up so the schedule lands at exactly zero
  • 46 validated fixtures from the US, Canada, France, Japan, Italy, and South Korea

Installation

pip install mortgagemath

Requires Python 3.11+. Zero runtime dependencies.

python -m mortgagemath   # self-check against reference values

Quick example

A standard 30-year fixed-rate mortgage from the command line:

mortgagemath summary --principal 300000 --rate 6.5 --term-months 360

Or generate the full payment-by-payment schedule:

mortgagemath schedule --principal 300000 --rate 6.5 --term-months 360

The same loan from Python:

from mortgagemath import us_30_year_fixed, periodic_payment, amortization_schedule

loan = us_30_year_fixed("300000", "6.5")

print(periodic_payment(loan))         # Decimal("1896.21")
sched = amortization_schedule(loan)
print(sched[1].interest)              # Decimal("1625.00")  — payment #1
print(sched[1].principal)             # Decimal("271.21")
print(sched[-1].balance)              # Decimal("0.00")     — exact zero
print(sched[-1].total_interest)       # Decimal("382628.90") — lifetime interest

The schedule is a plain list — sched[0] is the initial balance (no payment), sched[1] through sched[360] are the monthly payments.

For a quick summary without iterating the schedule:

from mortgagemath import us_30_year_fixed, loan_summary

s = loan_summary(us_30_year_fixed("300000", "6.5"))
print(s.periodic_payment)             # Decimal("1896.21")
print(s.total_interest)               # Decimal("382628.90")
print(s.total_paid)                   # Decimal("682628.90")
print(s.num_payments)                 # 360

Convenience constructors like us_30_year_fixed, us_15_year_fixed, canada_fixed_j2, canada_accelerated_biweekly, and us_actual_360_commercial handle common cases. The full LoanParams dataclass is available when you need every parameter explicitly:

from decimal import Decimal
from mortgagemath import LoanParams, PaymentRounding, amortization_schedule

loan = LoanParams(
    principal=Decimal("162000"),
    annual_rate=Decimal("3.875"),
    term_months=360,
    payment_rounding=PaymentRounding.ROUND_HALF_UP,
    interest_rounding=PaymentRounding.ROUND_HALF_UP,
)
sched = amortization_schedule(loan)
print(sched[1].payment)             # Decimal("761.78")

For Canadian j₂ mortgages, ARMs with rate and payment caps, commercial Actual/360 with balloon, interest-only periods, fee-loaded French schedules, and Japanese yen-precision loans, see the Worked examples vignette.

Pandas and Matplotlib integration

mortgagemath returns pure Python dataclasses, so converting to a pandas.DataFrame for analysis or plotting is one line:

Pandas Plot

import pandas as pd
from mortgagemath import us_30_year_fixed, amortization_schedule

loan = us_30_year_fixed("300000", "6.5")
df = pd.DataFrame(amortization_schedule(loan))

See the Pandas and Data Visualization vignette for plotting examples and scenario analysis.

What's validated

46 published amortization tables exercised by a test suite of more than 400 tests that runs on every push and release. Every committed fixture cell reproduces its source value to the cent (or yen). The sources span six countries and a wide range of loan structures:

  • US regulatory — CFPB sample disclosures, Reg Z Appendix H ARM with 15 years of historical rate adjustments, FHLBB 1935 direct-reduction plan
  • US commercial — Fannie Mae Multifamily Actual/360 with balloon, Geltner CRE carry-precision
  • US textbooks — OpenStax, Goldstein, Skinner (1913), Arcones SOA Exam FM, Las Positas, Mississippi State Extension
  • Canada — Olivier and eCampus Ontario semi-annual j₂ mortgages (monthly and quarterly), RBC accelerated bi-weekly
  • France — MoneyVox tableau d'amortissement with assurance emprunteur fee loading
  • Japan — JHF Flat 35 and LoanKeisan full 360-row schedule with yen-precision truncation rounding
  • Italy — Solution Bank and BCC Brescia regulatory transparency documents
  • South Korea — Tistory worked mortgage with won-precision
  • Reference works — TI BA II Plus official guidebook, Wikipedia mortgage calculator
  • Synthetic — half-cent rounding boundaries, zero-interest edge case

See the Validation vignette for the full 46-fixture parameter matrix and bibliography.

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
Pandas & Viz DataFrames, plotting, and scenario analysis
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 pytest needed.
  • Contributors — add a paired TOML + CSV fixture under tests/schedules/. See tests/schedules/README.md for the schema and contribution workflow.

For unrelated bugs or feature requests, use the Bug or feature request template.

License

MIT

Metadata

Release files for mortgagemath 0.7.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mortgagemath 0.7.1
File Size Uploaded Provenance
mortgagemath-0.7.1.tar.gz 4.0 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mortgagemath 0.7.1
File Interpreter ABI Platform
mortgagemath-0.7.1-py3-none-any.whl Python 3 none any Details

Total release size: 4.1 MB

Release files / mortgagemath-0.7.1.tar.gz

Download URL mortgagemath-0.7.1.tar.gz
Size 4.0 MB
Tags Source
SHA-256 checksum
How to use checksums
e5c242a124730c6b506779bccdd32e171c2053adc431d572a382cb8a263b46e3
BLAKE2b-256 checksum
How to use checksums
ef91ffa69cb94c15a1fe47b6bbcde6321ef419f7914ac375874bd036b90ca1a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","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}

Release files / mortgagemath-0.7.1-py3-none-any.whl

Download URL mortgagemath-0.7.1-py3-none-any.whl
Size 31.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4ebb520ae826168ab03e11eb934d57df0c3fa007f0d13ca207757dc82afe9c04
BLAKE2b-256 checksum
How to use checksums
c231009a2393188c41f3455e8e91d53d6323d4996081ef119e0901e7b74578c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","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}

Security for mortgagemath 0.7.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page