Links: |TradingView|TradeStation|NinjaTrader|MT4|MT5|Python|
TradeStation: April 2026
In “A Synthetic Oscillator” in this issue, John Ehlers introduces a nonlinear oscillator designed to reduce lag while maintaining smooth, responsive trading signals. The indicator adapts to changing market conditions by measuring the instantaneous dominant cycle and generating signals through a phase-based sine waveform.
EasyLanguage code for the indicator is shown here and a sample chart plotting the indicator is shown in the code below.
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: $RMS
{
$RMS Function
(C) 2025 John F. Ehlers
}
inputs:
Price( numericseries ),
Length( numericsimple );
variable:
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);
Function: $SuperSmoother
{
$SuperSmoother Function
(C) 2025 John F. Ehlers
}
inputs:
Price( numericseries ),
Period( numericsimple );
variables:
A0( 0 ),
Q( 0 ),
C1( 0 ),
C2( 0 );
Q = ExpValue( -1.414*3.14159 / Period );
C1 = 2 * Q * Cosine(1.414*180 / Period);
C2 = Q*Q;
A0 = (1 - c1 + c2) / 2;
if CurrentBar >= 4 Then $SuperSmoother = A0*( Price +
Price[1]) + C1 * $SuperSmoother[1] - C2 * $SuperSmoother[2];
if Currentbar < 4 then
$SuperSmoother = Price;
Function: $Hann
{
$Hann Windowed Lowpass FIR Filter Function
(c) 2025 John F. Ehlers
}
inputs:
Price( numericseries ),
Length( numericsimple );
variables:
count(0),
coef(0),
Filt(0);
Filt = 0;
coef = 0;
for count = 1 to Length
begin
Filt = Filt + (1 - Cosine(360*count / (Length +
1)))*Price[count - 1];
coef = coef + (1 - Cosine(360*count / (Length + 1)));
end;
if coef <> 0 then
$Hann = Filt / coef;
Function $UltimateSmoother
{
UltimateSmoother Function
(C) 2004-2024 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;
Indicator: Synthetic Oscillator
{
TASC APR 2026
Synthetic Oscillator Indicator
(C) 2025 John F. Ehlers
}
inputs:
LowerBound( 15 ),
UpperBound( 25 ),
Length( 4 );
variables:
Price( 0 ),
HP( 0 ),
LP( 0 ),
RMS( 0 ),
Real( 0 ),
ROC( 0 ),
QRMS( 0 ),
Imag( 0 ),
Denom( 0 ),
DC( 0 ),
Count( 0 ),
Mid( 0 ),
HP2( 0 ),
BP( 0 ),
Phase( 0 ),
Synth( 0 ),
Synth2( 0 ),
ROC2( 0 );
Price = $Hann( Close, 12 );
{ Real component is bandpass filtered and normalized }
HP = $HighPass( Price, UpperBound );
LP = $SuperSmoother( HP, LowerBound );
RMS = $RMS( LP, 100 );
if RMS <> 0 then
Real = LP / RMS;
{ Imaginary component is rate of change normalized }
ROC = Real - Real[ 1 ];
QRMS = $RMS( ROC, 100 );
if QRMS <> 0 then
Imag = ROC / QRMS;
{ Solve rate of change of arctangent }
Denom = ( ( Real - Real[ 1 ] ) * Imag )
- ( ( Imag - Imag[ 1 ] ) * Real );
if Denom <> 0 then
DC = 6.28 * ( ( Real * Real )
+ ( Imag * Imag ) ) / Denom;
{ Limit range of measured values }
if DC < LowerBound then
DC = LowerBound;
if DC > UpperBound then
DC = UpperBound;
Mid = SquareRoot( LowerBound * UpperBound );
{ Create a bandpass filter at the average dominant cycle period }
HP2 = $HighPass( Close, Mid );
BP = $UltimateSmoother( HP2, Mid );
{ Cumulate phase and force reset at 0 and 180 degrees }
Phase = Phase + ( 360 / DC );
if BP crosses over 0 then
Phase = 180 / DC;
if BP crosses under 0 then
Phase = 180 + ( 180 / DC );
{ Synthetic oscillator is the sine of the cumulative phase angle }
Synth = Sine( Phase );
{ Remove reset glitch if continuity falls in the same quadrant }
if Phase > 0 and Phase < 90 and Synth < Synth[ 1 ] then
Synth = Synth[ 1 ];
if Phase > 180 and Phase < 270 and Synth > Synth[ 1 ] then
Synth = Synth[ 1 ];
plot1( Synth );
plot2( 0 );
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.