Functional Weave
Code in Python

lending.daily-interest@1.0.1

README.md

3,520 bytes · view raw

# lending.daily-interest

Interest on an account whose balance changes during the period: a savings
account with deposits, a loan with a payment mid-month, an overdraft that goes
in and out. Each balance accrues balance × rate × (the year fraction for the
days it was held), under the day-count convention the contract names, and the
pieces are added up.

## How it is computed

- `balances` is the balance history: each entry holds from its date until
  the next entry's date. The first entry must start on or before `fromIso`
  (the opening balance); entries after `toIso` are ignored.
- The period is `fromIso` included to `toIso` excluded, the usual accrual
  convention: 1 January to 31 January is 30 days of interest.
- Each piece's year fraction comes from dates.day-count-fraction (ACT/365F,
  ACT/360, 30/360, 30E/360, ACT/ACT ISDA), as an exact fraction.
- The pieces are summed exactly with math.rational, and the total is rounded
  once, with the mode you pass. `exact` is that unrounded total in minor
  units, for audit and for carrying fractions of a penny into the next period
  if your ledger does that.

Rounding once is the point. Rounding each day (or each balance change) and
adding the rounded amounts drifts: three days at 0.23p each would post 0p
where the true total is 0.68p, and more balance changes would mean more
drift. Some ledgers do post whole pence daily; if yours does, call this once
per day instead.

## Signs

A negative balance (overdrawn, or a loan held as a debt) accrues negative
interest, and a negative rate charges a positive balance. The rounding modes
are those of math.round-div, symmetric about zero: `down` is towards zero,
`up` away from it.

## Splitting and 30/360

Under ACT/365F, ACT/360 and ACT/ACT the pieces add up to the whole period
exactly. Under 30/360 each piece is measured on its own, as a contract that
names 30/360 per balance period would, so a piece ending on the 31st can
differ by a day from measuring the whole month at once.

## Limits

The exact running total must fit math.rational (numerator and denominator
within 2^53 - 1); that holds for balances into the hundreds of millions of
pounds at ordinary rates, and a larger one is an error ("rational overflow"),
never a wrong answer. The rate is -100000 to 100000 basis points, and the rate
is fixed for the period: for a rate change, call once per rate and add.

## Before you rely on this

**Not professional advice.** This capability calculates lending figures from published rules. It is a software component for developers, not financial advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed above, and have a consumer-credit compliance specialist review how you use it, before anyone relies on the output. Provided "as is" under its licence, without warranty.

**Unreviewed.** This capability's implementations agree in every language and pass its published test vectors, which were worked out from the official sources cited. But no qualified consumer-credit compliance specialist has yet checked those vectors, or confirmed that the capability covers the cases it claims. Treat it as a draft. Do not use it for real people, money or decisions without your own expert review. Once a qualified reviewer signs off, this notice is replaced with their name, qualification and the date. Each new version needs fresh sign-off.

1.0.1 marks it unreviewed. The code and the tests are unchanged.