diff --git a/NEWS.md b/NEWS.md index d27e7db8..273fa574 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,9 @@ # ichimoku 1.4.10.9000 (development) +* Allows using the environment variable 'OANDA_API_KEY' as an alternative to storing using the 'keyring' package. * Arguments 'keep.data' and 'keep.attrs' across the package now have an explicit default value of FALSE (no resultant change in behaviour). * Internal performance enhancements. -* Requires nanonext >= 0.11.0 to ensure optimal stability in interactions with the OANDA API. +* Requires nanonext >= 0.11.0. # ichimoku 1.4.10 diff --git a/R/oanda.R b/R/oanda.R index 6b1d1fb6..0405eb6d 100644 --- a/R/oanda.R +++ b/R/oanda.R @@ -46,8 +46,9 @@ #' this has been changed by \code{\link{oanda_switch}}. #' @param apikey (optional) string containing the OANDA fxTrade API key (personal #' access token), or function that returns this string. Does not need to be -#' specified if already stored by oanda_set_key(). Can also be entered -#' interactively if not specified. +#' specified if already stored as the environment variable +#' \code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +#' entered interactively if not specified. #' @param quietly (optional) if set to TRUE, will suppress printing of auxiliary #' output to the console and return quietly. #' @@ -199,8 +200,7 @@ getPrices <- function(instrument, granularity, count = NULL, from = NULL, `User-Agent` = .user_agent), response = "date") resp[["status"]] == 200L || - stop("status code ", resp[["status"]], " - ", - deserialize_json(resp[["data"]]), call. = FALSE) + stop("status code ", resp[["status"]], " - ", deserialize_json(resp[["data"]]), call. = FALSE) timestamp <- as.POSIXct.POSIXlt(strptime(resp[["headers"]][["date"]], format = "%a, %d %b %Y %H:%M:%S", tz = "UTC")) candles <- deserialize_json(resp[["data"]], query = "/candles") @@ -798,12 +798,9 @@ oanda_studio <- function(instrument = "USD_JPY", #' #' @export #' -oanda_instruments <- function(server, apikey) { - +oanda_instruments <- function(server, apikey) do_$getInstruments(server = server, apikey = apikey) -} - #' Set OANDA fxTrade API Key #' #' Save OANDA fxTrade API key (personal access token) to the system credential diff --git a/R/switch.R b/R/switch.R index 09dcabcb..79d17ab4 100644 --- a/R/switch.R +++ b/R/switch.R @@ -63,7 +63,8 @@ deserialize_json <- function(x, query = NULL) do_ <- function() { server_type <- "practice" - livestore <- keystore <- instruments <- account <- NULL + livestore <- keystore <- Sys.getenv("OANDA_API_KEY") + instruments <- account <- NULL list( getServer = function() server_type, @@ -83,7 +84,7 @@ do_ <- function() { if (missing(server)) server <- server_type switch(server, practice = { - if (is.null(keystore)) { + if (!nzchar(keystore)) { if (requireNamespace("keyring", quietly = TRUE)) { apikey <- tryCatch(keyring::key_get(service = "OANDA_API_KEY"), error = function(e) { message("No API key found for 'practice' account type\nPlease use oanda_set_key() to store your API key for automatic retrieval") @@ -97,7 +98,7 @@ do_ <- function() { invisible(keystore) }, live = { - if (is.null(livestore)) { + if (!nzchar(livestore)) { if (requireNamespace("keyring", quietly = TRUE)) { apikey <- tryCatch(keyring::key_get(service = "OANDA_LIVE_KEY"), error = function(e) { message("No API key found for 'live' account type\nPlease use oanda_set_key() to store your API key for automatic retrieval") @@ -122,8 +123,7 @@ do_ <- function() { headers = c("Authorization" = paste0("Bearer ", apikey), "User-Agent" = .user_agent)) resp[["status"]] == 200L || - stop("status code ", resp[["status"]], " - ", - deserialize_json(resp[["data"]]), call. = FALSE) + stop("status code ", resp[["status"]], " - ", deserialize_json(resp[["data"]]), call. = FALSE) parsed <- deserialize_json(resp[["data"]]) length(parsed[["accounts"]]) || stop(parsed, call. = FALSE) account <<- parsed[["accounts"]][[1L]][["id"]] @@ -141,8 +141,7 @@ do_ <- function() { headers = c("Authorization" = paste0("Bearer ", apikey), "User-Agent" = .user_agent)) resp[["status"]] == 200L || - stop("status code ", resp[["status"]], " - ", - deserialize_json(resp[["data"]]), call. = FALSE) + stop("status code ", resp[["status"]], " - ", deserialize_json(resp[["data"]]), call. = FALSE) parsed <- deserialize_json(resp[["data"]]) length(parsed[["instruments"]]) || { warning(parsed, diff --git a/man/oanda.Rd b/man/oanda.Rd index ba6f3508..40f0088d 100644 --- a/man/oanda.Rd +++ b/man/oanda.Rd @@ -50,8 +50,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} \item{quietly}{(optional) if set to TRUE, will suppress printing of auxiliary output to the console and return quietly.} diff --git a/man/oanda_chart.Rd b/man/oanda_chart.Rd index ed143527..fce96a45 100644 --- a/man/oanda_chart.Rd +++ b/man/oanda_chart.Rd @@ -58,8 +58,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} \item{...}{additional arguments passed along to \code{\link{ichimoku}} for calculating the ichimoku cloud or \code{\link{autoplot}} to set chart diff --git a/man/oanda_instruments.Rd b/man/oanda_instruments.Rd index 4344472f..1691078e 100644 --- a/man/oanda_instruments.Rd +++ b/man/oanda_instruments.Rd @@ -13,8 +13,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ A data.frame containing the instrument name, full display name, and type. diff --git a/man/oanda_orders.Rd b/man/oanda_orders.Rd index faf5e631..1ac69b97 100644 --- a/man/oanda_orders.Rd +++ b/man/oanda_orders.Rd @@ -22,8 +22,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ Invisibly, a data frame of the order book with parameters saved as diff --git a/man/oanda_positions.Rd b/man/oanda_positions.Rd index c7c0b2ef..45768a1e 100644 --- a/man/oanda_positions.Rd +++ b/man/oanda_positions.Rd @@ -22,8 +22,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ Invisibly, a data frame of the position book with parameters saved as diff --git a/man/oanda_quote.Rd b/man/oanda_quote.Rd index b5c93079..9c6b1acf 100644 --- a/man/oanda_quote.Rd +++ b/man/oanda_quote.Rd @@ -21,8 +21,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ Invisible NULL. The instrument, timestamp, daily open, high, low and diff --git a/man/oanda_stream.Rd b/man/oanda_stream.Rd index 74cbfff3..2a24be2a 100644 --- a/man/oanda_stream.Rd +++ b/man/oanda_stream.Rd @@ -25,8 +25,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ Returned invisibly, a dataframe containing the data for the streaming diff --git a/man/oanda_studio.Rd b/man/oanda_studio.Rd index e38c46d0..722e6039 100644 --- a/man/oanda_studio.Rd +++ b/man/oanda_studio.Rd @@ -53,8 +53,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} \item{new.process}{[default FALSE] if TRUE, will start the shiny session in a new R process, unblocking the current process and allowing continued use diff --git a/man/oanda_view.Rd b/man/oanda_view.Rd index 2f87d305..be4778c4 100644 --- a/man/oanda_view.Rd +++ b/man/oanda_view.Rd @@ -26,8 +26,9 @@ this has been changed by \code{\link{oanda_switch}}.} \item{apikey}{(optional) string containing the OANDA fxTrade API key (personal access token), or function that returns this string. Does not need to be -specified if already stored by oanda_set_key(). Can also be entered -interactively if not specified.} +specified if already stored as the environment variable +\code{OANDA_API_KEY} or by \code{\link{oanda_set_key}}. Can also be +entered interactively if not specified.} } \value{ A data.frame containing the daily open, high, low and last prices, diff --git a/vignettes/xoanda.Rmd b/vignettes/xoanda.Rmd index 53f1eda4..3a3b7d5b 100644 --- a/vignettes/xoanda.Rmd +++ b/vignettes/xoanda.Rmd @@ -44,6 +44,8 @@ Separate keys can be set for practice and live accounts; please choose the corre If an access token is revoked and re-generated, please remember to set the API key again through the `oanda_set_key()` function. +As an alternative, the package looks for an environment variable "OANDA_API_KEY". If present, this will be taken to be the OANDA API key, irrespective of type of account, and in precedence to keys stored using 'keyring'. + ## Using a Live Account If you are using an access token for a live (real money) account, you will want to call `oanda_switch()` at the beginning of each session; this switches the default server from the practice server to the live server. Settings will only persist until the end of the session. @@ -76,8 +78,8 @@ The arguments to the function are phrased identically to that of the API itself - `from` (optional) the start of the time range for which to fetch price data, for example "2020-02-01" - `to` (optional) the end of the time range for which to fetch price data, for example "2020-06-30" - `price` [default "M"] the pricing component, one of "M" (midpoint), "B" (bid) or "A" (ask) -- `server` (optional) Specify the "practice" or "live" server according to the account type held with OANDA. If not specified, will default to "practice", unless this has been changed by `oanda_switch()`. -- `apikey` (optional) string containing the OANDA fxTrade API key (personal access token). Does not need to be specified if already stored by `oanda_set_key()`. This argument is designed for specifying a function that returns such a string rather than the string itself, which could be potentially unsecure. This allows other packages that provide secure storage of secrets to be used if preferred over 'keyring' +- `server` (optional) Specify the "practice" or "live" server according to the account type held with OANDA. If not specified, will default to "practice", unless this has been changed by `oanda_switch()` +- `apikey` (optional) string containing the OANDA fxTrade API key (personal access token). Does not need to be specified if already stored as the environment variable 'OANDA_API_KEY' or by `oanda_set_key()`. This argument is designed for specifying a function that returns such a string rather than the string itself, which could be potentially unsecure. This allows other packages that provide secure storage of secrets to be used if preferred over 'keyring' - `quietly` if set to TRUE, will suppress printing of output to the console and return quietly Note: if both `from` and `to` are specified and the request would result in over 5000 periods being returned, the function prompts the user to confirm if multiple requests should be submitted. Unless the user response is "n" or "no", the data will proceed to be downloaded in batches and merged together into a single dataframe. The function is safe for use in non-interactive settings as in such cases the download will proceed automatically without prompting.