# asset-loan-amortization

Amortisation maths for fixed-rate, asset-backed instalment loans — the kind written
against an RV, a semi truck, a tractor, a parcel of land or a manufactured home.
Zero dependencies, CommonJS, Node 18+.

This is the calculation layer extracted from the loan calculators published at
[assetloancalculator.com](https://assetloancalculator.com/) — for example the
[RV loan calculator](https://assetloancalculator.com/rv-loan-calculator/) and the
[semi-truck loan calculator](https://assetloancalculator.com/semi-truck-loan-calculator/).

## Install

```sh
npm install asset-loan-amortization
```

## Use

```js
const { monthlyPayment, schedule, totalInterest, payoffSavings } =
  require('asset-loan-amortization');

monthlyPayment({ principal: 30000, annualRate: 0.0699, termMonths: 60 });
// 593.8944258963024

const s = schedule({ principal: 30000, annualRate: 0.0699, termMonths: 60 });
s.payment;        // 593.89
s.months;         // 60
s.totalInterest;  // total finance charge
s.periods[0];     // { period: 1, payment, interest, principal, balance }

payoffSavings({ principal: 30000, annualRate: 0.0699, termMonths: 60, extraPayment: 100 });
// { interestSaved, monthsSaved, baselineMonths, acceleratedMonths }
```

## API

### `monthlyPayment({ principal, annualRate, termMonths })`
Level payment for a fully amortising fixed-rate loan, unrounded.

    pmt = P * i / (1 - (1 + i)^-n),  i = annualRate / 12

`annualRate` is a nominal annual rate as a decimal (`0.0699` is 6.99%). A rate of
`0` degrades to `principal / termMonths`.

### `schedule({ principal, annualRate, termMonths, extraPayment })`
Period-by-period table. Returns `{ payment, periods, totalInterest, totalPaid, months }`.
Each row is `{ period, payment, interest, principal, balance }`, reported to the cent.

`extraPayment` (optional, default `0`) is recurring extra principal. The loan then
retires early and `months` is less than `termMonths`; the final period is trimmed so
the balance lands exactly on zero instead of going negative.

### `totalInterest(opts)`
Total finance charge over the life of the loan.

### `payoffSavings({ ..., extraPayment })`
Compares the accelerated schedule against the baseline and returns
`{ interestSaved, monthsSaved, baselineMonths, acceleratedMonths }`.

## Rounding

The running balance is carried at full precision; rounding to the cent happens only
when a row is reported. The reported principal column therefore sums back to the
principal to within the per-row rounding error — at most 0.005 per period, so about
0.30 on a 60-month note. Do not treat the rounded rows as a ledger.

## Scope and limits

Fixed-rate, monthly-compounded, level-payment loans only. Not modelled: variable
rates, Rule-of-78s rebates, balloon payments, irregular first periods, fees rolled
into APR, or day-count conventions other than a plain 1/12 monthly period.

## Test

```sh
npm test
```

Nine assertions covering the closed-form payment value, the zero-rate case,
principal-column reconciliation, first-period interest, extra-payment acceleration,
the no-negative-balance guarantee on the final period, and input validation.

## Licence

MIT
