Efficient way to calculate Gauss Filter

Good Afternoon / Evening AFL Experts,

Inspired by this Tradestation function (source openly available as .ELD )

{Gaussian Filter}

Inputs: Price(NumericSeries), iptPeriod(NumericSimple), iptPoles(NumericSimple);

variables: aa(0), b(0), w(0), x(0), y(0), y1(0), y2(0), y3(0), y4(0),
	       a_1(0), a_12(0), a_13(0), a_14(0), a2(0), a3(0), a4(0), Pi(3.141592654),
	       sqrtOf2(1.414213562), Period(2), poles(0);

if (iptPeriod < 2) then 
	Period = 2
else
	Period = iptPeriod;

// Number of filter poles must be between 1 and 4, inclusive
if iptPoles < 1 then
	poles = 1
else if iptPoles > 4 then
	poles = 4
else 
	poles = iptPoles;

// initialization - performed only for first bar
if CurrentBar = 1 then
begin
    w = 2 * Pi / Period; // omega
    w = 180 * w / Pi;    // in degrees

    b = (1 - cosine(w)) / (power(sqrtOf2, 2.0/poles) - 1.0);

    aa = -b + squareroot(b*b + 2*b);
    a_1 = 1.0 - aa;
    a_12 = a_1 * a_1;
    a_13 = a_1 * a_1 * a_1;
    a_14 = a_12 * a_12;
    a2 = aa * aa;
    a3 = aa * aa * aa;
    a4 = a2 * a2;

    y1 = Price;
    y2 = y1;
	y3 = y2;
    y4 = y3;
end;

{ Calculate your indicator value here }
x = Price;

if (poles = 1) then
	y = aa * x + a_1 * y1
else if (poles = 2) then
	y = a2 * x + 2 * a_1 * y1 - a_12 * y2
else if (poles = 3) then
	y = a3 * x + 3 * a_1 * y1 - 3 * a_12 * y2 + a_13 * y3
else if (poles = 4) then
	y = a4 * x + 4 * a_1 * y1 - 6 * a_12 * y2 + 4 * a_13 * y3 - a_14 * y4;

y4 = y3; // delayed by four bars
y3 = y2; // delayed by three bars
y2 = y1; // delayed by two bars
y1 = y;  // delayed by one bar

Gauss = y;

Without access to KB or other function narratives amidst the server issue, this is my hit-and-trial in AFL:

n = BarCount;

function fact( num )
{
	 a = 1;
	 nn = IIf( num <= 1, 1, num );
	 for( i = 1; i <= nn; i++ )
	 {
		 a = a * i;
	 }
	 return a;
}

function getPoles( f, Poles, alpha )
{
	 filt = f;
	 _sign = 1;
	 
	 results = 0 + n;
	 
	 for( r = 1; r <= Max( Min( Poles, n ), 1 ); r++ )
	 {
		 mult = fact( Poles ) / ( fact( Poles - r ) * fact( r ) );
		 matPo = ( 1 - alpha ) ^ r;
		 prev = Nz( filt[ r - 1 ], 0 );
		 _Sum = _sign * mult * matPo * prev;
		 results = results + _Sum;
		 _sign = _sign * -1;
	 }
	 
	 return results - n;
}

function Gauss( Price, Lag, PoleNum )
{
	 Pi = 3.141592653589793238462643;
	 
	 beta = ( 1 - cos( 2 * Pi / Lag ) ) / ( ( sqrt( 2 ) ^ ( 2 / PoleNum ) ) - 1 );
	 alfa = -beta + sqrt( beta * beta + 2 * beta );
	 pre = Nz( Price, 0 ) * ( alfa ^ PoleNum );
	 _Filter = pre;
	 
	 result = IIf( n > 0, getPoles( Ref( _Filter, -1 ), PoleNum, alfa ), 0 );
	 _Filter = pre + result;
	 
	 return _Filter;
}

_SECTION_BEGIN( "Gauss Filter" );
	 Plot( Gauss( ( H + L ) / 2, 13, 8 ), "Gauss", colorWhite, styleLine );
_SECTION_END();

Please help to share an efficient and correct way to calculate the Gauss filter using AFL.

Thank you

@Cougar there was an article by John Ehlers in the January 2006 issue of Technical Analysis of Stocks and Commodities in which the author discusses Gaussian filters (as well as others) while he creates a 2nd order infinite impulse response filter (IIR).

