Skip to content

Commit

Permalink
Merge pull request #32 from matthiasgomolka/sfplus
Browse files Browse the repository at this point in the history
Clean support for SimFin+
  • Loading branch information
matthiasgomolka authored Sep 11, 2021
2 parents f77d9ea + f79a31f commit 7a5d6c9
Show file tree
Hide file tree
Showing 29 changed files with 1,145 additions and 705 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master

name: R-CMD-check

Expand Down Expand Up @@ -87,7 +85,8 @@ jobs:
- name: Check
env:
_R_CHECK_CRAN_INCOMING_: false
SIMFIN_API_KEY: ${{ secrets.SIMFIN_API_KEY }}
SFPLUS_API_KEY: ${{ secrets.SFPLUS_API_KEY }}
SF_API_KEY: ${{ secrets.SF_API_KEY }}
run: |
options(crayon.enabled = TRUE)
rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check")
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:

- name: Test coverage
env:
SIMFIN_API_KEY: ${{ secrets.SIMFIN_API_KEY }}
SFPLUS_API_KEY: ${{ secrets.SFPLUS_API_KEY }}
SF_API_KEY: ${{ secrets.SF_API_KEY }}
run: covr::codecov()
shell: Rscript {0}
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ Imports:
memoise (>= 1.1.0),
RcppSimdJson (>= 0.1.1),
utils,
progressr
progressr,
bit64
Suggests:
covr (>= 3.5.0),
testthat,
Expand All @@ -34,7 +35,7 @@ Suggests:
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
RoxygenNote: 7.1.2
VignetteBuilder: knitr
Config/testthat/edition: 3
Config/testthat/parallel: true
Expand Down
6 changes: 6 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ export(sfa_get_shares)
export(sfa_get_statement)
export(sfa_set_api_key)
export(sfa_set_cache_dir)
export(sfa_set_sfplus)
importFrom(RcppSimdJson,fparse)
importFrom(bit64,as.integer64)
importFrom(checkmate,assert_character)
importFrom(checkmate,assert_choice)
importFrom(checkmate,assert_date)
importFrom(checkmate,assert_directory)
importFrom(checkmate,assert_integerish)
importFrom(checkmate,assert_logical)
importFrom(checkmate,assert_string)
importFrom(data.table,CJ)
importFrom(data.table,as.data.table)
importFrom(data.table,fread)
importFrom(data.table,is.data.table)
importFrom(data.table,rbindlist)
importFrom(data.table,set)
importFrom(data.table,setattr)
Expand All @@ -26,6 +31,7 @@ importFrom(data.table,setnames)
importFrom(data.table,transpose)
importFrom(data.table,year)
importFrom(future.apply,future_lapply)
importFrom(future.apply,future_mapply)
importFrom(httr,GET)
importFrom(httr,content)
importFrom(memoise,cache_filesystem)
Expand Down
242 changes: 143 additions & 99 deletions R/check_inputs.R
Original file line number Diff line number Diff line change
@@ -1,111 +1,155 @@
#' Generic input checks
#' @description This function covers all kinds of (recurring) input checks in
#' {simfinapi}. This keeps the other functions cleaner.
#' @inheritParams sfa_get_statement
#' @inheritParams sfa_get_prices
#' @inheritParams sfa_get_shares
#' @inheritParams sfa_get_ref
#' @importFrom checkmate assert_string assert_directory assert_character
#' assert_integerish assert_choice assert_date
#' @importFrom data.table year
check_inputs <- function(
api_key = NULL, cache_dir = NULL, ticker = NULL, simfin_id = NULL,
statement = NULL, period = NULL, fyear = NULL, start = NULL, end = NULL,
ttm = NULL, shares = NULL, ratios = NULL, type = NULL, ref_data = NULL
) {
if (!is.null(api_key)) {
checkmate::assert_string(api_key, pattern = "^[[:alnum:]]{32}$")
}
if (!is.null(cache_dir)) {
checkmate::assert_directory(cache_dir, access = "rw")
}
if (!is.null(ticker)) {
checkmate::assert_character(
ticker,
pattern = "^[A-Za-z0-9_\\.\\-]+$",
any.missing = FALSE,
null.ok = TRUE
)
}
if (!is.null(simfin_id)) {
checkmate::assert_integerish(
simfin_id,
lower = 1L,
any.missing = FALSE,
null.ok = TRUE
)
}
if (!is.null(statement)) {
checkmate::assert_choice(
statement,
c("pl", "bs", "cf", "derived", "all"),
fmatch = TRUE
)
}
if (!is.null(period)) {
checkmate::assert_choice(
period,
c("q1", "q2", "q3", "q4", "fy", "h1", "h2", "9m", "6m", "quarters"),
fmatch = TRUE
)
}
if (!is.null(fyear)) {
checkmate::assert_integerish(
fyear,
lower = 1900L,
upper = data.table::year(Sys.Date())
)
msg_sfplus_required <- function(var, verb = "Omitting") {
stop(verb, " '", var, "' is reserved for SimFin+ users.", call. = FALSE)
}

#' @importFrom checkmate assert_string
check_api_key <- function(api_key) {
checkmate::assert_string(api_key, pattern = "^[[:alnum:]]{32}$")
}

#' @importFrom checkmate assert_directory
check_cache_dir <- function(cache_dir) {
checkmate::assert_directory(cache_dir, access = "rw")
}

#' @importFrom checkmate assert_logical
check_sfplus <- function(sfplus) {
checkmate::assert_logical(sfplus, any.missing = FALSE, len = 1L)
}

#' @importFrom checkmate assert_character
check_ticker <- function(ticker) {
checkmate::assert_character(
ticker,
pattern = "^[A-Za-z0-9_\\.\\-]+$",
any.missing = FALSE,
null.ok = TRUE
)
}

#' @importFrom checkmate assert_integerish
check_simfin_id <- function(simfin_id) {
checkmate::assert_integerish(
simfin_id,
lower = 1L,
any.missing = FALSE,
null.ok = TRUE
)
}

#' @importFrom checkmate assert_choice
check_statement <- function(statement, sfplus) {
checkmate::assert_choice(
statement,
c("pl", "bs", "cf", "derived", "all"),
fmatch = TRUE
)
if (statement == "all" & isFALSE(sfplus)) {
stop('statement = "all" is reserved for SimFin+ users.', call. = FALSE)
}
if (!is.null(start)) {
checkmate::assert_date(
start,
lower = as.Date("1900-01-01"),
upper = Sys.Date()
)
}

#' @importFrom checkmate assert_choice
check_period <- function(period, sfplus) {
if (is.null(period) & isFALSE(sfplus)) {
msg_sfplus_required("period")
}
if (!is.null(end)) {
checkmate::assert_date(
end,
lower = as.Date("1900-01-01"),
upper = Sys.Date()
)
checkmate::assert_choice(
period,
c("q1", "q2", "q3", "q4", "fy", "h1", "h2", "9m", "6m", "quarters"),
null.ok = TRUE,
fmatch = TRUE
)
if (period == "quarters" & isFALSE(sfplus)) {
stop('period = "quarters" is reserved for SimFin+ users.', call. = FALSE)
}
if (!is.null(ttm)) {
checkmate::assert_logical(ttm, any.missing = FALSE, len = 1L)
}

#' @importFrom checkmate assert_integerish
check_fyear <- function(fyear, sfplus) {
if (is.null(fyear) & isFALSE(sfplus)) {
msg_sfplus_required("fyear")
}
if (!is.null(shares)) {
checkmate::assert_logical(shares, any.missing = FALSE, len = 1L)
checkmate::assert_integerish(
fyear,
lower = 1900L,
upper = data.table::year(Sys.Date()),
null.ok = TRUE
)
}

#' @importFrom checkmate assert_date
check_start <- function(start, sfplus) {
if (!is.null(start) & isFALSE(sfplus)) {
msg_sfplus_required("start", "Specifying")
}
if (!is.null(ratios)) {
checkmate::assert_logical(ratios, any.missing = FALSE, len = 1L)
checkmate::assert_date(
start,
lower = as.Date("1900-01-01"),
upper = Sys.Date(),
null.ok = TRUE
)
}

#' @importFrom checkmate assert_date
check_end <- function(end, sfplus) {
if (!is.null(end) & isFALSE(sfplus)) {
msg_sfplus_required("end", "Specifying")
}
if (!is.null(type)) {
checkmate::assert_choice(
type,
choices = c("common", "wa-basic", "wa-diluted"),
fmatch = TRUE
checkmate::assert_date(
end,
lower = as.Date("1900-01-01"),
upper = Sys.Date(),
null.ok = TRUE
)
}

#' @importFrom checkmate assert_logical
check_ttm <- function(ttm) {
checkmate::assert_logical(ttm, any.missing = FALSE, len = 1L)
}

#' @importFrom checkmate assert_logical
check_shares <- function(shares, sfplus) {
checkmate::assert_logical(shares, any.missing = FALSE, len = 1L)

if (isTRUE(shares) & isFALSE(sfplus)) {
stop(
"'shares = TRUE' is reserved to SimFin+ users. As a normal user, please ",
"use 'sfa_get_shares()' with 'type = \"wa-basic\"' or 'type = ",
"\"wa-diluted\".",
call. = FALSE
)
}
if (!is.null(ref_data)) {
checkmate::assert_choice(
ref_data,
choices = c("industries", "markets"),
fmatch = TRUE
)
}

#' @importFrom checkmate assert_logical
check_ratios <- function(ratios, sfplus) {
if (!is.null(ratios) & isFALSE(sfplus)) {
msg_sfplus_required("ratios", "Specifying")
}
checkmate::assert_logical(
ratios,
any.missing = FALSE,
len = 1L,
null.ok = TRUE
)
}

#' @importFrom checkmate assert_choice
check_type <- function(type) {
checkmate::assert_choice(
type,
choices = c("common", "wa-basic", "wa-diluted"),
fmatch = TRUE
)
}

#' @param api_key See function using this argument.
#' @param cache_dir See function using this argument.
#' @param ticker See function using this argument.
#' @param simfin_id See function using this argument.
#' @param statement See function using this argument.
#' @param period See function using this argument.
#' @param fyear See function using this argument.
#' @param start See function using this argument.
#' @param end See function using this argument.
#' @param ttm See function using this argument.
#' @param shares See function using this argument.
#' @param ratios See function using this argument.
#' @param type See function using this argument.
#' @importFrom checkmate assert_choice
check_ref_data <- function(ref_data) {
checkmate::assert_choice(
ref_data,
choices = c("industries", "markets"),
fmatch = TRUE
)
}
25 changes: 22 additions & 3 deletions R/param_doc.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#' @param cache_dir [character] Your cache directory. It's recommended to set
#' the cache directory globally using [sfa_set_cache_dir].
#'
#' @param sfplus [logical] Set`TRUE` if you have a SimFin+ account. It's
#' recommended to set `sfplus` globally using [sfa_set_sfplus].
#'
#' @param ticker [integer] Ticker of the companies of interest.
#'
#' @param simfin_id [integer] 'SimFin' IDs of the companies of interest. Any
Expand Down Expand Up @@ -45,10 +48,26 @@
#'
#' @param fyear [integer] Filter for fiscal year. As a non-SimFin+ user, you
#' have to provide exactly one fiscal year. As SimFin+ user, this filter can
#' be omitted to retrieve data available for the company. You can also chain
#' this filter with a comma, to retrieve multiple years at once (e.g. `fyear =
#' "2015,2016,2017"` to retrieve the data for 3 years at once).
#' be omitted to retrieve all data available for the company.
#'
#' @param ratios [logical] With `TRUE`, you can display some price related
#' ratios along with the share price data (reserved for SimFin+ users). The
#' ratios that will be displayed are:
#'
#' - Market-Cap
#' - Price to Earnings Ratio (quarterly)
#' - Price to Earnings Ratio (ttm)
#' - Price to Sales Ratio (quarterly)
#' - Price to Sales Ratio (ttm)
#' - Price to Book Value (ttm)
#' - Price to Free Cash Flow (quarterly)
#' - Price to Free Cash Flow (ttm)
#' - Enterprise Value (ttm)
#' - EV/EBITDA (ttm)
#' - EV/Sales (ttm)
#' - EV/FCF (ttm)
#' - Book to Market Value (ttm)
#' - Operating Income/EV (ttm).
#'
#' @section Parallel processing:
#' This function supports parallel processing via `future.apply`. If your
Expand Down
3 changes: 2 additions & 1 deletion R/sfa_get_entities.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ sfa_get_entities <- function(
api_key = getOption("sfa_api_key"),
cache_dir = getOption("sfa_cache_dir")
) {
check_inputs(api_key = api_key, cache_dir = cache_dir)
check_api_key(api_key)
check_cache_dir(cache_dir)

response_light <- call_api(
path = list("api/v2/companies/list/"),
Expand Down
Loading

0 comments on commit 7a5d6c9

Please sign in to comment.