Skip to main content

Cent-accurate mortgage amortization for Python, validated against 45 published regulatory, textbook, and lender examples

Project description

mortgagemath logo

mortgagemath

tests

coverage PyPI License: MIT PyPI Downloads Documentation

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_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN)
  • Two balance-tracking modesROUND_EACH (US lender statements) and CARRY_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
  • Flat per-period fees via fee_per_period, validated against French assurance emprunteur payment columns
  • Convenience constructors for common US fixed-rate, Canadian j_2, Actual/360 commercial, and fixed-payment loans
  • Exact zero ending balance — the final row trues up so the schedule lands at $0.00
  • 45 validated fixtures (including 15+ full-schedule cell-for-cell matches) 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 mortgagemath import (
    PaymentRounding, us_30_year_fixed,
    periodic_payment, amortization_schedule,
)

loan = us_30_year_fixed(
    "162000.00",
    "3.875",
    payment_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

The lower-level LoanParams dataclass remains available when you need every knob explicitly. For the common cases, constructors such as us_30_year_fixed, us_15_year_fixed, canada_fixed_j2, us_actual_360_commercial, and fixed_payment_mortgage return ordinary validated LoanParams objects.

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.

Pandas and Matplotlib Integration

Because mortgagemath returns pure Python dataclasses mapping directly to numerical values, it integrates seamlessly into the data science ecosystem.

You can easily convert an amortization schedule into a pandas.DataFrame to do vectorized analysis, date math, or plot the results with matplotlib.

Pandas Plot

import pandas as pd
import matplotlib.pyplot as plt
from mortgagemath import us_30_year_fixed, amortization_schedule

# 1. Create a schedule
loan = us_30_year_fixed("300000", "6.5")
schedule = amortization_schedule(loan)

# 2. Convert to DataFrame
df = pd.DataFrame(schedule)

# 3. Quick plot of Principal vs Interest over time
df_plot = df[df["number"] > 0]
fig, ax = plt.subplots(figsize=(8, 5))
ax.stackplot(
    df_plot["number"],
    df_plot["principal"].astype(float),
    df_plot["interest"].astype(float),
    labels=['Principal', 'Interest']
)
ax.set_title("Amortization Schedule")
ax.legend(loc='upper right')
plt.show()

See the Pandas and Data Visualization vignette for more examples, including date offsets and scenario analysis.

What's validated

45 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 45-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
Pandas & Viz How to use Pandas DataFrames and plot schedules with Matplotlib
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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mortgagemath-0.7.0.tar.gz (1.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mortgagemath-0.7.0-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

Details for the file mortgagemath-0.7.0.tar.gz.

File metadata

  • Download URL: mortgagemath-0.7.0.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for mortgagemath-0.7.0.tar.gz
Algorithm Hash digest
SHA256 a09cc32625d959ba28e1b944a07bb40c94a111c874e1e896bd6d076f8cea8614
MD5 fbcb2acaae3f458a0f3d8f74187be088
BLAKE2b-256 6ce50fd4096e6cc79d5cb23d3e5dda8fae1de750e5de65fc93f1add255d4f350

See more details on using hashes here.

File details

Details for the file mortgagemath-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: mortgagemath-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 29.3 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for mortgagemath-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97a1ac86d7ee293f123e3cc2744707bba6fde24df372efc956673ffe60680489
MD5 ed2b9d0ea0f95d8c32b6dfae231bbe23
BLAKE2b-256 bc111eec7fabd6977bd89aa46d65da18e7d0333dbaf1bb853517e8bccb4fe0db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page