In the article “The UniEMA: A Universal Exponential Moving Average” in this issue, Igor Durkin presents a universal EMA designed to manage the tradeoff between lag and noise. The approach consolidates EMA, DEMA, TEMA, and related smoothing methods into a single indicator controlled by four parameters. The EasyLanguage implementation contains two functions and two corresponding indicators. The UniEMA indicator plots a single universal EMA line, while the UniEMA Cascade indicator plots intermediate smoothing stages as a cascade. The UniEMA indicator can be applied multiple times with different inputs to compare varying degrees of smoothing and observe crossovers as turning points.
Code: Select all
Function: UniXMA
{*******************************************************
TASC NOV 2026
Description : UniXMA Function
Provided By : (C) 2011-2026 Igor Durkin, trendlaboratory.net
*******************************************************}
inputs:
price( numericseries ),
length( numericsimple ),
poles( numericsimple ),
order( NumericSimple ),
wf( numericsimple ),
df( NumericSimple );
variables:
alpha(0),
bet(0),
k(0),
j(0),
uniema(0),
uni_size(0);
arrays:
uniema_tmp[](0);
{ calculate alpha once—lag is preserved across all Order
values }
once
begin
alpha = wf*order / (length + wf*order - 1);
bet = 1 - alpha;
uni_size = poles * order;
Array_SetMaxIndex( uniema_tmp, uni_size - 1 );
end;
uniema = price;
if currentbar >= 1 then
begin
{ outer loop—Order passes }
for k=0 to order-1
begin
{ inner loop—Poles correction }
for j=0 to poles-1
begin
{ initialise filter state at first call }
if currentbar = 1 then
uniema_tmp[poles*k+j] = price
else
begin
uniema_tmp[poles*k+j] = bet
* uniema_tmp[poles*k+j][1]
+ alpha * uniema;
if j > 0 then
uniema = uniema
+ df
* (uniema_tmp[poles*k]
- uniema_tmp[poles*k+j])
else
uniema = uniema_tmp[poles*k+j];
end;
end;
end;
end;
UniXMA = uniema;
Function: UniXMA_arr
{*******************************************************
TASC NOV 2026
Description : UniXMA_arr Function
Provided By : (C) 2011-2026 Igor Durkin, trendlaboratory.net
*******************************************************}
inputs:
price( numericseries ),
length( numericsimple ),
poles( numericsimple ),
order( numericsimple ),
wf( numericsimple ),
df( numericsimple ),
outarray[n]( numericarrayref );
variables:
alpha( 0 ),
bet( 0 ),
k( 0 ),
j( 0 ),
uniema( 0 ),
uni_size( 0 );
arrays:
uniema_tmp[]( 0 );
{ calculate alpha once—lag is preserved across all Order
values }
once
begin
alpha = wf * order / (length + wf * order - 1);
bet = 1 - alpha;
uni_size = poles*order;
Array_SetMaxIndex(uniema_tmp, uni_size-1);
end;
uniema = price;
if currentbar >= 1 then
begin
{ outer loop—Order passes }
for k=0 to order-1
begin
{ inner loop—Poles correction }
for j=0 to poles-1 begin
{ initialise filter state at first call }
if currentbar = 1 then
uniema_tmp[poles*k+j] = price
else
begin
uniema_tmp[poles*k+j] = bet
* uniema_tmp[poles*k+j][1] + alpha * uniema;
if j > 0 then
uniema = uniema + df*(uniema_tmp[poles*k]
- uniema_tmp[poles*k+j])
else
uniema = uniema_tmp[poles*k+j];
end;
end;
outarray[k] = uniema;
end;
end;
UniXMA_arr = uniema;
Indicator: UniEMA
{*******************************************************
TASC NOV 2026
Description : This Indicator plots UniEMA
Provided By : (C) 2011-2026 Igor Durkin, trendlaboratory.net
*******************************************************}
inputs:
double Price( Close), // Applied to
int Length( 14 ), // Period
int Poles( 2 ), // Poles: 1-EMA, 2-DEMA, 3-TEMA, 4-QEMA
int Order( 3 ), // Smoothing Order (min. 1)
double WeightFactor( 2 ), // (Wilder=1,EMA=2)
double DampingFactor( 0.5 ), // Damping Factor (ex. 0.7)
int Displace( 0 ), // Displace in bars
bool ShowColorLine( true ), // Show Color Line
int UpTrendColor( blue ), // UpTrend Color
int DnTrendColor( red ), // DownTrend Color
int ColorBarsBack( 1 ); // Color Bars Back (0 or 1)
variable:
UniEMA( 0 ),
trend( 0 );
if Displace >= 0 or CurrentBar > AbsValue(Displace) then
begin
UniEMA = UniXMA(Price, Length, Poles, Order,
WeightFactor, DampingFactor);
Plot1[Displace]( UniEMA,"UniEMA" );
if ShowColorLine then
begin
trend = trend[1];
if UniEMA > UniEMA[1] then trend = 1;
if UniEMA < UniEMA[1] then trend = -1;
if trend > 0 then
SetPlotColor[Displace + ColorBarsBack]
(1, UpTrendColor);
if trend < 0 then
SetPlotColor[Displace + ColorBarsBack]
(1, DnTrendColor);
end;
if Displace <= 0 then
begin
if Price > UniEMA and UniEMA > UniEMA[1]
and UniEMA[1] <= UniEMA[2] then
Alert( "Indicator turning up" )
else if Price < UniEMA and UniEMA < UniEMA[1]
and UniEMA[1] >= UniEMA[2] then
Alert( "Indicator turning down" );
end;
end;
Indicator: UniEMA Cascade
{*******************************************************
TASC NOV 2026
Description : This Indicator plots UniEMA Cascade
Provided By : (C) 2011-2026 Igor Durkin, trendlaboratory.net
*******************************************************}
inputs:
double Price( Close ), // Applied to
int Length( 14), // Period
int Poles( 1 ), // Poles (min. 1)
int Order( 20 ), // Smoothing Order (min. 1)
double WeightFactor( 2 ), // (Wilder=1,EMA=2)
double DampingFactor( 0 ), // Damping Factor
int UpTrendColor( Green ), // UpTrend Color
int DnTrendColor( Red ); // DownTrend Color
variables:
int k( 0 ),
double UniEMA( 0 );
array:
smooths[](0),
trend[](0);
once
begin
Array_SetMaxIndex( smooths, Order - 1 );
Array_SetMaxIndex( trend, Order - 1 );
end;
if CurrentBar > 1 then
begin
UniEMA = UniXMA_arr( Price, Length, Poles, Order,
WeightFactor, DampingFactor, smooths);
for k = 0 to Order-1
begin
trend[k] = trend[k][1];
if smooths[k] > smooths[k][1] then
trend[k] = 1;
if smooths[k] < smooths[k][1] then
trend[k] = -1;
switch(k)
begin
case 0: Plot1( smooths[k],"Order #1" );
case 1: Plot2( smooths[k],"Order #2" );
case 2: Plot3( smooths[k],"Order #3" );
case 3: Plot4( smooths[k],"Order #4" );
case 4: Plot5( smooths[k],"Order #5" );
case 5: Plot6( smooths[k],"Order #6" );
case 6: Plot7( smooths[k],"Order #7" );
case 7: Plot8( smooths[k],"Order #8" );
case 8: Plot9( smooths[k],"Order #9" );
case 9: Plot10( smooths[k],"Order #10" );
case 10: Plot11( smooths[k],"Order #11" );
case 11: Plot12( smooths[k],"Order #12" );
case 12: Plot13( smooths[k],"Order #13" );
case 13: Plot14( smooths[k],"Order #14" );
case 14: Plot15( smooths[k],"Order #15" );
case 15: Plot16( smooths[k],"Order #16" );
case 16: Plot17( smooths[k],"Order #17" );
case 17: Plot18( smooths[k],"Order #18" );
case 18: Plot19( smooths[k],"Order #19" );
case 19: Plot20( smooths[k],"Order #20" );
end;
if trend[k] > 0 then
SetPlotColor[1]( k + 1, UpTrendColor)
else
SetPlotColor[1]( k + 1, DnTrendColor);
end;
end;
A sample chart is shown in Figure 1.
FIGURE 1: TRADESTATION. This shows a daily chart of the S&P 500 ETF SPY, showing a portion of 2026 with the UniEMA Cascade indicator applied.