library(TTR)
lengths = c(5,10,15,20,30,40,50,75,100,150,200, 250, 300, 350, 400, 450, 500)
MA = matrix(0, nrow=length(Close), ncol=length(lengths))
for (i in 1:length(lengths)) {
  MA[,i] = SMA(Close, lengths[i])
}
# assume the MA represents fair value
# does price really return to "fair value?" within our window length?
returns = numeric(length(lengths)); occurrences = returns
pnl = returns
returnperiod = 5 ## allow 5 * the MA length for a return to value
for (i in 1:length(lengths)) {
  window = lengths[i] * returnperiod 
  start = lengths[i]; end = length(Close) - window
  for (k in start:end) {
    # see if price is above (1) or below (-1) the MA
    ab = 0 # equal to MA
    if (Close[k] > MA[k,i]) ab = 1
    if (Close[k] < MA[k,i]) ab = -1
    
    # see if price really reverts to "value" over our window length
    occurrences[i] = occurrences[i] + 1
    converged = FALSE
    for (win in 1:window) {
      if (ab == 1 && Low[k+win] <= MA[k,i]) {
        returns[i] = returns[i] + 1
        pnl[i] = pnl[i] + Close[k] - MA[k,i]
        converged = TRUE
        break
      } else if (ab == -1 && High[k+win] >= MA[k,i]) {
        returns[i] = returns[i] + 1
        pnl[i] = pnl[i] - (Close[k] - MA[k,i])
        converged = TRUE
        break
      }
    }
    # calculate pnl given failure to converge and an exit
    # assume just exit at current price
    if (!converged && ab != 0) { 
      if (ab == 1) pnl[i] = pnl[i] + Close[k] - Close[k+window]
      if (ab == -1) pnl[i] = pnl[i] - (Close[k] - Close[k+window])
    }
  }
}
tbl = cbind(lengths, returns/occurrences,pnl / occurrences)
colnames(tbl) = c('MA Length', 'Convergence %', 'Pnl')
tbl
