Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
I came across the link to the John Ehlers paper: Predictive Indicators for Effective Trading Strategies, while reading the Dekalog Blog. John Ehlers offers a different way to smooth prices and incorporate the new filter into the oscillator construction. Fortunately, the EasyLanguage code was also provided and i was able to translate it into R.
Following are some results from the paper and test of John’s stochastic oscillator.
############################################################################### # Super Smoother filter 2013 John F. Ehlers # http://www.stockspotter.com/files/PredictiveIndicators.pdf ############################################################################### super.smoother.filter <- function(x) { a1 = exp( -1.414 * pi / 10.0 ) b1 = 2.0 * a1 * cos( (1.414*180.0/10.0) * pi / 180.0 ) c2 = b1 c3 = -a1 * a1 c1 = 1.0 - c2 - c3 x = c1 * (x + mlag(x)) / 2 x[1] = x[2] out = x * NA out[] = filter(x, c(c2, c3), method='recursive', init=c(0,0)) out } # Roofing filter 2013 John F. Ehlers roofing.filter <- function(x) { # Highpass filter cyclic components whose periods are shorter than 48 bars alpha1 = (cos((0.707*360 / 48) * pi / 180.0 ) + sin((0.707*360 / 48) * pi / 180.0 ) - 1) / cos((0.707*360 / 48) * pi / 180.0 ) x = (1 - alpha1 / 2)*(1 - alpha1 / 2)*( x - 2*mlag(x) + mlag(x,2)) x[1] = x[2] = x[3] HP = x * NA HP[] = filter(x, c(2*(1 - alpha1), - (1 - alpha1)*(1 - alpha1)), method='recursive', init=c(0,0)) super.smoother.filter(HP) } # My Stochastic Indicator 2013 John F. Ehlers roofing.stochastic.indicator <- function(x, lookback = 20) { Filt = roofing.filter(x) HighestC = runMax(Filt, lookback) HighestC[1:lookback] = as.double(HighestC[lookback]) LowestC = runMin(Filt, lookback) LowestC[1:lookback] = as.double(LowestC[lookback]) Stoc = (Filt - LowestC) / (HighestC - LowestC) super.smoother.filter(Stoc) }
First let’s plot the John’s stochastic oscillator vs traditional one.
############################################################################### # Load Systematic Investor Toolbox (SIT) # http://systematicinvestor.wordpress.com/systematic-investor-toolbox/ ############################################################################### setInternet2(TRUE) con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb')) source(con) close(con) #***************************************************************** # Load historical data #****************************************************************** load.packages('quantmod') tickers = spl('DG') data = new.env() getSymbols(tickers, src = 'yahoo', from = '1970-01-01', env = data, auto.assign = T) for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T) bt.prep(data) #***************************************************************** # Setup #***************************************************************** prices = data$prices models = list() # John Ehlers Stochastic stoch = roofing.stochastic.indicator(prices) # 14 Day Stochastic stoch14 = bt.apply(data, function(x) stoch(HLC(x),14)[,'slowD']) #***************************************************************** # Create plots #****************************************************************** dates = '2011:10::2012:9' layout(1:3) plota(prices[dates], type='l', plotX=F) plota.legend('DG') plota(stoch[dates], type='l', plotX=F) abline(h = 0.2, col='red') abline(h = 0.8, col='red') plota.legend('John Ehlers Stochastic') plota(stoch14[dates], type='l') abline(h = 0.2, col='red') abline(h = 0.8, col='red') plota.legend('Stochastic')
Next let’s code the trading rules as in Figure 6 and 8 in the John Ehlers paper: Predictive Indicators for Effective Trading Strategies
#***************************************************************** # Code Strategies #***************************************************************** # Figure 6: Conventional Wisdom is to Buy When the Indicator Crosses Above 20% and # To Sell Short when the Indicator Crosses below 80% data$weight[] = NA data$weight[] = iif(cross.up(stoch, 0.2), 1, iif(cross.dn(stoch, 0.8), -1, NA)) models$post = bt.run.share(data, clean.signal=T, trade.summary=T) data$weight[] = NA data$weight[] = iif(cross.up(stoch, 0.2), 1, iif(cross.dn(stoch, 0.8), 0, NA)) models$post.L = bt.run.share(data, clean.signal=T, trade.summary=T) data$weight[] = NA data$weight[] = iif(cross.up(stoch, 0.2), 0, iif(cross.dn(stoch, 0.8), -1, NA)) models$post.S = bt.run.share(data, clean.signal=T, trade.summary=T) # Figure 8: Predictive Indicators Enable You to Buy When the Indicator Crosses Below 20% and # To Sell Short when the Indicator Crosses Above 80% data$weight[] = NA data$weight[] = iif(cross.dn(stoch, 0.2), 1, iif(cross.up(stoch, 0.8), -1, NA)) models$pre = bt.run.share(data, clean.signal=T, trade.summary=T) data$weight[] = NA data$weight[] = iif(cross.dn(stoch, 0.2), 1, iif(cross.up(stoch, 0.8), 0, NA)) models$pre.L = bt.run.share(data, clean.signal=T, trade.summary=T) data$weight[] = NA data$weight[] = iif(cross.dn(stoch, 0.2), 0, iif(cross.up(stoch, 0.8), -1, NA)) models$pre.S = bt.run.share(data, clean.signal=T, trade.summary=T) #***************************************************************** # Create Report #****************************************************************** strategy.performance.snapshoot(models, T)
Look’s like most profit comes from the long side.
Finally let’s visualize the timing of the signal for these strategies:
john.ehlers.custom.strategy.plot <- function(data, models, name, main = name, dates = '::', layout = NULL # flag to indicate if layout is already set ) { # John Ehlers Stochastic stoch = roofing.stochastic.indicator(data$prices) # highlight logic based on weight weight = models[[name]]$weight[dates] col = iif(weight > 0, 'green', iif(weight < 0, 'red', 'white')) plota.control$col.x.highlight = col.add.alpha(col, 100) highlight = T if(is.null(layout)) layout(1:2) plota(data$prices[dates], type='l', x.highlight = highlight, plotX = F, main=main) plota.legend('Long,Short,Not Invested','green,red,white') plota(stoch[dates], type='l', x.highlight = highlight, plotX = F, ylim=c(0,1)) col = col.add.alpha('red', 100) abline(h = 0.2, col=col, lwd=3) abline(h = 0.8, col=col, lwd=3) plota.legend('John Ehlers Stochastic') } layout(1:4, heights=c(2,1,2,1)) john.ehlers.custom.strategy.plot(data, models, 'post.L', dates = '2013::', layout=T, main = 'post.L: Buy When the Indicator Crosses Above 20% and Sell when the Indicator Crosses Below 80%') john.ehlers.custom.strategy.plot(data, models, 'pre.L', dates = '2013::', layout=T, main = 'pre.L: Buy When the Indicator Crosses Below 20% and Sell when the Indicator Crosses Above 80%')
As a homework, I encourage you to compare trading the John’s stochastic oscillator vs traditional one.
To view the complete source code for this example, please have a look at the john.ehlers.filter.test() function in bt.test.r at github.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.