-1

I have two xts objects: stock and base. I calculate the relative strength (which is simply the ratio of closing price of stock and of the base index) and I want to plot the weekly relative strength outside the candlestick pattern. The links for the data are here and here.

library(quantmod)
library(xts)

read_stock = function(fichier){ #read and preprocess data
  stock = read.csv(fichier, header = T)
  stock$DATE = as.Date(stock$DATE, format = "%d/%m/%Y") #standardize time format
  stock = stock[! duplicated(index(stock), fromLast = T),] # Remove rows with a duplicated timestamp, 
                                                      # but keep the latest one
  stock$CLOSE = as.numeric(stock$CLOSE) #current numeric columns are of type character
  stock$OPEN = as.numeric(stock$OPEN)   #so need to convert into double
  stock$HIGH = as.numeric(stock$HIGH)   #otherwise quantmod functions won't work
  stock$LOW = as.numeric(stock$LOW)
  stock$VOLUME = as.numeric(stock$VOLUME)
  stock = xts(x = stock[,-1], order.by = stock[,1]) # convert to xts class
  return(stock)
}

relative.strength = function(stock, base = read_stock("vni.csv")){
  rs = Cl(stock) / Cl(base)
  rs = apply.weekly(rs, FUN = mean)
}
stock = read_stock("aaa.csv")

candleChart(stock, theme='white')
addRS = newTA(FUN=relative.strength,col='red', legend='RS')
addRS()

However R returns me this error:

 Error in `/.default`(Cl(stock), Cl(base)) : non-numeric argument to binary operator

How can I fix this?

SiXUlm
  • 159
  • 3
  • 12

2 Answers2

1

One problem is that "vni.csv" contains a "Ticker" column. Since xts objects are a matrix at their core, you can't have columns of different types. So the first thing you need to do is ensure that you only keep the OHLC and volume columns of the "vni.csv" file. I've refactored your read_stock function to be:

read_stock = function(fichier) {
  # read and preprocess data
  stock <- read.csv(fichier, header = TRUE, as.is = TRUE)
  stock$DATE = as.Date(stock$DATE, format = "%d/%m/%Y")
  stock = stock[!duplicated(index(stock), fromLast = TRUE),]
  # convert to xts class
  stock = xts(OHLCV(stock), order.by = stock$DATE)
  return(stock)
}

Next, it looks like the the first argument to relative.strength inside the addRS function is passed as a matrix, not an xts object. So you need to convert to xts, but take care that the index class of the stock object is the same as the index class of the base object.

Then you need to make sure your weekly rs object has an observation for each day in stock. You can do that by merging your weekly data with an empty xts object that has all the index values for the stock object.

So I refactored your relative.strength function to:

relative.strength = function(stock, base) {
  # convert to xts
  sxts <- as.xts(stock)
  # ensure 'stock' index class is the same as 'base' index class
  indexClass(sxts) <- indexClass(base)
  index(sxts) <- index(sxts)
  # calculate relative strength
  rs = Cl(sxts) / Cl(base)
  # weekly mean relative strength
  rs = apply.weekly(rs, FUN = mean)
  # merge 'rs' with empty xts object contain the same index values as 'stock'
  merge(rs, xts(,index(sxts)), fill = na.locf)
}

Now, this code:

stock = read_stock("aaa.csv")
base = read_stock("vni.csv")
addRS = newTA(FUN=relative.strength, col='red', legend='RS')
candleChart(stock, theme='white')
addRS(base)

Produces this chart:

enter image description here

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • Thanks a lot! I have one small question. In the first line in relative.strength function, why do we still need to convert "stock" to an xts object, even though the "stock" itself is already an xts object (as a result of read_stock function)? – SiXUlm Jun 18 '17 at 10:27
  • @SiXUlm: Because the `addRS` function generated by `newTA` calls `as.matrix` on the xts data. So we need to convert it back to xts with a Date index in order to merge with the `base` object. – Joshua Ulrich Jun 18 '17 at 15:35
0

The following line in your read_stock function is causing the problem:

stock = xts(x = stock[,-1], order.by = stock[,1]) # convert to xts class

vni.csv has the actual symbol name in the third column of your data, so when you put stock[,-1] you're actually including a character column and xts forces all the other columns to be characters as well. Then R alerts you about dividing a number by a character at Cl(stock) / Cl(base). Here is a simple example of this error message with division:

> x <- c(1,2)
> y <- c("A", "B")
> x/y
Error in x/y : non-numeric argument to binary operator

I suggest you remove the character column in vni.csv that contains "VNIndex" in every row or modify your function called read_stock() to better protect against this type of issue.

Steven M. Mortimer
  • 1,618
  • 14
  • 36