Search code examples
rquantmodportfoliotradingalgorithmic-trading

Bollinger Strategy in R with Entry and Exit Signals at Re-allocation Dates


I have the following simple trading strategy:

Entry Signal: when the Price of IBM is above the upper Bollinger band.

Close Signal: when the Price of IBM is below the lower Bollinger band.

Here are the Bollinger Bands:

require(quantmod)

# load IBM data 
tickers = c("IBM")
myEnv = new.env()
getSymbols(tickers, from="2012-01-03", to="2014-12-01", env=myEnv)

close.prices = do.call(merge, eapply(myEnv, Cl))
close.prices = close.prices[,pmatch(tickers,colnames(close.prices))]
colnames(close.prices) = c("IBM")

# extract the upper and lower bollinger band with TTR's BBands function
bb.up = BBands(close.prices, n=20, maType = SMA)[,3] 
bb.dn = BBands(close.prices, n=20, maType = SMA)[,1]

The tricky part now is to close the position only if the Price of IBM is below the lower Bollinger band at the re-allocation date. Otherwise we roll the Signal of the last period to the next period. To accomplish weekly re-allocation:

# apply the startpoints function to pick the week's first trading day for 
# re-allocating the portfolio

startpoints = function (x, on = "weeks", k = 1) {
  head(endpoints(x, on, k) + 1, -1)
}

sig.bb.up = ifelse(close.prices > bb.up, 1, 0)
sig.bb.up = sig.bb.up[startpoints(bb.up),]

sig.bb.dn = ifelse(close.prices < bb.dn, 1, 0)
sig.bb.dn = sig.bb.dn[startpoints(bb.dn),]

The whole question now is how to define a properly coded signal function sig.bb that contains a "1" as soon as the Price is above its upper bollinger band at a re-allocation date, then holds the stock until the price is below its lower bollinger band at any following re-allocation date.

What I have tried is to catch the frist observation and then to roll all the following observations based on the first entry of the sig.bb vector

sig.bb = ifelse(index(close.prices[1,1]) == "2012-01-03", sig.bb.up,
                ifelse(close.prices > bb.up, 1,
                       ifelse(close.prices < bb.dn, 0, lag(sig.bb))))

which returns "NA"...

How to proceed (for those interested in this topic) after sig.bb is obtained can be found here: Equally Weighted Reallocation of Stock Portfolio at Specific Dates According to a Signal


Solution

  • I'm not exactly sure what you want the output to be, but see if this is close

    m <- merge(close.prices, BBands(close.prices, n=20, maType="SMA"))
    
    m$sig[with(m, IBM > up) & index(m) %in% index(m)[startpoints(m, on="weeks")]] <- 1
    m$sig[with(m, IBM < dn) & index(m) %in% index(m)[startpoints(m, on="weeks")]] <- 0
    m$sig[1] <- 0
    na.locf(m)