LowPass filter formula

Posted By: sabgto

LowPass filter formula - 10/16/12 18:22

In the help manual I read that LowPass filter is better than EMA and it seems to be that it is true.
What is the LowPass() formula ?. Can I see the source code of this function ?. I've been searching with google and only found eletronics related topics.
Posted By: stevegee58

Re: LowPass filter formula - 10/16/12 22:45

Code:
var smoothF(int period) { return 2./(period+1); }

var LowPass(var *Data,int Period)
{
	var* LP = series(*Data,3);
	var a = smoothF(Period);
	var a2 = a*a;
	return LP[0] = (a-0.25*a2)*Data[0]
		+ 0.5*a2*Data[1]
		- (a-0.75*a2)*Data[2]
		+ 2*(1.-a)*LP[1]
		- (1.-a)*(1.-a)*LP[2];
}

Posted By: gfx

Re: LowPass filter formula - 10/17/12 03:47

I understand just enough about digital filters to be dangerous laugh but not enough to understand the derivation. But no worries, don't need to know the derivation to use it.

What's smoothF(), Steve?
Posted By: BySharDe

Re: LowPass filter formula - 10/17/12 09:09

LowPass, is it the well-known concept in Image Processing?
BTW, what is EMA?
Posted By: sabgto

Re: LowPass filter formula - 10/17/12 16:49

Thanks stevegee58.
EMA = Exponential Moving Average
Posted By: sabgto

Re: LowPass filter formula - 10/18/12 16:23

I'd like to write this function (LowPass) in Mql4 in order to plot on MT4 but I found that I don't understand the "series" function.

var smoothF(int period) { return 2./(period+1); }

var LowPass(var *Data,int Period)
{
var* LP = series(*Data,3);
var a = smoothF(Period);
var a2 = a*a;
return LP[0] = (a-0.25*a2)*Data[0]
+ 0.5*a2*Data[1]
- (a-0.75*a2)*Data[2]
+ 2*(1.-a)*LP[1]
- (1.-a)*(1.-a)*LP[2];
}

What does exactly do this line ?
var* LP = series(*Data,3);
LP is a 3 element array filled with "what" of "*Data" ?
I thought that was filled with the first 3 elements of "*Data" but it seems to be that it's not true.

Could someone help me with this ?
Thanks.
Posted By: jcl

Re: LowPass filter formula - 10/19/12 07:29

A series is a special version of an array, used in commercial trade platforms. It's first element is filled with *Data and the array is shifted by 1 on every bar.

http://zorro-trader.com/manual/en/series.htm
Posted By: sabgto

Re: LowPass filter formula - 10/19/12 17:34

With the following code:
***********************************************************
var smoothF(int period) { return 2./(period+1); }

var LowPassX(var *Data,int Period)
{
char txt[80];
var* LP = series(*Data,3);
// just to get the "Data" and "LP" values in a file
sprintf(txt, "%.5f, %.5f, %.5f, %.5f, %.5f, %.5f, %.5f%c%c",
Data[0], Data[1], Data[2], Data[3], LP[0], LP[1], LP[2], 0x0D, 0x0A);
file_append("c:/t/output.txt", txt);

var a = smoothF(Period);
var a2 = a*a;

return LP[0] = (a-0.25*a2)*Data[0]
+ 0.5*a2*Data[1]
- (a-0.75*a2)*Data[2]
+ 2*(1.-a)*LP[1]
- (1.-a)*(1.-a)*LP[2];
}

function run(){

BarPeriod = 1440;
StartDate = 20120301;
NumDays = 10;
var Period;

var* pH = series(priceHigh());
Period = 5;
var LP0 = LowPassX(pH,3*Period);

plot("LP0", LP0, 0, BLUE);

}
***********************************************************
I got this data (only de first 10 records are shown):

