A band-pass filter is one of the cleanest ways to isolate the cyclic part of a price series: it removes the trend and the high frequency noise and keeps only the swings around a chosen period. Its weakness is that you have to choose that period, and the dominant cycle of a market does not sit still. A filter tuned to 20 bars is lagging and distorted when the market is swinging every 12.
The AutoTune Filter, presented by John F. Ehlers in the May 2026 issue of Technical Analysis of Stocks & Commodities (“A Rolling Autocorrelation Function”), solves this by measuring the dominant cycle on every bar and re-centering the band-pass filter on it. The result is an oscillator that follows the rhythm the market is actually showing, not the one you guessed when you set the parameter.
The price first goes through Ehlers’ two-pole high-pass filter with a cutoff equal to the window period. What survives is a zero-centred series made of the swings shorter than that period, with the trend removed.
On that high-pass series the indicator computes the correlation between the last window bars and the same window shifted by 1, 2, 3… up to window bars. This is a rolling autocorrelation function, recalculated on every bar.
The key idea is simple: if the market is cycling with a period P, the series shifted by half a cycle (P/2 bars) is in phase opposition with itself, so the correlation at that lag is the most negative of all. Find the lag with the lowest correlation, double it, and you have the dominant cycle.
The measured cycle is allowed to move by at most 2 bars per bar. This keeps the filter stable when the autocorrelation minimum jumps from one lag to another in noisy conditions.
Finally, Ehlers’ band-pass filter is applied to the price with its centre period set to the dominant cycle of the current bar and a bandwidth of 0.25. This is the AutoTune Filter.
window, that controls both the high-pass cutoff and the range of cycles that can be detected (up to twice the window)
window (default: 20, minimum 3): high-pass filter period and length of the autocorrelation window. Cycles up to twice this value can be detected.dispType (default: 3): output to display. 0 = high-pass filter, 1 = minimum correlation, 2 = dominant cycle, 3 = tuned band-pass filter.bw (default: 0.25): bandwidth of the band-pass filter. Lower values give a narrower, smoother filter; higher values let more frequencies through.Apply the indicator in its own panel below the price chart.
//---------------------------------------------------------------
//PRC_AutoTune Filter
//version = 0
//24.09.2026
//Iván González @ www.prorealcode.com
//Author: John F. Ehlers
//Sharing ProRealTime knowledge
//--------------------------------------------------------------------//
// Apply it in its own panel (not on the price).
//----- Inputs
window = 20 // high-pass period and autocorrelation window (min 3)
dispType = 3 // 0 = high-pass filter, 1 = min. correlation, 2 = dominant cycle, 3 = tuned band-pass filter
bw = 0.25 // bandwidth of the band-pass filter
src = customclose
window = max(3, round(window))
//----- High-pass filter (ProBuilder trigonometry works in degrees)
wRad = 1.414 * 3.14159265 / window
qHp = exp(0 - wRad)
c1Hp = 2 * qHp * cos(1.414 * 180 / window)
c2Hp = qHp * qHp
a0Hp = 0.25 * (1 + c1Hp + c2Hp)
IF barindex >= 4 THEN
hp = a0Hp * (src - 2 * src[1] + src[2]) + c1Hp * hp[1] - c2Hp * hp[2]
ELSE
hp = 0
ENDIF
//----- Rolling autocorrelation of the high-pass series, lags 1..window
sx = summation[window](hp)
sxx = summation[window](hp * hp)
minCorr = 2
minLag = 1
FOR lagV = 1 TO window DO
corr = 1
IF barindex >= window - 1 + lagV THEN
sy = sx[lagV]
syy = sxx[lagV]
sxy = 0
FOR cV = 0 TO window - 1 DO
sxy = sxy + hp[cV] * hp[cV + lagV]
NEXT
covV = window * sxy - sx * sy
vx = window * sxx - sx * sx
vy = window * syy - sy * sy
den = vx * vy
IF den > 0 THEN
corr = covV / sqrt(den)
ENDIF
ENDIF
// first lag with the lowest correlation
IF corr < minCorr THEN
minCorr = corr
minLag = lagV
ENDIF
NEXT
//----- Dominant cycle: twice the lag of lowest correlation, moving 2 bars at most per bar
dc = minLag * 2
IF barindex > 0 THEN
dc = min(max(dc, dc[1] - 2), dc[1] + 2)
ENDIF
//----- Band-pass filter tuned to the dominant cycle
l1Bp = cos(360 / dc)
g1Bp = cos(360 * bw / dc)
s1Bp = 1 / g1Bp - sqrt(1 / (g1Bp * g1Bp) - 1)
IF barindex >= 3 THEN
bp = 0.5 * (1 - s1Bp) * (src - src[2]) + l1Bp * (1 + s1Bp) * bp[1] - s1Bp * bp[2]
ELSE
bp = 0
ENDIF
//----- Output
IF dispType = 0 THEN
outV = hp
ELSIF dispType = 1 THEN
outV = minCorr
ELSIF dispType = 2 THEN
outV = dc
ELSE
outV = bp
ENDIF
RETURN outV COLOURED(41, 98, 255) AS "Series", 0 COLOURED(120, 123, 134) STYLE(dottedline2) AS "Zero line"
Most cycle tools ask you to choose the period. The AutoTune Filter measures it on every bar with a rolling autocorrelation and tunes itself accordingly, which makes it a practical way to follow the rhythm of a market as it changes.