Every interest rate calculation needs a period of time: a rate is compounded for some time, and a curve has a rate at each maturity. In fixedincome this period of time is a Term object.

What is a Term

A Term is a number with a unit. The units can be "day", "month" or "year", and the plural forms are also accepted.

t <- term(6, "months")
t
#> [1] "6 months"

Term extends numeric, so it is a vector: it has a length, it can be indexed and it can be used as a column of a data.frame.

terms <- term(c(1, 21, 42, 63), "days")
length(terms)
#> [1] 4
terms[2:3]
#> [1] "21 days" "42 days"
data.frame(terms = terms, rate = c(0.1365, 0.1366, 0.1368, 0.1371))
#>     terms   rate
#> 1   1 day 0.1365
#> 2 21 days 0.1366
#> 3 42 days 0.1368
#> 4 63 days 0.1371

The units are kept in the units slot, and as.numeric() returns the value without the units.

t@units
#> [1] "month"
as.numeric(t)
#> [1] 6

When the units are not given, days are used.

term(10)
#> [1] "10 days"

Creating Terms

There are three ways to create a Term.

From a number and its units, with term(). Each element can have its own units.

term(1:3, "years")
#> [1] "1 year"  "2 years" "3 years"
term(c(10, 6), c("days", "months"))
#> [1] "10 days"  "6 months"

From text, with as.term().

as.term(c("6 months", "1 year", "21 days"))
#> [1] "6 months" "1 year"   "21 days"

From two dates and a calendar, with term(). This creates a DateRangeTerm, a Term in days that also keeps the two dates and the calendar used to count the days between them. The days are counted with the bizdays package, so with the "Brazil/ANBIMA" calendar only business days are counted.

d1 <- as.Date("2022-12-23")
d2 <- as.Date("2023-01-03")
term(d1, d2, "Brazil/ANBIMA")
#> [1] "7 days"
term(d1, d2, "actual")
#> [1] "11 days"

Converting units

How many days are there in one year? It depends on the market convention: 252 business days in Brazil, 360 or 365 actual days elsewhere. This convention is the daycount, so converting a Term from one unit to another needs a daycount. This is done with todays(), tomonths() and toyears().

one_year <- term(1, "year")
todays(daycount("business/252"), one_year)
#> [1] "252 days"
todays(daycount("actual/360"), one_year)
#> [1] "360 days"
todays(daycount("actual/365"), one_year)
#> [1] "365 days"
toyears(daycount("business/252"), term(126, "days"))
#> [1] "0.5 year"
tomonths(daycount("business/252"), term(63, "days"))
#> [1] "3 months"

A month is one twelfth of a year, so with business/252 one month has 21 days.

The article Day Count Conventions explains daycounts in detail.

Operations

Terms and numbers

Arithmetic with a number keeps the Term and its units, and comparison with a number returns a logical.

t <- term(c(10, 20), "days")
t * 2
#> [1] "20 days" "40 days"
t + 1
#> [1] "11 days" "21 days"
t > 15
#> [1] FALSE  TRUE

Terms and Terms

Arithmetic and comparison between two Terms work when both have the same units:

  • +, - and %% return a Term;
  • / and %/% return a number, because the units cancel out;
  • comparisons return a logical.
t1 <- term(42, "days")
t2 <- term(21, "days")
t1 - t2
#> [1] "21 days"
t1 / t2
#> [1] 2
t1 > t2
#> [1] TRUE

* and ^ between two Terms are not defined, because days times days has no meaning as a period of time.

try(t1 * t2)
#> Error in t1 * t2 : Operation * is not defined for two Terms

Terms with different units

Terms with different units can’t be combined directly. To add one month and twelve days, the month must first be converted into days, and that needs a daycount. So these operations raise an error.

try(term(1, "month") + term(12, "days"))
#> Error : Terms with different units: convert them first with todays(), tomonths() or toyears(), or use with_daycount()

Convert first, then operate.

todays(daycount("business/252"), term(1, "month")) + term(12, "days")
#> [1] "33 days"

Or evaluate the operations with a daycount, using with_daycount(). The Terms are converted to the smallest unit among them: years become months, and months become days.

with_daycount("business/252", term(1, "month") + term(12, "days"))
#> [1] "33 days"
with_daycount("business/252", term(1, "year") + term(6, "months"))
#> [1] "18 months"

The result depends on the daycount: one year is 252 days with business/252, but not with actual/360.

with_daycount("business/252", term(252, "days") == term(1, "year"))
#> [1] TRUE
with_daycount("actual/360", term(252, "days") == term(1, "year"))
#> [1] FALSE

Outside with_daycount() the daycount is not set, so these operations raise an error again.

Other functions

c() combines Terms, and each element keeps its own units.

c(term(1, "day"), term(5, "days"))
#> [1] "1 day"  "5 days"
c(term(10, "days"), term(6, "months"))
#> [1] "10 days"  "6 months"

diff() returns the Terms between consecutive elements, and shift() moves the elements, filling the gap with NA.

terms <- term(c(1, 21, 42, 63), "days")
diff(terms)
#> [1] "20 days" "21 days" "21 days"
shift(terms)
#> [1] "NA days" "1 day"   "21 days" "42 days"

Summary functions like sum() and cumsum() return plain numbers. Use term() to get a Term back.

term(cumsum(terms), "days")
#> [1] "1 day"    "22 days"  "64 days"  "127 days"

Terms with interest rates

A spot rate is compounded for a Term. The units of the Term are converted with the daycount of the rate, so six months and half a year give the same compounding factor.

sr <- spotrate(0.1375, "discrete", "business/252", "Brazil/ANBIMA")
compound(sr, term(6, "months"))
#> [1] 1.066536
compound(sr, term(0.5, "years"))
#> [1] 1.066536
compound(sr, term(126, "days"))
#> [1] 1.066536

The terms of a SpotRateCurve are kept in days. Indexing a curve with [[ accepts a Term in any units, and converts it to days with the daycount of the curve.

curve <- spotratecurve(
  c(0.1315, 0.1319, 0.1338, 0.1348, 0.1372, 0.1381),
  c(1, 21, 42, 63, 126, 252),
  "discrete", "business/252", "Brazil/ANBIMA",
  refdate = as.Date("2022-08-05")
)
curve[[term(1, "year")]]
#>          SpotRateCurve
#> 252 days        0.1381
#> discrete business/252 Brazil/ANBIMA 
#> Reference date: 2022-08-05
curve[[term(c(3, 6), "months")]]
#>          SpotRateCurve
#> 63 days         0.1348
#> 126 days        0.1372
#> discrete business/252 Brazil/ANBIMA 
#> Reference date: 2022-08-05

With an interpolation, the curve also returns rates between its terms.

interpolation(curve) <- interp_flatforward()
curve[[term(c(10, 100), "days")]]
#>          SpotRateCurve
#> 10 days         0.1319
#> 100 days        0.1366
#> discrete business/252 Brazil/ANBIMA 
#> Reference date: 2022-08-05

Forward rates between two Terms are computed with forwardrate().

forwardrate(curve, term(3, "months"), term(6, "months"))
#>         ForwardRate
#> 63 days   0.1396051
#> discrete business/252 Brazil/ANBIMA