Skip to content

Commit

Permalink
Updated API calls and Tests
Browse files Browse the repository at this point in the history
All calls are now checked for errors, and functions are aborted with appropriate error codes and messages. The tests are updated accordingly, and doesnt require regular updates due to API range restrictions
  • Loading branch information
serkor1 committed Dec 9, 2023
1 parent 17dba25 commit 894c18a
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 40 deletions.
6 changes: 6 additions & 0 deletions R/api_binance.R
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ binanceTickers <- function(
path = endPoint
)


# 3) parse response
response <- jsonlite::fromJSON(
txt = httr::content(
Expand Down Expand Up @@ -330,6 +331,11 @@ binanceQuote <- function(
)
)

# 1.1) Check for error
check_for_errors(
response = response
)

# 2) parse response
response <- jsonlite::fromJSON(
txt = httr::content(
Expand Down
5 changes: 5 additions & 0 deletions R/api_bitmart.R
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ bitmartQuote <- function(
)
)

# 1.1) Check for error
check_for_errors(
response = response
)


# 2) parse response
response <- jsonlite::fromJSON(
Expand Down
6 changes: 6 additions & 0 deletions R/api_kraken.R
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ krakenQuote <- function(
)
)



} else {

response <- httr::GET(
Expand All @@ -414,6 +416,10 @@ krakenQuote <- function(

}

# 1.1) Check for error
check_for_errors(
response = response
)

# 2) parse response
response <- jsonlite::fromJSON(
Expand Down
9 changes: 9 additions & 0 deletions R/api_kucoin.R
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ kucoinQuote <- function(
)


# 1.1) Check for error
check_for_errors(
response = response
)


# # 2) parse response
response <- jsonlite::fromJSON(
txt = httr::content(
Expand Down Expand Up @@ -495,4 +501,7 @@ kucoinQuote <- function(
}





# script end;
95 changes: 95 additions & 0 deletions R/helper.R
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,99 @@ annotations <- function(


}



# check for http errors;
check_for_errors <- function(
response,
call = rlang::caller_env(n = 3)
) {

# 1) check for error;
#
# If an error code is thrown
# or the response includes
# an empty list.
#
# Not all failed API calls returns
# a propoer code.
error_condition <- httr::http_error(response)

# 1.1) convert content
# and check its content if
# the returns a list
check_content <- jsonlite::fromJSON(
txt = httr::content(
response,
encoding = 'UTF-8',
as = 'text'
)
)

if (inherits(check_content, 'list')) {

no_data_returned <- all(
sapply(
X = jsonlite::fromJSON(
txt = httr::content(
response,
encoding = 'UTF-8',
as = 'text'
)
),
FUN = function(x) {
(
inherits(x = x, what = 'character') | !length(x)
)


}
)
)

error_condition <- error_condition | no_data_returned

}

if (error_condition) {

# 2) abort remaining
# operations and paste
# the error message
error_message <- jsonlite::fromJSON(
txt = httr::content(
response,
encoding = 'UTF-8',
as = 'text'
)
)

# 2.1) check for empty
# content in the error messages
# this is relevant for REST APIs like
# KuCoin Futures.
idx <- sapply(error_message, function(x){!length(x)})
error_message[idx] <- 'No sensible error information.'

# 2.2) extract a the error
# message.
#
# NOTE: its not possible to
# use, say, ['msg'] as the container
# for each API varies. So this shotgun approach
# is somewhat sensible
rlang::abort(
message = paste(
error_message[[2]]
),
call = call
)


}

}


# script end;
143 changes: 103 additions & 40 deletions tests/testthat/test-getQuote.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,106 +2,169 @@
#
# The internal test data, is the last known validated
# data before any major overhauls to the functions.
# expect no errors; ####
#
# NOTE: kuCoin futures doesnt support
# calls that are more than a month old
# so these tests may fail because of this. So the tests has to
# updated once every month, or anytime the tests
# has to be run.
#
# TODO: the tests has to be revised so its more
# robust to API call limits.
# Why wouldn't you?
testthat::test_that(
desc = "getQuote returns a xts object from Binance futures, corresponding to the existing one.",
desc = "getQuote returning GET requests from Binance Spot market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

# 2) determine test parameter
testthat::expect_equal(
testthat::expect_no_error(
object = cryptoQuotes::getQuote(
ticker = 'ATOMUSDT',
source = 'binance',
futures = FALSE,
interval = '15m'
)
)
}
)

testthat::test_that(
desc = "getQuote returning GET requests from Binance Futures market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

testthat::expect_no_error(
object = cryptoQuotes::getQuote(
ticker = 'ATOMUSDT',
source = 'binance',
futures = TRUE,
interval = '15m',
from = '2023-11-25',
to = '2023-11-28'
),
expected = cryptoQuotes:::internalTest[[1]][[2]]
interval = '15m'
)
)

}
}
)


testthat::test_that(
desc = "getQuote returns a xts object from Kucoin futures, corresponding to the existing one.",
desc = "getQuote returning GET requests from KuCoin Futures market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

# 2) determine test parameter
testthat::expect_equal(
testthat::expect_no_error(
object = cryptoQuotes::getQuote(
ticker = 'ATOMUSDTM',
source = 'kucoin',
futures = TRUE,
interval = '15m',
from = '2023-11-25',
to = '2023-11-28'
),
expected = cryptoQuotes:::internalTest[[2]][[2]]
interval = '15m'
)
)

}
)




testthat::test_that(
desc = "getQuote returns a xts object from Binance spot, corresponding to the existing one.",
desc = "getQuote returning GET requests from KuCoin Spot market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

# 2) determine test parameter
testthat::expect_equal(
testthat::expect_no_error(
object = cryptoQuotes::getQuote(
ticker = 'ATOMUSDT',
ticker = 'ATOM-USDT',
source = 'kucoin',
futures = FALSE,
interval = '15m'
)
)

}
)

# expect errors; ####
# Test forced errors to check wether
# error messages are correctly displayed
testthat::test_that(
desc = "getQuote failing GET requests from Binance Spot market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

testthat::expect_error(
object = cryptoQuotes::getQuote(
ticker = 'FAKETICKER',
source = 'binance',
futures = FALSE,
interval = '15m',
from = '2023-11-25',
to = '2023-11-28'
),
expected = cryptoQuotes:::internalTest[[1]][[1]]
interval = '15m'
)
)
}
)