Data[0] is the price from today, data[1] the price from yesterday, data[2] the price from day before yesterday, etc. “LP” is taken from “data”.
var* LP = series(*Data,3);
LP[0] = Data[0], LP[2] comes from the previous value of LP[1] but the question is respect LP[1], where does the value of LP[1] come from ?. The value 1.33375, resalted in the image, where was it taken from ?

What I’m trying to do is to replace “series(*Data,3)” with another kind of code.

Thanks a lot for your help and your patience.

P.D. I don't know how to put my code in a "code box", sorry.
Posted By: jcl

Re: LowPass filter formula - 10/20/12 07:01

Look at your code: you're first printing the value and then calculate it. That's why your LP[1] is in fact LP[0].
Posted By: deweymcg

Re: LowPass filter formula - 11/05/12 04:39

I have been trying to find an equivalent indicator for use with metatrader but no luck so far. The one I found has the following (which seems different):

Code:
//---- indicator settings
#property indicator_chart_window 
#property indicator_buffers 3 
#property indicator_color1 Yellow 
#property indicator_color2 LightBlue 
#property indicator_color3 Tomato 
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 2 
//---- indicator parameters
extern int     Price          = 0;  //Price mode : 0-Close,1-Open,2-High,3-Low,4-Median,5-Typical,6-Weighted
extern int     Order          = 3;  //Filter Order: 1-EMA,2-2nd Order,3-3rd Order
extern int     FilterPeriod   =14;  //Filter Period 
extern int     PreSmooth      = 1;  //Pre-smoothing period
extern int     PreSmoothMode  = 0;  //Pre-smoothing MA Mode: 0-SMA,1-EMA,2-SMMA,3-LWMA
extern double  PctFilter      = 0;  //Dynamic filter in decimal(multiplier for StdDev)
extern int     ColorMode      = 0;  //Color Mode: 0-off,1-on
extern int     ColorBarBack   = 1;  //Should be 0 or 1 
extern int     AlertMode      = 0;  //Sound Alert switch (0-off,1-on) 
extern int     WarningMode    = 0;  //Sound Warning switch(0-off,1-on) 
//---- indicator buffers
double     Filter[];
double     UpTrend[];
double     DnTrend[];
double     Smoother[];
double     trend[];
double     Del[];
double     AvgDel[];

int        draw_begin;
bool       UpTrendAlert=false, DownTrendAlert=false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
//---- indicator buffers mapping
   IndicatorBuffers(7);
   SetIndexBuffer(0,Filter);
   SetIndexBuffer(1,UpTrend);
   SetIndexBuffer(2,DnTrend);
   SetIndexBuffer(3,Smoother);
   SetIndexBuffer(4,trend);  
   SetIndexBuffer(5,Del);
   SetIndexBuffer(6,AvgDel);
//---- drawing settings
   SetIndexStyle(0,DRAW_LINE);
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   draw_begin = FilterPeriod + PreSmooth;
   SetIndexDrawBegin(0,draw_begin);
   SetIndexDrawBegin(1,draw_begin);
   SetIndexDrawBegin(2,draw_begin);
   IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS)+1);
//---- name for DataWindow and indicator subwindow label
   IndicatorShortName("LowPassFilter("+Order+","+FilterPeriod+")");
   SetIndexLabel(0,"LowPassFilter");
   SetIndexLabel(1,"UpTrend");
   SetIndexLabel(2,"DnTrend");
