Attachments forums

Re: Ehlers Indicators for TradeStation

Banzai, Wed Apr 15, 2026 6:25 am

The AutoTune Filter

Links: |TradingView|TradeStation|NinjaTrader|MT4|MT5|Python|

TradeStation: May 2026
In “The AutoTune Filter” in this issue, John Ehlers presents an adaptive filter that measures dominant market cycles using rolling autocorrelation, then tunes a bandpass filter to produce smoother, more consistent mean-reversion signals with reduced phase distortion. The tuned bandpass output highlights peaks and troughs that can help identify potential market turning points. In the EasyLanguage code, plots 3, 4, and 5 of the charts have been commented out but can be enabled to display additional values, including the minimum autocorrelation used in cycle detection, resulting dominant cycle length, and tuned bandpass output.

Code: Select all

Function: $HighPass

{
	$HighPass Function
 	(C) 2004-2024 John F. Ehlers
}

inputs:
	Price(numericseries),
	Period(numericsimple);
	
variables:
	a1( 0 ),
	b1( 0 ),
	c1( 0 ),
	c2( 0 ),
	c3( 0 );

a1 = ExpValue(-1.414 * 3.14159 / Period);
b1 = 2 * a1 * Cosine(1.414 * 180 / Period);
c2 = b1;
c3 = -a1 * a1;
c1 = (1 + c2 - c3) / 4;

if CurrentBar >= 4 then 
 	$HighPass = c1*(Price - 2 * Price[1] + Price[2]) +
	 c2 * $HighPass[1] + c3 * $HighPass[2];
if Currentbar < 4 then 
	$HighPass = 0;


Function: $BandPass

{
	Bandpass Function
	(C) 2005 - 2022 John F. Ehlers
}

inputs:
	Price( NumericSeries ),
	Period( NumericSimple ),
	Bandwidth( NumericSimple );

variables:
	G1( 0 ),
	S1( 0 ),
	L1( 0 ),
	BP( 0 );

L1 = Cosine( 360 / Period );
G1 = Cosine( Bandwidth * 360 / Period );
S1 = 1 / G1 - SquareRoot( 1 / (G1 * G1) - 1 );
BP = .5 * (1 - S1) * (Price - Price[2]) 
 + L1 * (1 + S1) * BP[1] - S1 * BP[2];

if CurrentBar < 3 then
begin
	BP = 0;
end;

$BandPass = BP;

Indicator: AutoTune

{
	TASC MAY 2026
	AutoTune Indicator
	(C) 2025 John F. Ehlers
}

inputs:
	Window( 20 );

variables:
	Filt( 0 ),
	Lag( 0 ),
	J( 0 ),
	Sx( 0 ),
	Sy( 0 ),
	Sxx( 0 ),
	Sxy( 0 ),
	Syy( 0 ),
	X( 0 ),
	Y( 0 ),
	MinCorr( 0 ),
	DC( 0 ),
	BP( 0 );

arrays:
	Corr[100]( 0 );

Filt = $Highpass( Close, Window );
//Cycle test waveform
//Filt = Sine(360*CurrentBar / 20);
 
//>>>>>>>>> Correlation >>>>>>>>>>>>
for Lag = 1 to Window
begin
	Sx = 0;
	Sy = 0;
	Sxx = 0;
	Sxy = 0;
	Syy = 0;

	for J = 0 to Window - 1
	begin
		X = Filt[J];
		Y = Filt[Lag + J];
		Sx = Sx + X;
		Sy = Sy + Y;
		Sxx = Sxx + X * X;
		Sxy = Sxy + X * Y;
		Syy = Syy + Y * Y;
	end;

	if (Window * Sxx - Sx * Sx > 0) and( Window * Syy -
	Sy * Sy > 0) then Corr[Lag] = (Window * Sxy - Sx * Sy) /
	SquareRoot( (Window * Sxx - Sx * Sx)
	* (Window * Syy - Sy * Sy));
end;

//Find minimum correlation and Dominant Cycle
MinCorr = 1;

for Lag = 1 to Window
begin
	if Corr[Lag] < MinCorr then
	begin
		MinCorr = Corr[Lag];
		DC = 2 * Lag;
	end;
end;

if DC > DC[1] + 2 then
begin
	DC = DC[1] + 2;
end;

if DC < DC[1] - 2 then
begin
	DC = DC[1] - 2;
end;

BP = $Bandpass( Close, DC, .25 );

Plot1( 0, "Zero Line" );
Plot2( Filt, "Filt" );

//Plot3(MinCorr, "", blue, 4, 4);
//Plot4(DC, "", blue, 4, 4);
//Plot5(BP, "", blue, 4, 4);

Strategy: AutoTune Pro Forma

{
AutoTune Pro Forma Strategy
(C) 2025 John F. Ehlers
}
inputs:
	BegDate( 1090101 ),
	EndDate( 1251231 ),
	Window( 26 ),
	BW( .22 ),
	Thresh( -.22 ),
	Delay( 0 );

variables:
	Filt( 0 ),
	Lag( 0 ),
	J( 0 ),
	Sx( 0 ),
	Sy( 0 ),
	Sxx( 0 ),
	Sxy( 0 ),
	Syy( 0 ),
	X( 0 ),
	Y( 0 ),
	MinCorr( 0 ),
	DC( 0 ),
	BP( 0 ),
	ROC( 0 );

arrays:
	Corr[100]( 0 );

Filt = $Highpass( Close, Window );

//>>>>>>>>> Correlation >>>>>>>>>>>>
for Lag = 1 to Window
begin
	Sx = 0;
	Sy = 0;
	Sxx = 0;
	Sxy = 0;
	Syy = 0;

	for J = 0 to Window - 1
	begin
		X = Filt[J];
		Y = Filt[Lag + J];
		Sx = Sx + X;
		Sy = Sy + Y;
		Sxx = Sxx + X * X;
		Sxy = Sxy + X * Y;
		Syy = Syy + Y * Y;
	end;

	if (Window * Sxx - Sx * Sx > 0) 
	 and (Window * Syy - Sy * Sy > 0) then 
	 	Corr[Lag] = (Window * Sxy - Sx * Sy) /
	 	 SquareRoot( (Window * Sxx - Sx * Sx) 
	 	 * (Window * Syy - Sy * Sy) );
end;

//Find minimum correlation and Dominant Cycle
MinCorr = 1;

for Lag = 1 to Window
begin
	if Corr[Lag] < MinCorr then
	begin
		MinCorr = Corr[Lag];
		DC = 2 * Lag;
	end;
end;

if DC > DC[1] + 2 then
begin
	DC = DC[1] + 2;
end;

if DC < DC[1] - 2 then
begin
	DC = DC[1] - 2;
end;

BP = $Bandpass( Close, DC, BW );
ROC = BP - BP[2];

if ROC crosses over 0 and MinCorr < Thresh then
	Buy Next Bar On Open;

if ROC crosses under 0 and MinCorr < Thresh and Filt > 0 then 
	Sell Short Next Bar on Open;
A sample chart is shown in Figure 1. FIGURE 1: TRADESTATION. Demonstrated here is a daily chart of the emini S&P 500 continuous futures contract showing a portion of 2020 with the indicator and strategy applied.

This article is for informational purposes. No type of trading or investment recommendation, advice, or strategy is being made, given, or in any manner provided by TradeStation Securities or its affiliates.
All files in topic