R/srb.R

Defines functions srb_error_body srb parse_srb_calendar srb_calendar srb_cross_rates parse_srb_groups parse_srb_series parse_srb_data srb_series srb_data

Documented in srb_calendar srb_cross_rates srb_data srb_series

#' Fetch Sveriges Riksbank (SRb) data
#'
#' Retrieve time series data from the Sveriges Riksbank SWEA API.
#'
#' @param series (`character(1)`)\cr
#'   The series ID to query. See [srb_series()] for available series.
#' @param start_date (`NULL` | `Date(1)` | `character(1)`)\cr
#'   Start date of the data (e.g., `"2024-01-01"`). If `NULL`, all available data is returned.
#'   Default `NULL`.
#' @param end_date (`NULL` | `Date(1)` | `character(1)`)\cr
#'   End date of the data, in the same format as start_date. If `NULL`, data up to the latest
#'   available date is returned. Default `NULL`.
#' @returns A [data.table::data.table()] with the requested data.
#' @source <https://developer.api.riksbank.se/>
#' @family data
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' # fetch USD/SEK exchange rate
#' srb_data("SEKUSDPMI", start_date = "2024-01-01")
#'
#' # fetch EUR/SEK exchange rate
#' srb_data("SEKEURPMI", start_date = "2024-01-01")
#' }
srb_data = function(series, start_date = NULL, end_date = NULL) {
  assert_string(series, min.chars = 1L)
  start_date = assert_dateish(start_date, null.ok = TRUE)
  end_date = assert_dateish(end_date, null.ok = TRUE)

  start_date = start_date %||% as.Date("1900-01-01")
  if (is.null(end_date)) {
    end_date = as.Date(srb("Observations/Latest", series)$date)
  }

  json = srb("Observations", series, format(start_date), format(end_date))
  parse_srb_data(json, series)
}

#' Fetch Sveriges Riksbank (SRb) series metadata
#'
#' Retrieve available series or group metadata from the Sveriges Riksbank SWEA API.
#'
#' @param type (`character(1)`)\cr
#'   The type of metadata to query. One of `"series"` or `"groups"`. Default `"series"`.
#' @returns A [data.table::data.table()] with the requested metadata.
#' @source <https://developer.api.riksbank.se/>
#' @family metadata
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' srb_series()
#' }
srb_series = function(type = "series") {
  assert_choice(type, c("series", "groups"))
  if (type == "series") {
    parse_srb_series(srb("Series"))
  } else {
    parse_srb_groups(srb("Groups"))
  }
}

parse_srb_data = function(json, series) {
  if (length(json) == 0L) {
    dt = data.table(date = as.Date(character()), id = character(), value = numeric())
    setnames(dt, "id", "key")
    return(dt)
  }
  value = NULL
  dt = rbindlist(json)
  dt[, let(
    date = as.Date(date),
    key = toupper(series),
    value = as.numeric(value)
  )]
  setcolorder(dt, c("date", "key", "value"))
  dt[]
}

parse_srb_series = function(json) {
  dt = json |>
    map(\(x) setDT(map(x, \(v) v %||% NA_character_))) |>
    rbindlist() |>
    setnames(convert_camel_case)
  dt[]
}

parse_srb_groups = function(json) {
  if (!is.null(json$groupId)) {
    json = list(json)
  }

  flatten_groups = function(groups) {
    res = list()
    for (g in groups) {
      children = g$childGroups
      g$childGroups = NULL
      res = c(res, list(setDT(map(g, \(v) v %||% NA_character_))))
      if (length(children) > 0L) {
        res = c(res, flatten_groups(children))
      }
    }
    res
  }

  dt = json |>
    flatten_groups() |>
    rbindlist() |>
    setnames(convert_camel_case)
  dt[]
}

#' Fetch Sveriges Riksbank (SRb) cross rates
#'
#' Compute cross exchange rates between two currency series from the Sveriges Riksbank SWEA API.
#'
#' @param series1 (`character(1)`)\cr
#'   The first series ID (e.g., `"SEKUSDPMI"`).
#' @param series2 (`character(1)`)\cr
#'   The second series ID (e.g., `"SEKEURPMI"`).
#' @inheritParams srb_data
#' @returns A [data.table::data.table()] with the cross rate data.
#' @source <https://developer.api.riksbank.se/>
#' @family data
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' # USD/EUR cross rate
#' srb_cross_rates("SEKUSDPMI", "SEKEURPMI", start_date = "2024-01-01", end_date = "2024-01-31")
#' }
srb_cross_rates = function(series1, series2, start_date, end_date = NULL) {
  assert_string(series1, min.chars = 1L)
  assert_string(series2, min.chars = 1L)
  start_date = assert_dateish(start_date)
  end_date = assert_dateish(end_date, null.ok = TRUE)

  args = list("CrossRates", series1, series2, format(start_date))
  if (!is.null(end_date)) {
    args = c(args, format(end_date))
  }
  json = do.call(srb, args)
  series = paste(series1, series2, sep = "/")
  parse_srb_data(json, series)
}

#' Fetch Sveriges Riksbank (SRb) calendar days
#'
#' Retrieve Swedish banking calendar information from the Sveriges Riksbank SWEA API.
#'
#' @param start_date (`Date(1)` | `character(1)`)\cr
#'   Start date of the range (e.g., `"2024-01-01"`).
#' @param end_date (`NULL` | `Date(1)` | `character(1)`)\cr
#'   End date of the range. If `NULL`, data up to the latest available date is returned.
#'   Default `NULL`.
#' @returns A [data.table::data.table()] with the calendar day information.
#' @source <https://developer.api.riksbank.se/>
#' @family metadata
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' srb_calendar("2024-01-01", "2024-01-31")
#' }
srb_calendar = function(start_date, end_date = NULL) {
  start_date = assert_dateish(start_date)
  end_date = assert_dateish(end_date, null.ok = TRUE)

  args = list("CalendarDays", format(start_date))
  if (!is.null(end_date)) {
    args = c(args, format(end_date))
  }
  json = do.call(srb, args)
  parse_srb_calendar(json)
}

parse_srb_calendar = function(json) {
  if (length(json) == 0L) {
    return(data.table(
      calendar_date = as.Date(character()),
      swedish_bankday = logical(),
      week_year = integer(),
      week_number = integer(),
      quarter_number = integer(),
      ultimo = logical()
    ))
  }
  dt = setnames(rbindlist(json), convert_camel_case)
  calendar_date = NULL
  dt[, calendar_date := as.Date(calendar_date)]
  dt[]
}

srb = function(...) {
  resp = base_request("https://api.riksbank.se/swea/v1") |>
    req_url_path_append(...) |>
    req_error(body = srb_error_body) |>
    req_perform()
  if (!resp_has_body(resp)) {
    return(list())
  }
  resp_body_json(resp)
}

srb_error_body = function(resp) {
  resp_body_string(resp, "UTF-8")
}

Try the bbk package in your browser

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

bbk documentation built on Aug. 28, 2026, 5:07 p.m.