I am using R, quantmod and Performanceanalystics packages. As part of a backtesting strategy, I am trying to create a signal/holdings vector that tells me whether I should buy/sell/hold a stock, based on the value of RSI. If RSI<30, buy (so holdings increases by 1), if RSI is between 30 & 50, don't do anything (so holdings remain the same as yesterday). If RSI>=50, sell everything (so holdings become zero). Thereafter, use the dailyReturn() function from Performanceanalytics to calculate and generate a graph of returns.
Note that RSI() is a function that takes "price" and "day", and dailyReturn() function also takes "price"
I have been able to do perfectly fine with the following code below.
library(quantmod)
library(PerformanceAnalytics)
getSymbols("IBM", src= "yahoo", from = "2000-01-01", to ="2015-09-25")
rsi<-RSI(Cl(IBM),14)
rsi<-lag(rsi,1)
rsi[is.na(rsi)] <- 0
holdings1 <-c() #initialize the vector
holdings1[1:14+1]<-0 #Not holding any shares of IBM from 1st to the 15th day
for (i in 14+2: length(Cl(IBM))){ #assume start buying from the 16th day onwards since we are using RSI where n=14
if (rsi[i]<30){ #if RSI<30, we buy one share of IBM
holdings1[i]<-holdings1[i-1]+1
} else if (rsi[i]>50){ # if RSI>50, we sell all holdings
holdings1[i]<-0
} else
holdings1[i]<- holdings1[i-1] # remains the same: if 30<=RSI<=50 we don't do anything, so same holdings as prior
}
size1<-reclass(holdings1,Cl(IBM))
ret1<-dailyReturn(Cl(IBM))*size1
charts.PerformanceSummary(ret1)
But I am required to create a function called "size1()" that takes in "price" and "day" (Prof says, and I don't do computing). When I try to that, RStudio tells me "Error in lag(rsi, 1) : object 'rsi' not found". Why is that? Is it not legal to create a function or a vector in a function? Or should I structure my code in a different way from the first one above? The code with function(price,day) is below:
library(quantmod)
library(PerformanceAnalytics)
getSymbols("IBM", src= "yahoo", from = "2000-01-01", to ="2015-09-25") #download IBM, from the stipulated range of dates
size1<-function(price,day){
ris<-RSI(price,day)
ris<-lag(rsi,1)
rsi[is.na(rsi)] <- 0
holdings1<-c()
holdings1[1:day+1]<-0
for (i in day+2: length(price)){ #assume start buying from the 15th day onwards since we are using RSI, n=14
if (rsi[i]<30){ #if RSI<30, we buy one share of IBM
holdings1[i]<-holdings1[i-1]+1
} else if (rsi[i]<50){ # if 30<RSI<50, we don't buy or sell, so that the holdings does not change
holdings1[i]<-holdings1[i-1]
} else
holdings1[i]<-0 # sell all if RSI>50
size<-reclass(holdings1,price)
}
}
ret1<-dailyReturn(Cl(IBM))*size1(Cl(IBM),14)
charts.PerformanceSummary(ret1)
day+2:length(price)
isn't what you expect. :
has precedence over +
(see ?Syntax
). It evaluates to day + (2:length(price))
. You want (day+2):length(price)
. Also note that xts objects are a matrix with an index
attribute, and a matrix is just a vector with a dim
attribute. Calling length
on a matrix returns the total number of observations (the length
of the vector). You should use nrow
instead.
It's also good practice to pre-allocate the entire result vector before the for
loop. Your current code appends to holdings
every time you call holdings[i] <-
when i
is larger than the current length of holdings
.
Also, your function currently does not return anything. It looks like you intend to return the size
object. Note that you do not need to re-create that object at every loop iteration.
size1 <- function (price, day) {
rsi <- RSI(price, day)
rsi <- lag(rsi, 1)
rsi[is.na(rsi)] <- 0
holdings1 <- integer(nrow(price))
# assume start buying from the 15th day onwards,
# since we are using RSI, n=14
for (i in (day+1):nrow(price)) {
if (rsi[i] < 30) {
# if RSI<30, we buy one share of IBM
holdings1[i] <- holdings1[i - 1] + 1
}
else if (rsi[i] < 50) {
# if 30<RSI<50, we don't buy or sell,
# so that the holdings does not change
holdings1[i] <- holdings1[i - 1]
} else {
# sell all if RSI>50
holdings1[i] <- 0
}
}
reclass(holdings1, price)
}