quantmod
quantmod copied to clipboard
[R-Forge #2165] issue when downloading prices for ticker Lowe's Companies Inc (ticker LOW)
Submitted by: Paolo Cavatore Assigned to: Nobody R-Forge link
I just wanted to point out a likely bug in the below code when downloading prices for Lowe's Companies Inc (ticker LOW)
getSymbols('LOW', src='yahoo')
LOW.uA <- adjustOHLC(LOW, use.Adjusted=TRUE)
Error message:
Error in `-.default`(Lo(x), Cl(x)) : array incompatibili
Sounds like related to the ticker being equal to the name Low intended for the Low price.
Followups:
Date: 2013-07-18 01:49 Sender: jim green
`Lo` <-
function(x)
{
if(has.Lo(x))
return(x[,grep('Low',colnames(x),ignore.case=TRUE)])
stop('subscript out of bounds: no column name containing 'Low'')
}
the issue is here in the grep
, change 'Low' to '.Low' and it will work.
Date: 2013-07-18 02:06 Sender: Joshua Ulrich
JimGreen: Changing the pattern from 'Low' to '.Low' will cause this to break: data(sample_matrix); Lo(sample_matrix)
Date: 2013-07-21 00:52 Sender: jim green maybe this?
`Lo` <-
function(x)
{
if(has.Lo(x)) {
#prevent LOW.Low
if(length(grep('\.',colnames(x)[[1]]))){
return(x[,grep('.Low',colnames(x),ignore.case=TRUE)])
} else {
return(x[,grep('Low',colnames(x),ignore.case=TRUE)])
}
}
stop('subscript out of bounds: no column name containing 'Low'')
}
Date: 2013-07-26 16:35 Sender: Joshua Ulrich
I think the best solution is to take advantage of the fact that the has.*()
functions first look for an attribute that matches * (e.g. has.Lo()
looks for attr(x,'Lo')
). This would require that Lo
use x[,has.Lo(x,which=TRUE)]
instead of grep()
and that getSymbols
set those column attributes. Thoughts?
Enrico Schumann made an interesting suggestion in this thread on R-SIG-Finance.
Perhaps one could add a warning for this case, either in
Lo
orhas.Lo
?i <- grep("Low", colnames(x), ignore.case = TRUE) if (length(i) > 1L) warning("more than one column match 'low': ", paste(colnames(x)[i], collapse = " "))
I just realized that this bug has not been fixed yet!!
I don't like the warning approach because it will destroy any automated system with many names.
What about a combination of two previous suggestions?:
i <- grep("Low", colnames(x), ignore.case = TRUE)
if (length(i) > 1L)
i <- grep(".Low", colnames(x), ignore.case = TRUE)
That seems to be a promising approach. Here's a function that uses it:
lo <- function (x)
{
j <- has.Lo(x, which = TRUE)
if (length(j) > 1L) {
j <- grep(".Low", colnames(x), ignore.case = TRUE)
}
if (length(j) > 0L) {
return(x[, j])
}
stop("subscript out of bounds: no column name containing \"Low\"")
}
I would want some unit tests before committing the change though. The test that failed in Jim Green's original suggestion passes with the function above (e.g. lo(sample_matrix)
). I would really appreciate anyone who has thoughts about what this change may break.
I also want to add similar changes to the other column extractor functions (Op
, Hi
, Cl
, OHLC
, etc).
Probably a very edge case, but maybe something like this would be a touch safer. It would handle the case where a prefix had been added to the column names like “My.LOW.Low”
lo <- function (x)
{
j <- has.Lo(x, which = TRUE)
if (length(j) > 1L) {
j <- grep("LOW\\.Low", colnames(x), ignore.case = TRUE)
if(length(j) > 1L) warning("ambiguous column names: more than 1 column name containing \"Low\"")
}
if (length(j) > 0L) {
return(x[, j])
}
stop("subscript out of bounds: no column name containing \"Low\"")
}
Can't we isolate the OHLC columns by isolating the ticket name and dropping it? I.e. when we download a symbol, the colnames are something like SPY.Open, SPY.High, SPY.Low, SPY.Close, etc. Thus, we know that the descriptors occur after the last period in a symbols name. Therefore, we can throw out everything before that, thus leaving us with just the descriptors (OHLC, etc.). Does this work?
I agree this seems like a nice clean way as we generate the names internally anyway. Could still break if users rename, but that would not be quantmod problem.
On Sat, May 20, 2023 at 16:18 Ilya Kipnis @.***> wrote:
Can't we isolate the OHLC columns by isolating the ticket name and dropping it? I.e. when we download a symbol, the colnames are something like SPY.Open, SPY.High, SPY.Low, SPY.Close, etc. Thus, we know that the descriptors occur after the last period in a symbols name. Therefore, we can throw out everything before that, thus leaving us with just the descriptors (OHLC, etc.). Does this work?
— Reply to this email directly, view it on GitHub https://github.com/joshuaulrich/quantmod/issues/24#issuecomment-1556009516, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGWZQAFBR2WWB7LVANEEJDXHEYIVANCNFSM4A3H2ZRQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>
That would be a case of extreme PEBKAC imo.
On Sat, May 20, 2023, 4:36 PM Jeffrey Ryan @.***> wrote:
I agree this seems like a nice clean way as we generate the names internally anyway. Could still break if users rename, but that would not be quantmod problem.
On Sat, May 20, 2023 at 16:18 Ilya Kipnis @.***> wrote:
Can't we isolate the OHLC columns by isolating the ticket name and dropping it? I.e. when we download a symbol, the colnames are something like SPY.Open, SPY.High, SPY.Low, SPY.Close, etc. Thus, we know that the descriptors occur after the last period in a symbols name. Therefore, we can throw out everything before that, thus leaving us with just the descriptors (OHLC, etc.). Does this work?
— Reply to this email directly, view it on GitHub < https://github.com/joshuaulrich/quantmod/issues/24#issuecomment-1556009516 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAGWZQAFBR2WWB7LVANEEJDXHEYIVANCNFSM4A3H2ZRQ
. You are receiving this because you are subscribed to this thread.Message ID: @.***>
— Reply to this email directly, view it on GitHub https://github.com/joshuaulrich/quantmod/issues/24#issuecomment-1556017590, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABAA5UPNJKSDJSFRCEN6D53XHE2N5ANCNFSM4A3H2ZRQ . You are receiving this because you commented.Message ID: @.***>