module.exports = { slug: "amortization-schedule-row", title: "Amortization schedule row", deck_category: "finance", description: "Computes the interest, principal, and remaining balance for a single payment number of a fixed-payment amortizing loan.", inputs: [ { name: "principal", type: "number", unit: "currency units", required: true, description: "Original loan amount", min: 0 }, { name: "annual_rate_percent", type: "number", unit: "%", required: true, description: "Nominal annual interest rate, compounded monthly", min: 0 }, { name: "months", type: "integer", required: true, description: "Total number of monthly payments in the loan", min: 1 }, { name: "payment_number", type: "integer", required: true, description: "Which payment to report (1 = first payment)", min: 1 } ], outputs: [ { name: "interest_portion", unit: "currency units", description: "Interest paid in this payment" }, { name: "principal_portion", unit: "currency units", description: "Principal paid in this payment" }, { name: "remaining_balance", unit: "currency units", description: "Balance remaining after this payment" } ], steps: [ "Convert the annual rate to a decimal: r = annual_rate_percent / 100; monthly rate i = r / 12.", "Compute the fixed monthly payment using the standard annuity formula: payment = principal * i * (1+i)^months / ((1+i)^months - 1) (or principal/months if i = 0).", "Starting from balance = principal, iterate payment by payment: interest_this = balance * i; principal_this = payment - interest_this; balance = balance - principal_this.", "Stop at payment_number and report that payment's interest_portion, principal_portion, and the resulting remaining_balance.", "Round every reported amount to 2 decimals (money to cents); the final row's remaining_balance is clamped to 0 if within half a cent." ], constants: [], sources: [ { kind: "edition_page", value: "Brealey, Myers, Allen, Principles of Corporate Finance, 13th ed., Chapter 3, section 3-3 (Loan Amortization)", title: "Principles of Corporate Finance", publisher: "McGraw-Hill", retrieved_utc: "2026-09-30T19:31:29Z", note: "Standard amortization schedule construction from a fixed annuity payment" } ], disclaimer: null, questionText(inputs) { return `For a $${inputs.principal} loan at ${inputs.annual_rate_percent}% annual interest amortized over ${inputs.months} months, how much of payment number ${inputs.payment_number} is interest, how much is principal, and what is the remaining balance after it?`; }, run(inputs) { const { principal, annual_rate_percent, months, payment_number } = inputs; if (typeof principal !== "number" || principal < 0) throw new Error("principal must be a non-negative number"); if (typeof annual_rate_percent !== "number" || annual_rate_percent < 0) throw new Error("annual_rate_percent must be a non-negative number"); if (!Number.isInteger(months) || months <= 0) throw new Error("months must be a positive integer"); if (!Number.isInteger(payment_number) || payment_number < 1 || payment_number > months) throw new Error("payment_number must be an integer between 1 and months"); const r = annual_rate_percent / 100; const i = r / 12; let payment; if (i === 0) { payment = principal / months; } else { const factor = Math.pow(1 + i, months); payment = (principal * i * factor) / (factor - 1); } let balance = principal; let interest_portion = 0; let principal_portion = 0; for (let k = 1; k <= payment_number; k++) { interest_portion = balance * i; principal_portion = payment - interest_portion; balance = balance - principal_portion; } if (Math.abs(balance) < 0.005) balance = 0; interest_portion = Math.round(interest_portion * 100) / 100; principal_portion = Math.round(principal_portion * 100) / 100; const remaining_balance = Math.round(balance * 100) / 100; const fmt = (n) => n.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); return { answer: `Interest $${fmt(interest_portion)}, principal $${fmt(principal_portion)}, remaining balance $${fmt(remaining_balance)}`, values: { interest_portion, principal_portion, remaining_balance } }; }, examples: [ { name: "worked example", inputs: { principal: 200000, annual_rate_percent: 6, months: 360, payment_number: 1 }, expected: { answer: "Interest $1,000.00, principal $199.10, remaining balance $199,800.90" }, check: "hand computation: payment = 1199.10 (see loan-payment-amortized), first month interest = 200000*0.005 = 1000.00, principal = 1199.10-1000.00 = 199.10, balance = 200000-199.10 = 199800.90" }, { name: "test vector: last payment fully retires balance", inputs: { principal: 12000, annual_rate_percent: 0, months: 12, payment_number: 12 }, expected: { answer: "Interest $0.00, principal $1,000.00, remaining balance $0.00" }, check: "hand computation: zero interest loan, each payment is 1000.00 principal, after 12 payments balance is exactly 0" } ] };