There are already uncounted variants of moving averages. Vitali Apirine invented another one in his article in the Stocks&Commodities September issue. The LREMA is an EMA with a variable period derived from the distance of the current price and a linear regression line. This ensures an optimal EMA period at any point – at least in theory. Will this complex EMA variant beat the standard EMA for detecting trend changes?
The LR_EMA indicator can be directly converted from Apirine’s MetaStock to C:
var LREMA(int Periods,int Pds,var Mltp)
{
var Mltp1 = 2./(Periods+1);
var LR = LinearReg(seriesC(),Pds);
vars Dists = series(abs(LR-priceC()));
var ST = (Dists[0]-MinVal(Dists,Pds))/
max(MaxVal(Dists,Pds)-MinVal(Dists,Pds),0.01);
var Rate = min(1.,Mltp1*(1+ST*Mltp));
return EMA(priceC(),Rate);
}
The max and min functions prevent divisions by zero and EMA alpha parameters (Rate) above 1. This can otherwise happen at the begin of the backtest when price series are still flat.
The LREMA(20,20,5) and EMA(20) applied on SPY replicates the chart in Apirine’s article:
We can see that the LREMA (blue line) follows the price more closely than the EMA (red line). Which is not really surprising, because LREMA period is smaller at most places. But how good can the LREMA identify trend changes in a real trading system?
For testing this, we write a simple SPY system that concurrently trades with EMA, and with LREMA. A single position is entered when the faster EMA crosses over a slower EMA, and closed when it crosses back. The LREMA is used likewise. For not comparing apples with oranges, we optimize all time periods and test with walk-forward analysis. The code of this trading system in C:
void run() { BarPeriod = 1440; LookBack = 200; StartDate = 2005; EndDate = 2022; assetList("AssetsIB"); asset("SPY"); // walk-forward optimization setup set(PARAMETERS,TESTNOW,PLOTNOW); NumWFOCycles = 8; // run a loop over the two algos while(algo(loop("LR_EMA","EMA"))) { vars Signals1, Signals2; int Color; // optimize time periods int Period1 = optimize(20,10,50,10); int Period2 = Period1*optimize(2.5,1.5,3,0.5); if(Algo == "LR_EMA") { Signals1 = series(LREMA(Period1,Period1,5)); Signals2 = series(LREMA(Period2,Period2,5)); Color = BLUE; } else if(Algo == "EMA") { Signals1 = series(EMA(seriesC(),Period1)); Signals2 = series(EMA(seriesC(),Period2)); Color = GREY; } // trade on fast/slow crossovers if(crossOver(Signals1,Signals2)) enterLong(); if(crossUnder(Signals1,Signals2)) exitLong(); // plot equity curve plot(Algo,ProfitOpen+ProfitClosed,LINE+AXIS2,Color); } }
This script trades two different algos and compares the resulting equity curves. The fast and slow periods are optimized separately for both algorithms. The slow period is the fast period multiplied with a factor. This guarantees that the slow period is always bigger than the fast period during the optimization. The system must be first trained by clicking the [Train] button on the Zorro panel. After training, it automatically starts a backtest with walk-forward analysis.
Training and analysis take about 2 seconds. The resulting equity curve is plotted in a blue line for the LR_EMA algo, and in a grey line for the standard EMA algo:
We can see that both algorithms yield a positive result, but the standard EMA a bit more so than the LR_EMA. Not only the profit is smaller, the drawdowns are also worse with the new invented indicator – which is probably the reason why the article, like almost any article about a new indicator, did not contain an example system or a backtest. But maybe the walk-forward period optimization was simply more effective on the fixed-period EMA, than on the variable-period LR_EMA. If so, then the LR_EMA would fare better with unoptimized systems.
The LREMA indicator and the EMA/LREMA trading system can be downloaded from the 2022 script repository.
2 thoughts on “The Linear Regression-Adjusted Exponential Moving Average”