Thanks to a solution found here, users can input a ticker/symbol which is then checked for availability both locally and on the Internet. If the former is yes and/or the latter is no, then ask again for user input, else download from the Internet:
# load packages
library(svDialogs)
library(quantmod)
# start a loop; we'll find out if we need to exit based on user feedback
while (TRUE) {
# get a potential ticker value from the user
ticker <- toupper(dlgInput("Please enter a ticker that has not yet been loaded:")$res)
# if this value already exists in global environment, immediately go back to
# the beginning of the loop
if (exists(ticker)) next
# check Yahoo to see if the ticker is valid and if so get the results
yahooSymbol <- getSymbols.yahoo(ticker, env = globalenv())
# if yahoo returned a response, exit the loop
if (!identical(yahooSymbol, character(0))) break
}
But, when the user inputs more than one ticker/symbol, the code fails. In spite of this, when the code is run outside a while
statement, it is able to handle multiple tickers/symbols (part of the solution found here):
# load packages
library(svDialogs)
library(quantmod)
library(stringr)
# get tickers from user
ticker <- toupper(dlgInput("Please enter one or more tickers separated by comma.")$res)
# split tickers
tickers <- unlist(strsplit(gsub(" ", "", ticker, fixed = TRUE), ","))
# download from Yahoo!
yahooSymbol <- getSymbols.yahoo(tickers, env = globalenv())
# close all open Internet connections (as a precaution)
closeAllConnections()
So I thought that if code above works, why not in a while
statement like:
# load packages
library(svDialogs)
library(quantmod)
library(stringr)
while (TRUE) {
# get one or many tickers
ticker <- toupper(str_trim(dlgInput("Enter one or more new or not loaded tickers separated with comma.")$res))
# split tickers
tickers <- unlist(strsplit(gsub(" ", "", ticker, fixed = TRUE), ","))
# check locally if already loaded
if (exists(tickers)) next
# download from Yahoo!
yahooSymbol <- getSymbols.yahoo(tickers, env = globalenv())
# if yahoo returned a response, exit the loop
if (!identical(yahooSymbol, character(0))) break
}
Needless to say/write that I miserably failed with an Error in exists(tickers) : first argument has length > 1
. However, when I quote out if (exists(tickers)) next
, small victory, the yahooSymbol <- getSymbols.yahoo(tickers, env = globalenv())
does nevertheless download the symbols from Yahoo!
My question:
- How to correct the above piece of code so that it both loop-verifies the existence of the tickers and downloads them from Yahoo! if they exist there?
Systems used:
- R version: 4.1.1 (2021-08-10)
- RStudio version: 1.4.1717
- OS: macOS Catalina version 10.15.7 and macOS Big Sur version 11.6
CodePudding user response:
The problem comes from the fact that exists
only tests for the existence of a single object.
Try for example
exists(c("a", "b"))
and you will get the same error that crashes your code.
To solve your problem, try
if (all(sapply(tickers, exists))) next
sapply
will allow you to "apply" the functionexists
to all the elements intickers
,all
will tell if the resulting vector given by thesapply
is composed only ofTRUE
s.