/** * Core financial functions replicating Excel's PMT, IPMT, PPMT. * All functions return positive values (Excel returns negative for payments). */ /** * PMT — Fixed periodic payment for a loan. * Equivalent to Excel: -PMT(rate, nper, pv) */ export function pmt(rate: number, nper: number, pv: number): number { if (pv <= 0 || nper <= 0) return 0; if (rate === 0) return pv / nper; const factor = Math.pow(1 + rate, nper); return (pv * rate * factor) / (factor - 1); } /** * IPMT — Interest portion of a specific payment period. * Equivalent to Excel: -IPMT(rate, per, nper, pv) * @param per 1-based period number */ export function ipmt(rate: number, per: number, nper: number, pv: number): number { if (rate === 0 || pv <= 0 || nper <= 0) return 0; const bal = remainingBalance(rate, per - 1, nper, pv); return bal * rate; } /** * PPMT — Principal portion of a specific payment period. * Equivalent to Excel: -PPMT(rate, per, nper, pv) * @param per 1-based period number */ export function ppmt(rate: number, per: number, nper: number, pv: number): number { if (pv <= 0 || nper <= 0) return 0; return pmt(rate, nper, pv) - ipmt(rate, per, nper, pv); } /** * Remaining balance after `per` payments. * @param per Number of payments already made (0 = initial balance) */ export function remainingBalance(rate: number, per: number, nper: number, pv: number): number { if (pv <= 0 || nper <= 0) return 0; if (per <= 0) return pv; if (per >= nper) return 0; if (rate === 0) { return pv - pmt(rate, nper, pv) * per; } const payment = pmt(rate, nper, pv); const factor = Math.pow(1 + rate, per); return pv * factor - payment * (factor - 1) / rate; }