[This article was first published on Systematic Investor » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
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
#******************************************************************

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.

To leave a comment for the author, please follow the link and comment on their blog: Systematic Investor » R.

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.

# Never miss an update! Subscribe to R-bloggers to receive e-mails with the latest R posts.(You will not see this message again.)

Click here to close (This popup will not appear again)