Skip to content

Commit

Permalink
Simplify getSymbols.tiingo() implementation
Browse files Browse the repository at this point in the history
Remove the data.type parameter because getSymbols.tiingo() always
converts to an xts object. This user is not affected by which protocol
is used and handling the JSON response adds complexity. Use the CSV
interface because Tiingo said it's slightly more efficient and it
simplifies our implementation.

Fixes #343.
  • Loading branch information
ethanbsmith authored Oct 16, 2021
1 parent 4f5e6b7 commit f133a69
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ quantmod.Rproj
src/*.o
src/*.so
src/*.dll
*.Rproj
61 changes: 14 additions & 47 deletions R/getSymbols.R
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,6 @@ getSymbols.tiingo <- function(Symbols, env, api.key,
adjust=FALSE,
from='2007-01-01',
to=Sys.Date(),
data.type="json",
...) {

importDefaults("getSymbols.tiingo")
Expand Down Expand Up @@ -1510,62 +1509,30 @@ getSymbols.tiingo <- function(Symbols, env, api.key,
if (verbose) cat("loading", sym.name, ".....")
from.strftime <- strftime(from, format = "%Y-%m-%d")
to.strftime <- strftime(to, format = "%Y-%m-%d")

tiingo.names <- c("open", "high", "low", "close", "volume",
"adjOpen", "adjHigh", "adjLow", "adjClose",
"adjVolume", "divCash", "splitFactor")
qm.names <- paste(sym, c("Open", "High", "Low", "Close", "Volume",
"Open", "High", "Low", "Close", "Volume",
"DivCash", "SplitFactor"), sep=".")
if (isTRUE(adjust)) {
return.columns <- tiingo.names[6:10]
} else {
return.columns <- tiingo.names[1:5]
}

URL <- paste0("https://api.tiingo.com/tiingo/",
periodicity, "/",
sym.name, "/prices",
"?startDate=", from.strftime,
"&endDate=", to.strftime,
"&format=", data.type,
"&columns=", paste0(return.columns, collapse=","))
# If rate limit is hit, the csv API returns HTTP 200 (OK), while json API
# returns HTTP 429. The latter caused download.file() to error, but the
# contents of 'tmp' still contain the error message.
h <- curl::new_handle()
curl::handle_setheaders(h, Authorization = paste("Token", api.key))
response <- curl::curl_fetch_memory(URL, h)
response.data <- rawToChar(response$content)

if (data.type == "json") {
stock.data <- jsonlite::fromJSON(response.data)
if (verbose) cat("done.\n")
} else {
stock.data <- read.csv(text=response.data, as.is=TRUE)
}
"&format=csv",
"&token=", api.key)
#tiingo will return a text error for ticker not found, which read.csv converts
#to a zero row, 1 column data.frame, with a warning
stock.data <- suppressWarnings(read.csv(URL, as.is=TRUE))
# check for error
if (!all(return.columns %in% names(stock.data))) {
if (data.type == "json") {
msg <- stock.data$detail
} else {
msg <- readLines(response.data, warn=FALSE)
}
msg <- sub("Error: ", "", msg)
if (NCOL(stock.data) == 1) {
msg <- sub("Error: ", "", colnames(stock.data))
stop(msg, call. = FALSE)
}

tm.stamps <- as.POSIXct(stock.data[, "date"], ...)
stock.data[, "date"] <- NULL

# adjusted column names
adjcols <- grepl("^adj", colnames(stock.data))
# order Tiingo column names before converting to quantmod names
stock.data <- OHLCV(stock.data)
if (any(adjcols)) {
# put adjusted columns last
stock.data <- stock.data[, c(which(!adjcols), which(adjcols))]
if (adjust) {
stock.data <- stock.data[, c("adjOpen", "adjHigh", "adjLow", "adjClose", "adjVolume")]
} else {
stock.data <- stock.data[, c("open", "high", "low", "close", "volume")]
}
# now convert to quantmod column names
colnames(stock.data) <- qm.names[match(colnames(stock.data), tiingo.names)]
colnames(stock.data) <- paste(sym, c("Open", "High", "Low", "Close", "Volume"), sep=".")

# convert data to xts
xts.data <- xts(stock.data, tm.stamps, src="tiingo", updated=Sys.time())
Expand Down

0 comments on commit f133a69

Please sign in to comment.