tests/testthat/test-generalFunctions.R

# 1. Coupon.dates ---------------------------------------------------------

test_that("if format of maturity is not valid, an error has to emerge", {
  expect_error(coupon.dates(maturity = "ABC"), "is not valid")
})


test_that("if format of analysis.date is not valid as date an error has to emerge", {
  expect_error(coupon.dates(maturity = "2022-01-01",
                            analysis.date = "2022-01-45"), "is not valid as Date")
})

test_that("if TES, frequency of coupon dates is anual", {
  expect_length(coupon.dates(maturity = "2025-01-05",
                             analysis.date = "2023-01-03",
                             asset.type = "TES")$dates, 3)
})

test_that("if LIBOR, frequency of coupon dates is quarterly", {
  expect_length(coupon.dates(maturity = "2025-01-05",
                             analysis.date = "2023-01-03",
                             asset.type = "LIBOR")$dates, 9)
})

test_that("if LIBORSwaps, frequency of coupon dates is quarterly", {
  expect_length(coupon.dates(maturity = "2025-01-05",
                             analysis.date = "2023-01-03",
                             asset.type = "LIBORSwaps")$dates, 9)
})

test_that("if IBRSwaps, frequency of coupon dates is quarterly", {
  expect_length(coupon.dates(maturity = "2025-01-04",
                             analysis.date = "2023-01-03",
                             asset.type = "IBRSwaps")$dates, 9)
})

test_that("if asset requires the input of frequency, the frequency value is not assumed", {
  expect_length(coupon.dates(maturity = "2025-01-04",
                             analysis.date = "2023-01-03",
                             asset.type = "FixedIncome",
                             freq = 6)$dates, 13)
})

test_that("if maturity as date is given, function assumes coupon payments have already started", {
  expect_length(coupon.dates(maturity = "2025-01-04",
                             analysis.date = "2023-01-03",
                             asset.type = "FixedIncome",
                             freq = 1)$dates, 3)
})

test_that("if maturity as numeric is given, function assumes that trade-date is on analysis.date", {
  res <- as.Date(c("2024-01-05","2025-01-05"))
  expect_equal(coupon.dates(maturity = 2,
                            analysis.date = "2023-01-05",
                            asset.type = "FixedIncome",
                            freq = 1)$dates, res)
})

test_that("if maturity as numeric is given, but trade-date is specified,
          function doesn't assume trade-date is on analysis.date +2 if LIBOR", {
            res <- as.Date(c("2023-01-05","2024-01-05"))
            expect_equal(coupon.dates(maturity = 2,
                                      analysis.date = "2023-01-03",
                                      asset.type = "LIBORSwaps",
                                      freq = 1,
                                      trade.date = "2022-01-03")$dates, res)
          })



test_that("if maturity as numeric is given, but trade-date is specified,
          function doesn't assume trade-date is on analysis.date", {
            res <- as.Date(c("2024-01-03"))
            expect_equal(coupon.dates(maturity = 2,
                                      analysis.date = "2023-01-03",
                                      asset.type = "TES",
                                      freq = 1,
                                      trade.date = "2022-01-03")$dates, res)
          })


test_that("if following business days, then effective dates is one day later after dates,
          when dates lands on a holiday", {
            expect_equal(coupon.dates(maturity = "2023-01-01",
                                      analysis.date = "2022-01-01",
                                      asset.type = "FixedIncome",
                                      freq = 0,
                                      convention = "F")$effective.dates,
                         quantdates::AddBusinessDays(date = "2023-01-01",
                                                     numDate = 1))
          })

test_that("if backward business days, then effective dates is one day before dates,
          when dates lands on a holiday", {
            expect_equal(coupon.dates(maturity = "2023-01-01",
                                      analysis.date = "2022-01-01",
                                      asset.type = "FixedIncome",
                                      freq = 0,
                                      convention = "B")$effective.dates,
                         quantdates::AddBusinessDays(date = "2023-01-01",
                                                     numDate = -1))
          })

test_that("if modified following business days, then effective dates is one day before dates,
          when dates lands on a holiday and when next business days lands on a new month", {
            expect_equal(coupon.dates(maturity = "2023-12-31",
                                      analysis.date = "2022-01-01",
                                      asset.type = "FixedIncome",
                                      freq = 0,
                                      convention = "MF")$effective.dates,
                         quantdates::AddBusinessDays(date = "2023-12-31",
                                                     numDate = -1))
          })

