Ehlers Indicators for TradeStation
Posted: Sun Dec 14, 2025 6:00 am
Code: Select all
{
TASC JAN 2026
Reversion Index
(C) 2005 John F. Ehlers
}
inputs:
Length( 20 );
variables:
DeltaSum( 0 ),
AbsDeltaSum( 0 ),
Count( 0 ),
Ratio( 0 ),
Smooth( 0 ),
Trigger( 0 );
DeltaSum = 0;
AbsDeltaSum = 0;
for Count = 0 to Length - 1
begin
DeltaSum = DeltaSum + Close[Count] - Close[Count + 1];
AbsDeltaSum = AbsDeltaSum + AbsValue( Close[Count]
- Close[Count + 1] );
end;
if AbsDeltaSum <> 0 then
Ratio = DeltaSum / AbsDeltaSum;
Smooth = $SuperSmoother( Ratio, 8 );
Trigger = $SuperSmoother( Ratio, 4 );
Plot1( Smooth, "Smooth" );
Plot2( 0, "Zero" );
Plot3( Trigger, "Triger" );
Function: $SuperSmoother
{
SuperSmoother Function
(C) 2025 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;
if CurrentBar >= 4 then
$SuperSmoother = c1*(Price + Price[1]) / 2
+ c2 * $SuperSmoother[1] + c3 * $SuperSmoother[2];
if CurrentBar < 4 then
$SuperSmoother = Price;
Code: Select all
Function: $PMA
{
TASC MAR 2025
Projected Moving Average ($PMA) Function
(C) 2024 John F. Ehlers
}
inputs:
Price( numericseries ),
Length( numericsimple ),
PMA( numericref ),
Slope( numericref ),
SMA( numericref );
variables:
Count( 0 ),
Sx( 0 ),
Sy( 0 ),
Sxx( 0 ),
Syy( 0 ),
Sxy( 0 );
Sx = 0;
Sy = 0;
Sxx = 0;
Syy = 0;
Sxy = 0;
for Count = 1 to Length
begin
Sx = Sx + Count;
Sy = Sy + Price[Count - 1];
Sxx = Sxx + Count * Count;
Syy = Syy + Price[Count - 1] * Price[Count - 1];
Sxy = Sxy + count*Price[Count - 1];
end;
Slope = -(Length * Sxy - Sx * Sy) / (Length * Sxx - Sx * Sx);
SMA = Sy / Length;
PMA = SMA + Slope * Length / 2;
//Function Return Value
$PMA = 1;
Indicator: Projected Moving Average (PMA)
{
TASC MAR 2025
Projected Moving Average (PMA)
(C) 2024 John F. Ehlers
}
inputs:
Length( 20 );
variables:
ReturnValue( 0 ),
PMA( 0 ),
Slope( 0 ),
SMA( 0 ),
Predict( 0 );
ReturnValue = $PMA(Close, Length, PMA, Slope, SMA);
Predict = PMA + .5 * (Slope - Slope[2])*Length;
Plot1( PMA, "PMA" );
Plot2( Predict, "Predict" );
//Plot3( SMA, "SMA" )
Indicator: PMA Slope and Prediction
{
TASC MAR 2025
PMA Slope and Its Prediction
(C) 2024 John F. Ehlers
}
inputs:
Length( 20 );
variables:
ReturnValue( 0 ),
PMA( 0 ),
Slope( 0 ),
SMA( 0 ),
Predict( 0 );
ReturnValue = $PMA(Close, Length, PMA, Slope, SMA);
Predict = 1.5 * Slope - .5 * Slope[4];
Plot1( Slope, "Slope" );
Plot2( 0, "Zero Line" );
Plot3( Predict, "Predict" );
Code: Select all
{
TASC SEPTEMBER 2025
Continuation Index
(C) 2025 John F. Ehlers
}
inputs:
Gama( .8 ),
Order( 8 ),
Length( 40 );
variables:
US( 0 ),
LG( 0 ),
Ref( 0 ),
Variance( 0 ),
CI( 0 );
//Ultimate Smoother
US = $UltimateSmoother(Close, Length / 2);
//Laguerre Filter
LG = $Laguerre(Close, Gama, Order, Length);
//Average the filter difference
Variance = Average(AbsValue(US - LG), Length);
//Double the normalized variance
if Variance <> 0 then
Ref = 2*(US - LG) / Variance;
//Compress using an Inverse Fisher Transform
CI = ( ExpValue(2 * Ref) - 1) / (ExpValue(2 * Ref) + 1);
plot1( CI );
Plot2( 0 );
Function: $Laguerre
{
Laguerre Filter Function
(C) 2005-2022 John F. Ehlers
Usage: $Laguerre(Price, gama, Order, Length);
` gama must be less than 1 and equal to or greater
than zero order must be an integer, 10 or less
}
inputs:
Price( numericseries ),
Gama( numericsimple ),
Order( numericsimple ),
Length( numericsimple );
variables:
Count( 0 ),
FIR( 0 );
arrays:
LG[10, 2]( 0 );
//load the current values of the arrays to be the values
// one bar ago
for count = 1 to order
begin
LG[count, 2] = LG[count, 1];
end;
//compute the Laguerre components for the current bar
for count = 2 to order
begin
LG[count, 1] = -gama*LG[count - 1, 2] + LG[count - 1, 2]
+ gama*LG[count, 2];
End;
LG[1, 1] = $UltimateSmoother(Price, Length);
//sum the Laguerre components
FIR = 0;
for count = 1 to order
begin
FIR = FIR + LG[count, 1];
end;
$Laguerre = FIR / order;
Function: $SuperSmoother
{
UltimateSmoother Function
(C) 2004-2025 John F. Ehlers
}
inputs:
Price( numericseries ),
Period( numericsimple );
variables:
a1( 0 ),
b1( 0 ),
c1( 0 ),
c2( 0 ),
c3( 0 ),
US( 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
US = (1 - c1)*Price + (2 * c1 - c2) * Price[1]
- (c1 + c3) * Price[2] + c2*US[1] + c3 * US[2];
if CurrentBar < 4 then
US = Price;
$UltimateSmoother = US;
Code: Select all
{
TASC DEC 2025
One Euro Filter Indicator
From "1€ Filter: A Simple Speed-Based Low-Pass Filter
For Noisy Input In Interactive Systems" (CHI 2012)
By Georges Casiez, Nicolas Roussel, and Daniel Vogel
(C) 2025 John F. Ehlers
}
inputs:
PeriodMin( 10 ), // Minimum cutoff frequency
BetaVal( 0.2 ); // Responsiveness factor
variables:
Price( 0 ),
PeriodDX( 10 ),
AlphaDX( 0 ),
SmoothedDX( 0 ),
Cutoff( 0 ),
Alpha3( 0 ),
Smoothed( 0 );
Price = Close;
AlphaDX = 2 * 3.14159 / (4 * 3.14159 + PeriodDX);
// Initialize
if CurrentBar = 1 then
begin
SmoothedDX = 0;
Smoothed = Price;
end;
// EMA the Delta Price
SmoothedDX = AlphaDX * (Price - Price[1]) + (1 -
AlphaDX) * SmoothedDX[1];
// Adjust cutoff period based on fraction of the rate of
// change
Cutoff = PeriodMin + BetaVal * AbsValue(SmoothedDX);
// Compute adaptive alpha
Alpha3 = 2*3.14159 / (4 * 3.14159 + Cutoff);
//Adaptive smoothing
Smoothed = Alpha3 * Price + (1 - Alpha3) * Smoothed[1];
//Plot
Plot1( Smoothed );
Code: Select all
{
TASC JUN 2025
Cybernetic Oscillator
(C) 2025 John F. Ehlers
}
inputs:
HPLength( 30 ),
LPLength( 20 );
variables:
HP( 0 ),
LP( 0 ),
RMS( 0 ),
CyberneticOsc( 0 );
HP = $HighPass(Close, HPLength);
LP = $SuperSmoother(HP, LPLength);
RMS = $RMS(LP, 100);
if RMS <> 0 then
CyberneticOsc = LP / RMS;
Plot1( CyberneticOsc, "Cybernetic Osc" );
Plot2( 0, "Zero Line" );
Function: $HighPass
{
$HighPass Function
(C) 2004-2025 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: $SuperSmoother
{
$SuperSmoother Function
(C) 2004-2025 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;
if CurrentBar >= 4 then
$SuperSmoother = c1*(Price + Price[1]) / 2
+ c2 * $SuperSmoother[1] + c3 * $SuperSmoother[2];
if CurrentBar < 4 then
$SuperSmoother = Price;
Indicator: $RMS
{
RMS Function
(C) 2015-2025 John F. Ehlers
}
inputs:
Price( numericseries ),
Length( numericsimple );
variables:
SumSq( 0 ),
count( 0 );
SumSq = 0;
for count = 0 to Length - 1
begin
SumSq = SumSq + Price[count] * Price[count];
end;
If SumSq <> 0 then
$RMS = SquareRoot(SumSq / Length);
This infographics you are providing with your indicators are awesome. The information and the visuals. Thanks for sharing.
John Ehlers is like an electronic professor, and we’re attending his college classes.Abdi wrote: Fri Dec 26, 2025 10:01 pm This infographics you are providing with your indicators are awesome. The information and the visuals. Thanks for sharing.
And you are making it perfectly digestable for us slow leanersBanzai wrote: Sat Dec 27, 2025 2:28 am John Ehlers is like an electronic professor, and we’re attending his college classes.![]()