//---- initialization done
   return(0);
}
//+------------------------------------------------------------------+
//| LowPassFilter_v1                                                 |
//+------------------------------------------------------------------+
int start()
{
   int limit, i, shift;
   int counted_bars=IndicatorCounted();
   double a, b, c, pi = 3.1415926535;
   
   if(counted_bars<1)
   for(i=1;i<=draw_begin;i++) 
   {
   Filter[Bars-i]=0; 
   UpTrend[Bars-i]=0; 
   DnTrend[Bars-i]=0;
   }
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;

   for(shift=limit; shift>=0; shift--)
   Smoother[shift] = iMA(NULL,0,PreSmooth,0,PreSmoothMode,Price,shift);
   
   for(shift=limit; shift>=0; shift--)
   {
      if(Order == 1) Filter[shift] = iMAOnArray(Smoother,0,FilterPeriod,0,1,shift);
      else
		if(Order == 2) 
		{
		a = MathExp(-MathSqrt(2)*pi/FilterPeriod);
		b = 2*a*MathCos(MathSqrt(2)*pi/FilterPeriod);
    	Filter[shift] = b*Filter[shift+1] - a*a*Filter[shift+2] + (1 - b + a*a)*Smoother[shift];
		}
		else
		if(Order == 3) 
		{
		a = MathExp(-pi/FilterPeriod);
		b = 2*a*MathCos(MathSqrt(3)*pi/FilterPeriod);
    	c = MathExp(-2*pi/FilterPeriod); //a * a;
    	Filter[shift] = (b+c)*Filter[shift+1] - (c+b*c)*Filter[shift+2] + c*c*Filter[shift+3] + (1-b+c)*(1-c)*Smoother[shift];
		}
  
   int Length = FilterPeriod;
      
      if (PctFilter>0)
      {
      Del[shift] = MathAbs(Filter[shift] - Filter[shift+1]);
   
      double sumdel=0;
      for (int j=0;j<=Length-1;j++) sumdel = sumdel+Del[shift+j];
      AvgDel[shift] = sumdel/Length;
    
      double sumpow = 0;
      for (j=0;j<=Length-1;j++) sumpow+=MathPow(Del[j+shift]-AvgDel[j+shift],2);
      double StdDev = MathSqrt(sumpow/Length); 
     
      double filter = PctFilter * StdDev;
     
      if(MathAbs(Filter[shift]-Filter[shift+1]) < filter ) Filter[shift]=Filter[shift+1];
      }
      else
      filter=0;
   
      
      if (ColorMode>0)
      {
         trend[shift] = trend[shift+1];
         if (Filter[shift] - Filter[shift+1] > filter) trend[shift] = 1;
         if (Filter[shift+1] - Filter[shift] > filter) trend[shift] =-1;
    
         if (trend[shift]>0)
         {
            UpTrend[shift] = Filter[shift]; 
            if (trend[shift+ColorBarBack]<0) UpTrend[shift+ColorBarBack]=Filter[shift+ColorBarBack];
            DnTrend[i] = EMPTY_VALUE;
            if (WarningMode>0 && trend[shift+1]<0 && shift==0) PlaySound("alert2.wav");
         }
         else              
         if (trend[shift]<0)
         { 
            DnTrend[shift] = Filter[shift]; 
            if (trend[shift+ColorBarBack]>0) DnTrend[shift+ColorBarBack]=Filter[shift+ColorBarBack];
            UpTrend[shift] = EMPTY_VALUE;
            if (WarningMode>0 && trend[shift+1]>0 && shift==0) PlaySound("alert2.wav");
         }               
      }
   }         
//----------   
   string Message;
   
   if ( trend[2]<0 && trend[1]>0 && Volume[0]>1 && !UpTrendAlert)
	{
	Message = " "+Symbol()+" M"+Period()+": HMA Signal for BUY";
	if ( AlertMode>0 ) Alert (Message); 
	UpTrendAlert=true; DownTrendAlert=false;
	} 
	 	  
	if ( trend[2]>0 && trend[1]<0 && Volume[0]>1 && !DownTrendAlert)
	{
	Message = " "+Symbol()+" M"+Period()+": HMA Signal for SELL";
	if ( AlertMode>0 ) Alert (Message); 
	DownTrendAlert=true; UpTrendAlert=false;
	} 	         
//---- done
   return(0);
}

Posted By: jcl

Re: LowPass filter formula - 11/05/12 08:20