test_that("if modified backward business days, then effective dates is one day after dates,
          when dates lands on a holiday and when previous business days lands on a new month", {
            expect_equal(coupon.dates(maturity = "2023-01-01",
                                      analysis.date = "2022-01-01",
                                      asset.type = "FixedIncome",
                                      freq = 0,
                                      convention = "MB")$effective.dates,
                         quantdates::AddBusinessDays(date = "2023-01-01",
                                                     numDate = 0))
          })

test_that("if 1st of Jan, then following business day has to produce the same outpout as
          modified backward", {
            expect_setequal(coupon.dates(maturity = "2023-01-01",
                                         analysis.date = "2010-01-01",
                                         asset.type = "FixedIncome",
                                         freq = 1,
                                         convention = "F")$effective.dates,
                            coupon.dates(maturity = "2023-01-01",
                                         analysis.date = "2010-01-01",
                                         asset.type = "FixedIncome",
                                         freq = 1,
                                         convention = "MB")$effective.dates)
          })



test_that("short first or long first is assumed if trade-date is not specified and maturity is a date", {
  expect_setequal(coupon.dates(maturity = "2026-05-29",
                               analysis.date = "2023-02-28",
                               asset.type = "FixedIncome",
                               freq = 1, coupon.schedule = "SL")$dates,
                  coupon.dates(maturity = "2026-05-29",
                               analysis.date = "2023-02-28",
                               asset.type = "FixedIncome",
                               freq = 1, coupon.schedule = "LL")$dates)
})

test_that("Short Last works", {
  res <- as.Date(c("2020-08-29","2021-02-28","2021-08-29","2022-02-28","2022-08-29","2023-02-28","2023-08-29","2024-02-29",
                   "2024-08-29","2025-02-28","2025-08-29","2026-02-28","2026-05-29"))
  expect_setequal(coupon.dates(maturity = "2026-05-29",
                               analysis.date = "2020-02-29",
                               asset.type = "FixedIncome",
                               freq = 2, coupon.schedule = "SL",
                               trade.date = "2020-02-29")$dates, res)
})

test_that("if frequency of coupons aligns with maturity and trade.date, then coupon.schedule
          is not taken into account", {
            expect_setequal(coupon.dates(maturity = "2026-02-28",
                                         analysis.date = "2020-02-29",
                                         asset.type = "FixedIncome",
                                         freq = 2, coupon.schedule = "LL",
                                         trade.date = "2020-02-29")$dates,
                            coupon.dates(maturity = "2026-02-28",
                                         analysis.date = "2020-02-29",
                                         asset.type = "FixedIncome",
                                         freq = 2, coupon.schedule = "SF",
                                         trade.date = "2020-02-29")$dates)
          })

test_that("if frequency of coupons aligns with maturity and trade.date, then coupon.schedule
          is not taken into account", {
            expect_setequal(coupon.dates(maturity = 2,
                                         analysis.date = "2020-02-29",
                                         asset.type = "FixedIncome",
                                         freq = 2, coupon.schedule = "LF",
                                         trade.date = "2020-02-29")$dates,
                            coupon.dates(maturity = 2,
                                         analysis.date = "2020-02-29",
                                         asset.type = "FixedIncome",
                                         freq = 2, coupon.schedule = "SL",
                                         trade.date = "2020-02-29")$dates)
          })

test_that("Long First works", {
  res <- as.Date(c("2020-06-29", "2020-09-29", "2020-12-29", "2021-03-29"))
  expect_setequal(coupon.dates(maturity = 1.08,
                               analysis.date = "2020-02-29",
                               asset.type = "FixedIncome",
                               freq = 4, coupon.schedule = "LF",
                               trade.date = "2020-02-29")$dates, res)
})

test_that("Short First works", {
  res <- as.Date(c("2020-09-30","2020-12-31", "2021-03-31", "2021-06-30", "2021-09-30", "2021-12-31",
                   "2022-03-31", "2022-06-30", "2022-09-30"))
  expect_setequal(coupon.dates(maturity = 2.16,
                               analysis.date = "2020-07-31",
                               asset.type = "FixedIncome",
                               freq = 4, coupon.schedule = "SF",
                               trade.date = "2020-07-31")$dates, res)
})



# 2. Coupons --------------------------------------------------------------

test_that("If dates input is given and in a wrong format, an error has to emerge", {
  expect_warning(coupons(dates = "ABC",
                         coupon.rate = 0.04), "formats failed to parse")
})

test_that("If coupon.rate is not a unique number or doesn't has the same length as coupon dates,
          a warning message has to emerge", {
            expect_error(coupons(coupon.rate = c(0.04, 0.05),
                                 maturity = "2026-01-05" ,
                                 asset.type = "LIBOR",
                                 freq = 4), "length of dates")
          })

