A small Python function that builds the repayment schedule for a fixed-payment (annuity) loan. Written as a personal exercise in handling money correctly.
build_schedule(principal, monthly_rate, months) returns a list of rows, one per
month. Each row shows the payment, how much of it went to interest, how much went
to the principal, and the balance remaining afterwards.
The level payment comes from the standard annuity formula:
payment = P * i / (1 - (1 + i) ** -n)
The final month is handled separately: instead of charging the level payment, it
pays off whatever balance is left. Rounding each month to whole cents leaves a
small drift, and settling the remainder at the end keeps the last balance at
exactly 0.00 and makes the principal portions add back up to the original loan.
Money in binary floating point does not round the way people expect —
0.1 + 0.2 is not 0.3. Decimal stores the values exactly as written, and
quantize with ROUND_HALF_UP rounds to cents the way a bank statement does.
Over a 12-month schedule those fractions of a cent would otherwise accumulate.
from decimal import Decimal
from src.amortization import build_schedule
schedule = build_schedule(Decimal("100000"), Decimal("0.02"), 12)
for row in schedule:
print(row["month"], row["payment"], row["interest"], row["balance"])Rates are per month, as decimals: Decimal("0.02") is 2% monthly. Pass the
principal as a Decimal built from a string, not from a float.
The function also prints a True/False sanity check — whether the principal
portions sum back to the original loan amount.
Python 3 with the standard library. Nothing to install.