Designing a zero lag indicator
Filter Design September 23rd. 2007, 4:21pmThe problem with indicators and oscillators is that they suffer lag. For instance, a 19-bar moving average has a 9-bar lag i.e almost half the filter length. Exponential moving averages also suffer lag which varies over the sampling frequency range. The are many reasons why one should opt for a minimum lag indicator when filtering input data to a neural network. Generally speaking, you would not want your neural network to learn the lag present in the input data, or atleast you want to minimise this as much as possible. Here I describe a way of deriving an almost zero lag indicator in the Z-domain, as outlined in [Ehlers]
The time domain difference equation for an EMA is
![]()
where alpha is a number between 0 and 1. Taking the z-transform of both sides and re-arranging we get
![]()
I want to create a high-pass filter using the z-domain expression for the low-pass EMA filter. Hence I subtract the expression from 1. The reasoning behind this is that a filter with transfer response 1 represents all frequencies. Hence the residual of subtracting a low-pass filter from 1 should be a high-pass filter. But care must be taken. The transfer response of the EMA does not cover all frequencies right through to infinity because it is 0 at the nyquist frequency (i.e. when z = -1). Doing a direct subtraction would lead to a gain error in the frequency response. To eleminate this problem we take two sequential inputs and average them together, rather than using one input sample at a time. Thus the transfer response as a result of averaging becomes
![]()
We can now subtract this equation from 1 without fear of getting a gain error. Thus we have
![]()
![]()
![]()
Inorder to improve attenuation of the derived high-pass filter, we increase its order. But increasing the order of a filter is equivalent to introducing lag. However, the second-order Gaussain filter suffers the least amount of lag amongst all second order filters. Squaring the above equation would yield a second-order Gaussain filter. Thus we have
![]()
If we apply this filter to price data, we would essentially see cyclic components at the output. We are interested in trending components, or the low-pass components because we are designing a low-pass indicator filter. Hence we subtract the above equation from 1 again. After much simplification we get
![]()
By inspection we see that the number of delay operators in the numerator and denominator are equal. This implies the filter has zero lag. Hence we have derived an indicator with zero lag. The simulations below show different characteristics of the filter. I have also shown an equivalent MA filter for comparison purposes, since the lag relationship between an EMA and a MA is governed by the following equation
![]()
The impulse respose of our new filter is finite, unlike an its equivalent EMA filter. This shows our new filter demonstrates short memory over finite duration, which might be a desired feature if too many past values are not required to be remembered.
The frequency response of our new filter is comparable to that of its EMA counterpart. Notice that the attenuation at nyquist frequency is an asymptote. That is the benefit of taking two sequential input samples in deriving the new filter.
And now the most important graph - showing the filter lags:
We have successfully designed a filter with virtually zero lag.
Filter design summary
- Get z-domain EMA filter equation for general alpha.
- Convert z-domain EMA equation to take two sequential inputs at a time so as to eliminate gain error.
- Subtract expression from 1 to get high-pass filter.
- Convert expression to 2nd order Gaussain inorder to improve filter attenuation.
- Finally subtract expression from 1 to get your zero lag low-pass filter.
In my next post I shall compare the performace of our new filter using real price time-series.

November 11th, 2007 at 3:44 pm
Your lowpass filter with transfer function HPnew(z) is very similar to existing lowpass filters. To be precise, let
H(z) denote the transfer function of your initial lowpass filter. Subtracting H(z) from 1, squaring the result, and then subtracting it from 1 gives:
HPnew(z) = 1 - (1-H(z))^2 (where ^2 means square)
HPnew(z) = 1 - (1 - 2H(z) + H(z)^2)
HPnew(z)= 2H(z) - H(z)^2 = (2 - H(z))H(z)
This filter has exactly the same form as that of the DEMA filter developed by Patrick Mulloy in 1994, where in Mulloy’s work H(z) is the transfer function of the EMA filter. Other individuals have also used this same form with different choices for H(z).
November 11th, 2007 at 10:28 pm
Hi Edward,
The lowpass filter shown here is similar to others because Zero lag filters rely on having a general form:
where
and
can only be zero if they belong to the same 
The key is to ensure that the powers of
cancel eachother out in the denominator and numerator. The coefficients then determine the attenuation and lag characteristics the filter at different frequencies. In this case the coefficients are related via a common alpha value which acts as the tuning parameter.
As you have mentioned the choice for H(z) is flexible and tuning this allows one to create very short length filters with minimum lag. Infact this now inspires me to investigate noncausal filters.
I shall look up Mulloy’s work.
January 14th, 2008 at 8:04 pm
…And for us curious Matlab beginners: How could one go forth and implement this in Matlab? Which parts shall I look up in the help section…?
PS. Great blog! / Carl.
January 14th, 2008 at 10:31 pm
Hi Carl,
Its very simple if you have access to the Signal Processing toolbox. But one can still go about writing an m-function without any dependencies to any toolbox. I will cover this in a post at some point.
January 22nd, 2008 at 10:54 pm
[…] been investigating ways of reducing lag in these filters, buliding upon the results I got in a previous post where I showed how to design a a zero-lag indicator from first principles. It seems something can […]
March 4th, 2008 at 3:48 pm
Your topic about the design of a zero-lag indicator is very interesting! I would like to adress the same remark as Carl did: how can we (as starting MATLAB users) go forth and try some of your concepts in reality? Do you have some conceptual M-code available?
March 10th, 2008 at 7:53 am
I shall talk about this in my next post.