test_that("If freq when divided by 12 has a remainder different from zero, then an error
          has to emerge", {
            expect_error(coupons(coupon.rate = 0.04,
                                 maturity = "2026-01-05" ,
                                 asset.type = "LIBOR",
                                 freq = 7), "frequency of payments")
          })

test_that("Output is equal when using a unique coupon.rate or the same coupon rate for each coupon date", {
  expect_equal(coupons(coupon.rate = c(0.04, 0.04,0.04,0.04,0.04),
                       maturity = "2024-01-05" ,
                       analysis.date = "2023-01-03",
                       asset.type = "IBR",
                       freq = 4),
               coupons(coupon.rate = 0.04,
                       maturity = "2024-01-05" ,
                       analysis.date = "2023-01-03",
                       asset.type = "IBR",
                       freq = 4))
})

test_that("Introducing the input of coupon dates also works fine", {
  dates <- coupon.dates(maturity = "2025-01-05", analysis.date = "2023-01-05")
  expect_length(coupons(coupon.rate = 0.04,
                        maturity = "2024-01-05" ,
                        analysis.date = "2023-01-03",
                        asset.type = "IBR",
                        freq = 4,
                        dates = dates$dates),2)
})

test_that("output is equal to Excel calculations", {
  expect_equal(coupons(maturity = "2025-01-05",
                       analysis.date = "2023-01-03",
                       asset.type = "IBR",
                       freq = 4,
                       coupon.rate = 0.04),c(0.01022222, 0.01000000, 0.01011111, 0.01022222, 0.01022222, 0.01011111,
                                             0.01011111,0.01022222,1.01022222))


})

test_that("Coupon calculation is fine when bond is long first, (trade.date is introduced)", {
  expect_equal(coupons(coupon.rate = 0.04,
                       maturity = 1.08 ,
                       analysis.date = "2020-02-29",
                       asset.type = "IBR",
                       freq = 4,
                       trade.date = "2020-02-29",
                       coupon.schedule = "LF"
                       ), c(0.01344444, 0.01022222, 0.01011111, 1.01000000),tolerance = 0.0001)
})

test_that("Coupon calculation is fine when bond is short last, (trade.date is introduced)", {
  expect_equal(coupons(coupon.rate = 0.04,
                       maturity = 1.08 ,
                       analysis.date = "2020-02-29",
                       asset.type = "IBR",
                       freq = 4,
                       trade.date = "2020-02-29",
                       coupon.schedule = "SL"
                       ), c(0.01000000, 0.01022222, 0.01022222, 0.01011111, 1.00322222))
})



# 3. Discount Factors --------------------------------------------------------

test_that("If length of dates is longer than length of rates and length(rates) !=1,
          then an error has to emerge", {
  dates <- coupon.dates(maturity = "2025-01-05", analysis.date = "2015-01-05")
  expect_error(discount.factors(rates = c(0.01,0.02),
                                analysis.date = "2023-01-03",
                                dates = dates$dates), "Missing rates for all coupon")
})

test_that("Output has to have the same length as dates", {
  dates <- coupon.dates(maturity = "2025-01-05")
  expect_length(discount.factors(rates = c(0.01,0.03),
                                 analysis.date = "2023-01-03",
                                 dates = dates$dates), length(dates$dates))
})


test_that("if rates are constant, discount factor has to be each time smaller", {
  dates <- coupon.dates(maturity = "2025-01-05",
                        analysis.date = "2021-01-01",
                        asset.type = "IBR")
  for (i in 2:(length(dates$dates)-1)) {

    expect_gt(discount.factors(rates = rep(0.01,length(dates$dates)),
                               analysis.date = "2021-01-01",
                               dates = dates$dates)[i],
              discount.factors(rates = rep(0.01,length(dates$dates)),
                               analysis.date = "2015-01-01",
                               dates = dates$dates)[i+1])
  }
})



test_that("Discount factors have to be lower when using continously compounded interest rates", {
  dates <- coupon.dates(maturity = "2025-01-05", analysis.date = "2023-01-05")
  for (i in 1:(length(dates$dates))) {
    expect_lte(discount.factors(rates = c(0.01,0.04),
                                analysis.date = "2023-01-03",
                                dates = dates$dates,
                                rate.type = 0)[i],
               discount.factors(rates = c(0.01,0.04),
                                analysis.date = "2023-01-03",
                                dates = dates$dates,
                                rate.type = 1)[i])
  }
})



