quantmod icon indicating copy to clipboard operation
quantmod copied to clipboard

[R-Forge #2165] issue when downloading prices for ticker Lowe's Companies Inc (ticker LOW)

Open joshuaulrich opened this issue 9 years ago • 7 comments

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?

joshuaulrich avatar Jan 31 '15 22:01 joshuaulrich

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 or has.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 = " "))

joshuaulrich avatar Mar 16 '19 13:03 joshuaulrich

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)

dppalomar avatar Jun 19 '19 05:06 dppalomar

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).

joshuaulrich avatar Jun 23 '19 13:06 joshuaulrich

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\"")
}

ethanbsmith avatar Jun 23 '19 15:06 ethanbsmith

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?

IlyaKipnis avatar May 20 '23 21:05 IlyaKipnis

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: @.***>

jaryan avatar May 20 '23 21:05 jaryan

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: @.***>

IlyaKipnis avatar May 20 '23 21:05 IlyaKipnis