Search code examples
rquantmod

R / quantmod - discrepancy between BBands() and runsd(EMA) calculations


I am trying to create a signal state when my spread calculation is greater than or less than upper/lower Bollinger Bands, however my calculations:

pair <- c("qqq","iwm")
start <-  "2014-08-08"
finish <- "2015-08-13"
stckY <- suppressWarnings(getSymbols(pair[1], from = start, to = finish, auto.assign = FALSE))
stckX <- suppressWarnings(getSymbols(pair[2], from = start, to = finish, auto.assign = FALSE))

adY <- Ad(stckY)
adX <- Ad(stckX)

logY <- log(adY)
logX <- log(adX)

spread <- cbind(logY, logX)
spread <- spread[complete.cases(spread),] #remove NAs
spread$dailyDiff <- spread[,1] - spread[,2]

ema <- EMA(spread[,1] - spread[,2], n=20)
spread$UpBand <- (runSD(ema, n=20) * 2) + ema
spread$LwBand <- ema - (runSD(ema, n=20) * 2)

chartSeries(spread$dailyDiff, up.col = "white", 
            theme = chartTheme("black"), line.type = "l")
addEMA(n = 20, col = "orange")
addBBands(n = 20, sd = 2, maType = "EMA")

aren't matching the band values displayed on the chartSeries display and I cannot figure out why? The help file states that not using SMA might cause "inconsistencies", so maybe this is the source of the problem? The chartSeries is also using an EMA.

Perhaps there is a better way to go about this? I'm not sure how to reference the upper/lower bands using BBands() alone...


Solution

  • There are 2 problems:

    1. You're taking the standard deviation of the moving average when you should be taking the standard deviation of the original series.
    2. The BBands function uses sample = FALSE in the runSD call.

    This replicates the output of the BBands function in your chart:

    ema <- EMA(spread$dailyDiff, n=20)
    spread$UpBand <- runSD(spread$dailyDiff, n=20, sample=FALSE) * 2 + ema
    spread$LwBand <- ema - runSD(spread$dailyDiff, n=20, sample=FALSE) * 2
    tail(spread)
    #            QQQ.Adjusted IWM.Adjusted   dailyDiff      UpBand     LwBand
    # 2015-08-06     4.704563     4.793060 -0.08849663 -0.06442705 -0.1381200
    # 2015-08-07     4.703295     4.786575 -0.08328008 -0.06687188 -0.1322478
    # 2015-08-10     4.714652     4.798267 -0.08361464 -0.06938022 -0.1267023
    # 2015-08-11     4.701752     4.789323 -0.08757113 -0.07421110 -0.1198771
    # 2015-08-12     4.705196     4.787408 -0.08221192 -0.07856667 -0.1126964
    # 2015-08-13     4.703566     4.784320 -0.08075361 -0.08283161 -0.1055975
    tail(BBands(spread$dailyDiff, n=20, maType="EMA"))
    #                    dn        mavg          up      pctB
    # 2015-08-06 -0.1381200 -0.10127351 -0.06442705 0.6733800
    # 2015-08-07 -0.1322478 -0.09955985 -0.06687188 0.7490178
    # 2015-08-10 -0.1267023 -0.09804126 -0.06938022 0.7516764
    # 2015-08-11 -0.1198771 -0.09704411 -0.07421110 0.7074403
    # 2015-08-12 -0.1126964 -0.09563152 -0.07856667 0.8931942
    # 2015-08-13 -0.1055975 -0.09421457 -0.08283161 1.0912769