1
votes

I am importing some stock data from yahoo and would like to calculate the daily range as High - Low. I then want to put each stock's range in a single xts object. The below code accomplishes this but seems very convoluted to me.

The problem starts with lapply. I get a list of xts objects, but need to refer to the individual objects "a layer down" using [[ ]]. If I could get refer to each xts object as quotes[i], I could continue to use the apply functions rather than the for loops. I tried to use sapply instead of lapply but got an error, "Error in array(r, dim = d, dimnames = if (!(is.null(n1 <- names(x[[1L]])) & : length of 'dimnames' [1] not equal to array extent"

Furthermore, I hate the practice I used in the second for loop. range doesn't yet exist, so I need to create it but doing it in this way seems to defeat the purpose of a loop. Is there a better way? I'd also like to avoid creating an empty xts object as I know that is not good practice either.

require(quantmod)
tickers <- c("ERX", "EWJ", "EWW", "EWZ", "FAS", "FAZ")

quotes <- lapply(tickers,function(x) getSymbols(x, src="yahoo", from="2014-10-10", auto.assign=FALSE)) 
names(quotes) <- tickers

for (i in 1:length(quotes)){
  quotes[[i]] <- quotes[[i]][,2] - quotes[[i]][,3]
  colnames(quotes[[i]]) <- paste(names(quotes)[i], "Range")
}

for (i in 1:length(quotes)){

  if (i == 1) {range <- quotes[[i]]}

  else {range <- merge(range, quotes[[i]])}
}

Thank you.

1

1 Answers

3
votes

The easiest way is to store the data in an environment, and then loop over all the objects in the environment with eapply:

require(quantmod)
tickers <- c("ERX", "EWJ", "EWW", "EWZ", "FAS", "FAZ")
dataEnv <- new.env()
getSymbols(tickers, env=dataEnv)
# Calculate the range for all objects,
# then merge all range columns into one object
hl <- do.call(merge, eapply(dataEnv, function(x) Hi(x)-Lo(x)))
# update the column names
colnames(hl) <- gsub("(.*)High$", "\\1Range", colnames(hl))