<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/ehlerss-autocorrelation-periodogram/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://quantstrattrader.wordpress.com/2017/02/15/ehlerss-autocorrelation-periodogram/"> R – QuantStrat TradeR</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>This post will introduce John Ehlers’s Autocorrelation Periodogram mechanism–a mechanism designed to dynamically find a lookback period. That is, the most common parameter optimized in backtests is the lookback period.</p>
<p>Before beginning this post, I must give credit where it’s due, to one <a target="_blank" rel="nofollow" href="https://www.linkedin.com/in/fabrizio-maccallini-2a996053">Mr. Fabrizio Maccallini</a>, the head of structured derivatives at Nordea Markets in London. You can find the rest of the repository he did for Dr. John Ehlers’s <a target="_blank" rel="nofollow" href="https://www.amazon.com/Cycle-Analytics-Traders-Downloadable-Software/dp/1118728513">Cycle Analytics for Traders</a> on his <a target="_blank" rel="nofollow" href="https://github.com/fabmaccallini/ehlers">github</a>. I am grateful and honored that such intelligent and experienced individuals are helping to bring some of Dr. Ehlers’s methods into R.</p>
<p>The point of the Ehlers Autocorrelation Periodogram is to dynamically set a period between a minimum and a maximum period length. While I leave the exact explanation of the mechanic to Dr. Ehlers’s book, for all practical intents and purposes, in my opinion, the punchline of this method is to attempt to remove a massive source of overfitting from trading system creation–namely specifying a lookback period.</p>
<p>SMA of 50 days? 100 days? 200 days? Well, this algorithm takes that possibility of overfitting out of your hands. Simply, specify an upper and lower bound for your lookback, and it does the rest. How well it does it is a topic of discussion for those well-versed in the methodologies of electrical engineering (I’m not), so feel free to leave comments that discuss how well the algorithm does its job, and feel free to blog about it as well.</p>
<p>In any case, here’s the original algorithm code, courtesy of Mr. Maccallini:</p>
<pre>
AGC &lt;- function(loCutoff = 10, hiCutoff = 48, slope = 1.5) {      accSlope = -slope # acceptableSlope = 1.5 dB   ratio = 10 ^ (accSlope / 20)   if ((hiCutoff - loCutoff) > 0)
    factor &lt;-  ratio ^ (2 / (hiCutoff - loCutoff));
  return (factor)
}

autocorrPeriodogram &lt;- function(x, period1 = 10, period2 = 48, avgLength = 3) {
  # high pass filter
  alpha1 &lt;- (cos(sqrt(2) * pi / period2) + sin(sqrt(2) * pi / period2) - 1) / cos(sqrt(2) * pi / period2)
  hp &lt;- (1 - alpha1 / 2) ^ 2 * (x - 2 * lag(x) + lag(x, 2))
  hp &lt;- hp[-c(1, 2)]
  hp &lt;- filter(hp, (1 - alpha1), method = &quot;recursive&quot;)
  hp &lt;- c(NA, NA, hp)
  hp &lt;- xts(hp, order.by = index(x))
  # super smoother
  a1 &lt;- exp(-sqrt(2) * pi / period1)
  b1 &lt;- 2 * a1 * cos(sqrt(2) * pi / period1)
  c2 &lt;- b1
  c3 &lt;- -a1 * a1
  c1 &lt;- 1 - c2 - c3
  filt &lt;- c1 * (hp + lag(hp)) / 2
  leadNAs &lt;- sum(is.na(filt))
  filt &lt;- filt[-c(1: leadNAs)]
  filt &lt;- filter(filt, c(c2, c3), method = &quot;recursive&quot;)
  filt &lt;- c(rep(NA, leadNAs), filt)
  filt &lt;- xts(filt, order.by = index(x))
  # Pearson correlation for each value of lag
  autocorr &lt;- matrix(0, period2, length(filt))
  for (lag in 2: period2) {
    # Set the average length as M
    if (avgLength == 0) M &lt;- lag
    else M &lt;- avgLength
    autocorr[lag, ] &lt;- runCor(filt, lag(filt, lag), M)
  }
  autocorr[is.na(autocorr)] &lt;- 0
  # Discrete Fourier transform
  # Correlate autocorrelation values with the cosine and sine of each period of interest
  # The sum of the squares of each value represents relative power at each period
  cosinePart &lt;- sinePart &lt;- sqSum &lt;- R &lt;- Pwr &lt;- matrix(0, period2, length(filt))
  for (period in period1: period2) {
    for (N in 2: period2) {
      cosinePart[period, ] = cosinePart[period, ] + autocorr[N, ] * cos(2 * N * pi / period)
      sinePart[period, ] = sinePart[period, ] + autocorr[N, ] * sin(2 * N * pi / period)
    }
    sqSum[period, ] = cosinePart[period, ] ^ 2 + sinePart[period, ] ^ 2
    R[period, ] &lt;- EMA(sqSum[period, ] ^ 2, ratio = 0.2)
  }
  R[is.na(R)] &lt;- 0
  # Normalising Power
  K &lt;- AGC(period1, period2, 1.5)
  maxPwr &lt;- rep(0, length(filt))   for(period in period1: period2) {     for (i in 1: length(filt)) {       if (R[period, i] >= maxPwr[i]) maxPwr[i] &lt;- R[period, i]
      else maxPwr[i] &lt;- K * maxPwr[i]
    }
  }
  for(period in 2: period2) {
    Pwr[period, ] &lt;- R[period, ] / maxPwr
  }
  # Compute the dominant cycle using the Center of Gravity of the spectrum
  Spx &lt;- Sp &lt;- rep(0, length(filter))
  for(period in period1: period2) {
    Spx &lt;- Spx + period * Pwr[period, ] * (Pwr[period, ] >= 0.5)
    Sp &lt;- Sp + Pwr[period, ] * (Pwr[period, ] >= 0.5)
  }
  dominantCycle &lt;- Spx / Sp
  dominantCycle[is.nan(dominantCycle)] &lt;- 0
  dominantCycle &lt;- xts(dominantCycle, order.by=index(x))
  dominantCycle &lt;- dominantCycle[dominantCycle > 0]
  return(dominantCycle)
  #heatmap(Pwr, Rowv = NA, Colv = NA, na.rm = TRUE, labCol = &quot;&quot;, add.expr = lines(dominantCycle, col = 'blue'))
}
</pre>
<p>One thing I do notice is that this code uses a loop that says for(i in 1:length(filt)), which is an O(data points) loop, which I view as the plague in R. While I’ve used Rcpp before, it’s been for only the most basic of loops, so this is definitely a place where the algorithm can stand to be improved with Rcpp due to R’s inherent poor looping.</p>
<p>Those interested in the exact logic of the algorithm will, once again, find it in John Ehlers’s Cycle Analytics For Traders book (see link earlier in the post).</p>
<p>Of course, the first thing to do is to test how well the algorithm does what it purports to do, which is to dictate the lookback period of an algorithm.</p>
<p>Let’s run it on some data.</p>
<pre>
getSymbols('SPY', from = '1990-01-01')