test_that("outpout is equal to Excel calculations", {
  dates <-  coupon.dates(maturity = "2025-01-05",analysis.date = "2023-01-03", asset.type = "IBR", freq = 4)$effective.dates
  res <- c(0.9999455,0.9962543,0.9901207,0.9815680, 0.9707170,0.9577746,0.9427650,
           0.9254729,0.9065446)
  for (i in seq_along(dates)) {
    expect_equal(discount.factors(rates = c(0.01,0.015,0.02,0.025,0.03,0.035,0.04,0.045,0.05),
                                  analysis.date = "2023-01-03",
                                  rate.type = 1,
                                  dates = dates)[i], res[i],tolerance = 0.0001)
  }
})

# 4. Discount Time --------------------------------------------------------

test_that("if format of tinitial is not adequate, an error has to emerge", {
  expect_error(discount.time(tinitial = "ABC", tfinal = "2023-01-03"), "ABC is not valid as Date")
})

test_that("if format of tfinal is not adequate, an error has to emerge", {
  expect_error(discount.time(tinitial = "2023-01-01", tfinal = "Hoy"),"Hoy is not valid as Date")
})

test_that("A year has to be a year when intial date and final are the same date,
but with final having, and additional year", {
  expect_equal(discount.time(tinitial = "2023-01-01", tfinal = "2024-01-01"),1)
})

test_that("A year has to be a year, when intial date and final are the same date,
but with final having, and additional year", {
  expect_equal(discount.time(tinitial = "2021-06-13", tfinal = "2023-06-13"),2)
})

test_that("A year has to be a year, when intial date and final are the same date,
but with final having, and additional year", {
  expect_equal(discount.time(tinitial = "2021-12-31", tfinal = "2029-12-31"),8)
})

test_that("When initial date is 29-Feb, then a year is next year on the 28-Feb", {
  expect_equal(discount.time(tinitial = "2024-02-29", tfinal = "2025-02-28"),1)
})

test_that("When initial date is 29-Feb, then next year 27-Feb has to be,
          less than a year.", {
            expect_lt(discount.time(tinitial = "2024-02-29", tfinal = "2025-02-27"),1)
          })

test_that("When initial date is 29-Feb, then next year 27-Feb has to be,
          more than a year.", {
            expect_gt(discount.time(tinitial = "2024-02-29", tfinal = "2025-03-01"),1)
          })

test_that("When initial date is 29-Feb, then four years is next leap date", {
  expect_equal(discount.time(tinitial = "2024-02-29", tfinal = "2028-02-29"),4)
})

# 5. Accrued Interest -----------------------------------------------------

test_that("if analysis date is outside time gap between the previous and upcoming cupon date,
          return is 0.", {
            expect_equal(accrued.interests(analysis.date = "2025-01-03",
                                           coupon.rate = 0.04,
                                           maturity = "2024-01-03",
                                           daycount = "ACT/365",
                                           freq = 1),0)
          })

test_that("if accrued interest is calculated on a coupon date,
          then accrued interest is equal to 0.", {
            expect_equal(accrued.interests(analysis.date = "2023-01-04",
                                           coupon.rate = 0.04,
                                           maturity = "2024-01-04",
                                           daycount = "ACT/365"),0)
          })

test_that("if accrued interest is calculated on a coupon date (with different inputs),
          then accrued interest is equal to 0.", {
            expect_equal(accrued.interests(analysis.date = "2023-01-04",
                                           coupon.rate = 0.04,
                                           maturity = "2024-01-04",
                                           daycount = "ACT/360",
                                           freq = 4,
                                           asset.type = "IBR"),0)
          })

test_that("if analysis date is very close to next coupon date,
          then accrued interest has to be very close to coupon.", {
            expect_gt(accrued.interests(analysis.date = "2023-01-03",
                                        coupon.rate = 0.04,
                                        maturity = "2024-01-04",
                                        daycount = "ACT/365",
                                        freq = 1,
                                        asset.type = "TES"),0.039)
          })

test_that("if analysis date is very close to previous coupon date,
          then accrued interest has to be very close to zero.", {
            expect_lt(accrued.interests(analysis.date = "2023-01-05",
                                        coupon.rate = 0.04,
                                        maturity = "2024-01-04",
                                        daycount = "ACT/365",
                                        freq = 1,
                                        asset.type = "TES"),0.001)
          })

Try the QuantBondCurves package in your browser

Any scripts or data that you put into this service are public.

QuantBondCurves documentation built on April 4, 2025, 5:11 a.m.