This was coded into afl by @Tomasz
http://www.amibroker.com/members/traders/01-2006.html

Of course AmiBroker also has it's own built-in IIR
https://www.amibroker.com/guide/afl/iir.html

1 Like

Thank you @portfoliobuilder,

That helps! Also found an article on Gaussian Filters by Ehler. So, have coded the below but with erroneous results.

function Gauss( Price, CyclePeriod, Poles )
{
	 PI = 2 * asin( 1 );
	 beta = ( 1 - cos( 2 * PI / CyclePeriod ) ) / ( 2 ^ ( 1 / Poles ) - 1 );
	 alpha = -beta + sqrt( ( beta ^ 2 ) + ( 2 * beta ) );
	 
	 gf = 0;
	 gf =
	 IIf( Poles == 1, alpha * Price + ( 1 - alpha ) * Nz( Ref( gf, -1 ) ),
	 IIf( Poles == 2, ( alpha ^ 2 ) * Price + 2 * ( 1 - alpha ) * Nz( Ref( gf, -1 ) ) - ( ( 1 - alpha ) ^ 2 ) * Nz( Ref( gf, -2 ) ),
	 IIf( Poles == 3, ( alpha ^ 3 ) * Price + 3 * ( 1 - alpha ) * Nz( Ref( gf, -1 ) ) - ( ( 3 * ( ( 1 - alpha ) ^ 2 ) ) * Nz( Ref( gf, -2 ) ) ) + ( ( 1 - alpha ) ^ 3 ) * Nz( Ref( gf, -3 ) ),
	 IIf( Poles == 4, ( alpha ^ 4 ) * Price + 4 * ( 1 - alpha ) * Nz( Ref( gf, -1 ) ) - ( ( 6 * ( ( 1 - alpha ) ^ 2 ) ) * Nz( Ref( gf, -2 ) ) ) + ( ( 4 * ( ( 1 - alpha ) ^ 3 ) ) * Nz( Ref( gf, -3 ) ) ) - ( ( ( 1 - alpha ) ^ 4 ) * Nz( Ref( gf, -4 ) ) ),
	 Null ) ) ) );
	 
	 return gf;
}

The Swiss Army Indicator shows a 2-pole Gaussian Filter and a uses Poly2ndOrder() function.

  1. Is IIR function same to this Poly2ndOrder function for 2-poles?
  2. How do I correctly use IIR for a 4-pole Gauss Filter?

Sorry @Cougar I haven't had a need to learn much about the IIR so I can't give you much feedback on it's proper use. To me it is an academic curiosity as is most of Ehler's work using the many different derivations of indicators that he publishes. Maybe someone else on the forum with experience actually using the IIR or other similar concepts can offer you some advice.

I am circling round and round and round with the IIR arguments. Guide me a way out, please!

@Cougar - your codes are incorrect. IIR filters are recursive and you can't code them with Ref().

One way is to use loop, but there is really no need to re-invent the wheel and code loops, because all filtering functions are already available directly in AFL.

It is simple, for ALL IIR filters you should be using general-purpose IIR function
http://www.amibroker.com/f?iir

// Efficient and correct code for Gaussian 4 order IIR 
// Originally posted on forum.amibroker.com, see:
// @link: https://forum.amibroker.com/t/efficient-way-to-calculate-gauss-filter/11432/6

function Gauss4Order( Price, Period )
{
	PI = 3.1415926; 
	beta1 = ( 1 - cos( 2 * PI / Period ) ) / ( 2 ^ ( 1 / 4 ) - 1 );
	alpha = -beta1 + sqrt( beta1 ^ 2 + 2 * beta1 ); 
	
	return IIR( Price, alpha ^ 4, 4 * ( 1 - alpha ), 0, -6 * ( 1 - alpha ) ^ 2, 0, 4 * ( 1 - alpha ) ^ 3, 0, - ( 1 - alpha ) ^ 4 );
}

Plot( Close, "Price", colorDefault, styleCandle );

Plot( Gauss4Order( Close, 20 ), "Gauss4order 20", colorRed );
	

But since you are working with time discrete signal (quotations) Gaussian filter can be implemented by FIR as well
http://www.amibroker.com/f?fir
using sampled gaussian kernel:

8 Likes

I am no electrical engineer @Tomasz. Thank you for the vivid explanation - able to comprehend the IIR arguments now.