t1 &lt;- Sys.time()
out &lt;- autocorrPeriodogram(Ad(SPY), period1 = 120, period2 = 252, avgLength = 3)
t2 &lt;- Sys.time() print(t2-t1) </pre>
<p>And the result:</p>
<pre> > t1 &lt;- Sys.time() > out &lt;- autocorrPeriodogram(Ad(SPY), period1 = 120, period2 = 252, avgLength = 3) > t2 &lt;- Sys.time() > print(t2-t1)
Time difference of 33.25429 secs
</pre>
<p>Now, what does the algorithm-set lookback period look like?</p>
<pre>
plot(out)
</pre>
<p><img src="https://i1.wp.com/cdn.discordapp.com/attachments/203286714720976896/274424333869252608/unknown.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>Let’s zoom in on 2001 through 2003, when the markets went through some upheaval.</p>
<pre>
plot(out['2001::2003']
</pre>
<p><img src="https://i2.wp.com/cdn.discordapp.com/attachments/203286714720976896/274424721582587906/unknown.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>In this zoomed-in image, we can see that the algorithm’s estimates seem fairly jumpy.</p>
<p>Here’s some code to feed the algorithm’s estimates of n into an indicator to compute an indicator with a dynamic lookback period as set by Ehlers’s autocorrelation periodogram.</p>
<pre>
acpIndicator &lt;- function(x, minPeriod, maxPeriod, indicatorFun = EMA, ...) {
  acpOut &lt;- autocorrPeriodogram(x = x, period1 = minPeriod, period2 = maxPeriod)
  roundedAcpNs &lt;- round(acpOut, 0) # round to the nearest integer
  uniqueVals &lt;- unique(roundedAcpNs) # unique integer values
  out &lt;- xts(rep(NA, length(roundedAcpNs)), order.by=index(roundedAcpNs))

  for(i in 1:length(uniqueVals)) { # loop through unique values, compute indicator
    tmp &lt;- indicatorFun(x, n = uniqueVals[i], ...)
    out[roundedAcpNs==uniqueVals[i]] &lt;- tmp[roundedAcpNs==uniqueVals[i]]
  }
  return(out)
}
</pre>
<p>And here is the function applied with an SMA, to tune between 120 and 252 days.</p>
<pre>
ehlersSMA &lt;- acpIndicator(Ad(SPY), 120, 252, indicatorFun = SMA)

plot(Ad(SPY)['2008::2010'])
lines(ehlersSMA['2008::2010'], col = 'red')
</pre>
<p>And the result:</p>
<p><img src="https://i2.wp.com/cdn.discordapp.com/attachments/203286714720976896/281138091207557120/unknown.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>As seen, this algorithm is less consistent than I would like, at least when it comes to using a simple moving average.</p>
<p>For now, I’m going to leave this code here, and let people experiment with it. I hope that someone will find that this indicator is helpful to them.</p>
<p>Thanks for reading.</p>
<p>NOTES: I am always interested in networking/meet-ups in the northeast (Philadelphia/NYC). Furthermore, if you believe your firm will benefit from my skills, please do not hesitate to reach out to me. My linkedin profile can be found <a target="_blank" rel="nofollow" href="https://www.linkedin.com/in/ilyakipnis?trk=nav_responsive_tab_profile">here</a>. </p>
<p>Lastly, I am volunteering to curate the R section for books on quantocracy. If you have a book about R that can apply to finance, be sure to let me know about it, so that I can review it and possibly recommend it. Thakn you.</p>
<p> <a target="_blank" rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/quantstrattrader.wordpress.com/501/"><img alt="" src="http://feeds.wordpress.com/1.0/comments/quantstrattrader.wordpress.com/501/" border="0"></a> <img alt="" src="https://i1.wp.com/pixel.wp.com/b.gif?resize=1%2C1&ssl=1" border="0" data-recalc-dims="1"></p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://quantstrattrader.wordpress.com/2017/02/15/ehlerss-autocorrelation-periodogram/"> R – QuantStrat TradeR</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/fkFKusY934U"></a></div>