Functional Weave
Code in Rust

dates.day-count-fraction@1.0.0

README.md

1,765 bytes · view raw

# dates.day-count-fraction

The fraction of a year between two dates under the day count convention a
loan, bond or swap names. It returns an exact fraction, numerator and
denominator in lowest terms, rather than a float: interest is then
principal x rate x numerator / denominator in integer arithmetic, with one
rounding at the end (math.round-div), and three languages cannot disagree in
the fifteenth decimal place.

The conventions are those of the 2006 ISDA Definitions, section 4.16:

- `act-365f` (Actual/365 (Fixed), 4.16(d)): actual days / 365, even in a leap
  year, so a whole leap year is 366/365.
- `act-360` (Actual/360, 4.16(e)): actual days / 360, the money-market basis.
- `30-360` (30/360, Bond Basis, 4.16(f)): each month counts as 30 days.
  D1 = 31 becomes 30; D2 = 31 becomes 30 only if D1 is (now) 30. Fraction is
  (360 x (Y2 - Y1) + 30 x (M2 - M1) + (D2 - D1)) / 360.
- `30e-360` (30E/360, Eurobond Basis, 4.16(g)): as above, but D2 = 31 always
  becomes 30.
- `act-act-isda` (Actual/Actual (ISDA), 4.16(b)): the days falling in a leap
  year / 366 plus the days falling in a non-leap year / 365. The start date
  counts, the end date does not.

What it does not do. There is no end-of-February rule in `30-360`: ISDA bond
basis has none, unlike the "30/360 US" (NASD / SIA) variant, where the last day
of February counts as the 30th; 28 February to 1 March is 3/360 here. It does
not implement ACT/ACT ICMA, which needs the coupon schedule as well as two
dates, or 30E/360 ISDA, which needs the maturity date. Business day adjustment
of the dates is the caller's job, before calling.

The start must not be after the end; the same date twice is 0/1. Actual days
come from the dates.add-days kernel, so leap years and centuries are exact.