That looks not like a 2-pole lowpass filter, but like a Butterworth filter.

However it illustrates good the coding overhead of MQL4, even though it's also based on C. A 3rd order Butterworth filter in lite-C looks like this:

Code:
var Butterworth(var *Data,int Cutoff)
{
	var a = exp(-PI / Cutoff);
	var b = 2*a*cos(1.738*PI / Cutoff);
	var c = a*a;
	var c1 = b + c;
	var c2 = -(c + b*c);
	var c3 = c*c;
	var c0 = 1 - c1 - c2 - c3;

	var* Filt = series(*Data,4);
	return Filt[0] = c0*Data[0] + c1*Filt[1] + c2*Filt[2] + c3*Filt[3];
}

Posted By: deweymcg

Re: LowPass filter formula - 11/08/12 14:37

George on Steve Hopwood's forum was kind enough to supply this for Metatrader:

#property copyright "Copyright © 2012, George Heitman"
#property link "http://www.stevehopwoodforex.com"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Black

//---- input parameters
extern int Per=20;
extern int Price=PRICE_CLOSE;

//---- buffers
double LP[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
string short_name;
//---- additional buffers are used for counting.
IndicatorBuffers(1);
SetIndexBuffer(0,LP);

//---- indicator lines
SetIndexStyle(0,DRAW_LINE);

//---- name for DataWindow label
short_name=StringConcatenate("LowPass Filter (",Per,")");
IndicatorShortName(short_name);
SetIndexLabel(0,short_name);
//----
SetIndexDrawBegin(0,Per);
//----
return(0);
}

int start() {
int i,limit;

int counted_bars=IndicatorCounted();
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;

double a = 2.0/(Per+1.0);
double a2 = a*a;
double p1, p2, p3;

for(i=limit; i>=0; i--) {

switch(Price)
{
case PRICE_CLOSE: p1 = Close[i]; p2 = Close[i+1];p3 = Close[i+2];break;
case PRICE_OPEN: p1 = Open[i]; p2 = Open[i+1];p3 = Open[i+2];break;
case PRICE_HIGH: p1 = High[i]; p2 = High[i+1];p3 = High[i+2];break;
case PRICE_LOW: p1 = Low[i]; p2 = Low[i+1];p3 = Low[i+2];break;
case PRICE_MEDIAN: p1 = (High[i]+Low[i])/2; p2 = (High[i+1]+Low[i+1])/2;p3 = (High[i+2]+Low[i+2])/2;break;
case PRICE_TYPICAL: p1 = (High[i]+Low[i]+Close[i])/3; p2 = (High[i+1]+Low[i+1]+Close[i+1])/3;p3 = (High[i+2]+Low[i+2]+Close[i+2])/3;break;
case PRICE_WEIGHTED: p1 = (High[i]+Low[i]+2*Close[i])/4; p2 = (High[i+1]+Low[i+1]+2*Close[i+1])/4;p3 = (High[i+2]+Low[i+2]+2*Close[i+2])/4;break;
default: p1 = Close[i]; p2 = Close[i+1];p3 = Close[i+2];
}

LP[i] = (a-0.25*a2)*p1
+ 0.5*a2*p2
- (a-0.75*a2)*p3
+ 2*(1.0-a)*LP[i+1]
- (1.0-a)*(1.0-a)*LP[i+2];
}

return(0);
}
//+------------------------------------------------------------------+
Posted By: JerryS

Re: LowPass filter formula - 06/02/16 08:06

From: http://www.financial-hacker.com/trend-delusion-or-reality/

var LowPass(var *Data,int Period)
{
var* LP = series(Data[0]);
var a = 2.0/(1+Period);
return LP[0] = (a-0.25*a*a)*Data[0]
+ 0.5*a*a*Data[1]
- (a-0.75*a*a)*Data[2]
+ 2*(1.-a)*LP[1]
- (1.-a)*(1.-a)*LP[2];
}