testthat::test_that(
desc = "getQuote failing GET requests from Binance Futures market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

testthat::expect_error(
object = cryptoQuotes::getQuote(
ticker = 'FAKETICKER',
source = 'binance',
futures = TRUE,
interval = '15m'
)
)

}
)


testthat::test_that(
desc = "getQuote returns a xts object from Kucoin spot, corresponding to the existing one.",
desc = "getQuote failing GET requests from KuCoin Futures market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

# 2) determine test parameter
testthat::expect_equal(
testthat::expect_error(
object = cryptoQuotes::getQuote(
ticker = 'ATOM-USDT',
ticker = 'FAKETICKER',
source = 'kucoin',
futures = TRUE,
interval = '15m'
)
)

}
)




testthat::test_that(
desc = "getQuote failing GET requests from KuCoin Spot market",
code = {

# 1) skip tests on github
testthat::skip_on_ci()

# 2) determine test parameter
testthat::expect_error(
object = cryptoQuotes::getQuote(
ticker = 'FAKETICKER',
source = 'kucoin',
futures = FALSE,
interval = '15m',
from = '2023-11-25',
to = '2023-11-28'
),
expected = cryptoQuotes:::internalTest[[2]][[1]]
interval = '15m'
)
)

}
Expand Down

0 comments on commit 894c18a

Please sign in to comment.