Interest rates are quoted per year, but money is lent for some number of days. To compound a rate we need the period in years, and the day count convention (the daycount) is the rule that turns a period between two dates into a fraction of a year.
The same annual rate, for the same two dates, gives different amounts
of interest with different daycounts. That is why every
SpotRate in fixedincome carries its
daycount.
A daycount has two parts, written as
"<days>/<days in base>":
The year fraction is the number of days divided by the days in base.
fixedincome supports these daycounts:
| Daycount | Days counted | Days in base | Used for |
|---|---|---|---|
actual/360 |
calendar days | 360 | money markets in USD and EUR |
actual/365 |
calendar days | 365 | GBP money markets, many bonds |
business/252 |
business days | 252 | Brazilian rates (DI, Selic, bonds) |
30E/360 |
30 days per month | 360 | Eurobonds |
Other bases also work with actual and
business, for example actual/366 or
business/250.
For actual/... and business/... the days
are counted with the calendar of the rate, using the bizdays package.
The "actual" calendar counts every day, and
"Brazil/ANBIMA" counts only business days in Brazil.
d1 <- as.Date("2024-01-31")
d2 <- as.Date("2024-07-31")
term(d1, d2, "actual")
#> [1] "182 days"
term(d1, d2, "Brazil/ANBIMA")
#> [1] "125 days"With 30E/360 every month has 30 days, and a date on the
31st is moved to the 30th, so from 2024-01-31 to 2024-07-31 there are
exactly 6 × 30 = 180 days. The calendar is not used.
Let’s compound a simple rate of 10% from d1 to
d2 with each daycount.
compound(spotrate(0.10, "simple", "actual/360", "actual"), d1, d2)
#> [1] 1.050556
compound(spotrate(0.10, "simple", "actual/365", "actual"), d1, d2)
#> [1] 1.049863
compound(spotrate(0.10, "simple", "business/252", "Brazil/ANBIMA"), d1, d2)
#> [1] 1.049603
compound(spotrate(0.10, "simple", "30E/360", "actual"), d1, d2)
#> [1] 1.05The year fractions are 182/360, 182/365, 125/252 and 180/360. So
actual/360 pays the most interest: it counts every day, but
its year has only 360 days. A rate of 10% is not the same rate under
different daycounts.
To compare rates with different daycounts, find the rate that gives
the same compounding factor for the same dates.
implied_rate() returns the rate for a compounding factor
and a year fraction.
Here a Brazilian rate of 10% (business/252) is converted
to an actual/365 rate for the same period.
sr <- spotrate(0.10, "discrete", "business/252", "Brazil/ANBIMA")
factor <- compound(sr, d1, d2)
factor
#> [1] 1.048412
years <- as.numeric(term(d1, d2, "actual")) / 365
rate <- implied_rate("discrete", years, factor)
sr365 <- spotrate(rate, "discrete", "actual/365", "actual")
sr365
#> [1] "0.0994538 discrete actual/365 actual"
compound(sr365, d1, d2)
#> [1] 1.048412Both rates give the same factor for these dates, but the equivalent rate depends on the dates: another period has another number of business days.
SpotRate objects are always annual, but many rates are
quoted for other periods: inflation per month, the DI rate per day,
coupons per semester. The period argument of
spotrate() takes the rate for one period and stores the
equivalent annual rate: the rate with the same compounding factor over
that period. The period is a Term, or a string like
"1 month", and the daycount of the rate turns it into a
fraction of a year.
inflation <- spotrate(0.0045, "discrete", "business/252", "Brazil/ANBIMA",
period = "1 month"
)
inflation
#> [1] "0.05535675 discrete business/252 Brazil/ANBIMA"
compound(inflation, term(1, "month"))
#> [1] 1.0045With business/252 one month is 21 business days, but
calendar months have 17 to 23 business days in Brazil. For a rate tied
to a specific month, use a Term created from two dates: the
rate is converted with the business days of that month, so compounding
between those dates gives back the monthly rate.
The real rate is the nominal rate discounted by inflation:
.
With discrete compounding this holds for any period, so it can be
computed directly with annual SpotRate objects that have
the same compounding, daycount and calendar.
nominal <- spotrate(0.1065, "discrete", "business/252", "Brazil/ANBIMA")
real <- (1 + nominal) / (1 + inflation) - 1
real
#> [1] "0.04846063 discrete business/252 Brazil/ANBIMA"The real rate for one month is the same with both ways of computing it.
A Term can be in days, months or years, and the daycount
says how many days there are in one year (or in one month, which is one
twelfth of a year). todays(), tomonths() and
toyears() convert Terms with a daycount.
todays(daycount("business/252"), term(1, "year"))
#> [1] "252 days"
todays(daycount("actual/365"), term(1, "year"))
#> [1] "365 days"
toyears(daycount("30E/360"), term(90, "days"))
#> [1] "0.25 year"with_daycount() evaluates operations between Terms with
different units.
with_daycount("business/252", term(1, "month") + term(12, "days"))
#> [1] "33 days"
with_daycount("actual/360", term(6, "months") == term(180, "days"))
#> [1] TRUEThe article Working with Terms has more about Terms.
The daycount and the calendar must agree. For
actual/... and business/... the days come from
the calendar, so an actual/360 rate with the
"Brazil/ANBIMA" calendar counts business days, and gives a
smaller factor than the actual/360 rate above.
Use the "actual" calendar with actual/...
daycounts, and a business calendar with business/....
Rates with different daycounts can’t be combined. Arithmetic and comparison between two SpotRates require the same compounding, daycount and calendar. Convert one of them first, as in “Equivalent rates”.
sr1 <- spotrate(0.10, "discrete", "business/252", "Brazil/ANBIMA")
sr2 <- spotrate(0.10, "discrete", "actual/365", "actual")
try(sr1 - sr2)
#> Error : SpotRate objects have different slots (compounding, daycount or calendar)Only 30E/360 is supported among the 30/360 variants.
The US (NASD) and ISDA versions treat the end of the month differently,
and daycount() rejects them.
try(daycount("30/360"))
#> Error in daycount("30/360") :
#> Unsupported daycount (30/360): only actual/..., business/... and 30E/360 are implementedDates of a curve use the calendar. The terms of a
SpotRateCurve are kept in days, and functions that turn
them into dates, like maturities(), use the calendar of the
curve, even with 30E/360.