Home > Enterprise >  Allow user to input multiple values to be treated in while statement with R
Allow user to input multiple values to be treated in while statement with R

Time:09-28

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 function exists to all the elements in tickers,
  • all will tell if the resulting vector given by the sapply is composed only of TRUEs.
  • Related