I'm having trouble actually finding this function in the files that came with Zorro though... and I'm not sure what the Data is (i'm new to Zorro--is it ever defined in the code or it's just a variable you can replace with anything?)
Posted By: JerryS

Re: LowPass filter formula - 06/02/16 09:03

It doesn't even fully make sense to me how LP is defined...it includes earlier versions of itself (LP[2] and LP[1]) in its own definition.... Can it handle that?
Posted By: jcl

Re: LowPass filter formula - 06/02/16 10:45

You bet.
Posted By: JerryS

Re: LowPass filter formula - 06/02/16 17:36

If LP=series(Data[0]), then doesn't LP[1]=Data[1]? and LP[2]=Data[2]?

Could you please explain:

return LP[0] = (a-0.25*a*a)*Data[0]
+ 0.5*a*a*Data[1]
- (a-0.75*a*a)*Data[2]
+ 2*(1.-a)*LP[1]
- (1.-a)*(1.-a)*LP[2]

I'm just working with what I learned in the manual. If there's something else I need to read to be able to understand this language please let me know.
Posted By: JerryS

Re: LowPass filter formula - 06/03/16 03:06

I've now read the relevant chapter of Ehlers' text, and arrived at the following equation for a 2-pole filter (Gaussian), as supposedly written in EasyLanguage:

y = a*a*x + 2*(1-a)*y[1]-(1-a)*(1-a)*y[2]

Which seems much simpler but still has the problem of referring back to earlier versions of the same variable to define a variable (which is completely circular)... ***ALSO, it never in the chapter defines what "x" is supposed to be. (Kind of like in the Zorro code it doesn't define what "Data" is.***

If you are referring to earlier versions of a variable to run into this logical problem: what is y[2]? y[2] = a*a*x + 2*(1-a)*y[3]-(1-a)*(1-a)*y[4] ??? And what is y[4]???? It just goes on forever never truly defining what exactly it is...

When you return LP[0] = something... what are you doing? Why not just return LP[0]? How do you make it equal to something other than series(Data[0])? Should the result just be "false"? I know it can't be since the function is supposed to return a variable...

This is why we need a chat room--because it seems like it will take years to even understand one of the basic functions of the manual this way. According to wikipedia circular references are useless. I tend to believe that it works better than simple moving averages and can easily test it, but I prefer to halfway understand the indicators I'm using, and would expect anyone who takes this seriously to do the same. Hopefully someone out there can explain...
Posted By: jcl

Re: LowPass filter formula - 06/03/16 08:17

Asking such questions in a forum is better than in a chat room: Other users might have the same issue and can then read the answer here, while it would be lost in a chat.

The "x" in the above formula is the input to the filter, here normally the current price.

"return LP[0] = ..." assigns a value to LP[0] and returns that value at the same time.

And recursive definitions are a frequent element in math as well as in programming. You will find them everywhere in mathematical formulas and in program code. Y[1] is simply the previous value of Y.
Posted By: DdlV

Re: LowPass filter formula - 06/03/16 13:01

Hi JerryS. No idea what your computer/science/math background is, but I'll try to help. To expand on what jcl said, recursive is not the same as circular. Circular means the calculation is in some way using itself. Recursive means a prior value is being used. The classic example is factorial: n! = n * (n-1)!.

In the case of Zorro, this is done with series() (for simplicity to start think of them as time series). Perhaps the missing element is that on the first bar the value of y[n] with n>0 is 0 - only y[0] has a value. But on the next bar y[1] does also (the value of y[0] at the end of the previous bar), and so on. In this way the series is populated. If you add debug prints to your code, you can see this happening (as well as find other issues laugh ).

HTH.
Posted By: boatman

Re: LowPass filter formula - 06/08/16 22:27

Also search in the manual for "UnstablePeriod" for a description of how Zorro handles calculations that are influenced by an infinite number of past values.
© 2024 lite-C Forums