Indicator AFIRMA (Autoregressive Finite Impulse Response Moving Average)is a very interesting technical indicator, where forms the basis Moving average. Based on the digital filter accurately shows the price movement, though with a time lag. As you can see in the figures AFIRMA (blue) in combination with
Moving average - MA (red), indicating above average good signals based on fitting the smooth function (polynomial or a sin / cos like in Fourier transform) has no lag but often shows the price movement not so well. The condition of combined moving average and its first derivative continuity is set at two moving averages crossing. As a result, we have the smooth moving average that accurately tracks the prices without a time lag. For better business results should be combined with indicator
Bollinger Bands,
Trend Detection Index - TDI,
Laguerre RSI indicator, etc.
//+------------------------------------------------------------------+
//| AFIRMA.mq4 |
//| Copyright © 2006, gpwr. |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, gpwr."
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
#property indicator_width1 2
#property indicator_width2 2
//Global constants
#define pi 3.141592653589793238462643383279502884197169399375105820974944592
//Input parameters
extern int Periods = 4; // 1/(2*Periods) sets the filter bandwidth
extern int Taps = 21; // must be an odd number
extern int Window = 4; // selects windowing function
//Global variables
double w[], wsum, sx2, sx3, sx4, sx5, sx6, den;
int n;
//Indicator buffers
double FIRMA[];
double ARMA[];
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int init()
{
//Calculate weights
ArrayResize(w, Taps);
wsum = 0.0;
for(int k = 0; k < Taps; k++)
{
switch(Window)
{
case 1: w[k] = 1.0; // Rectangular window
break;
case 2: w[k] = 0.50 - 0.50*MathCos(2.0*pi*k / Taps); // Hanning window
break;
case 3: w[k] = 0.54 - 0.46*MathCos(2.0*pi*k / Taps); // Hamming window
break;
case 4: w[k] = 0.42 - 0.50*MathCos(2.0*pi*k / Taps) +
0.08*MathCos(4.0*pi*k / Taps); // Blackman window
break;
case 5: w[k] = 0.35875 - 0.48829*MathCos(2.0*pi*k / Taps) +
0.14128*MathCos(4.0*pi*k / Taps) -
0.01168*MathCos(6.0*pi*k / Taps); // Blackman - Harris window
break;
default: w[k] = 1; //Rectangular window
break;
}
if(k != Taps / 2.0)
w[k] = w[k]*MathSin(pi*(k - Taps / 2.0) / Periods) / pi / (k - Taps / 2.0);
wsum += w[k];
}
//Calculate sums for the least-squares method
n = (Taps - 1) / 2;
sx2 = (2*n + 1) / 3.0;
sx3 = n*(n + 1) / 2.0;
sx4 = sx2*(3*n*n+3*n - 1) / 5.0;
sx5 = sx3*(2*n*n+2*n - 1) / 3.0;
sx6 = sx2*(3*n*n*n*(n + 2) - 3*n+1) / 7.0;
den = sx6*sx4 / sx5 - sx5;
//Initialize indicator
IndicatorBuffers(2);
SetIndexBuffer(0, FIRMA);
SetIndexBuffer(1, ARMA);
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2);
SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2);
IndicatorShortName("AFIRMA");
return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int deinit()
{
return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int start()
{
//Calculate FIR MA for all bars except for the last n bars
ArrayInitialize(FIRMA, EMPTY_VALUE);
for(int i = 0; i <= Bars - Taps; i++)
{
FIRMA[i+n] = 0.0;
for(int k = 0; k < Taps; k++)
FIRMA[i+n] += Close[i+k]*w[k] / wsum;
}
//Calculate regressive MA for the remaining n bars
double a0 = FIRMA[n];
double a1 = FIRMA[n] - FIRMA[n+1];
double sx2y = 0.0;
double sx3y = 0.0;
for(i = 0; i <= n; i++)
{
sx2y += i*i*Close[n-i];
sx3y += i*i*i*Close[n-i];
}
sx2y = 2.0*sx2y / n / (n + 1);
sx3y = 2.0*sx3y / n / (n + 1);
double p = sx2y - a0*sx2 - a1*sx3;
double q = sx3y - a0*sx3 - a1*sx4;
double a2 = (p*sx6 / sx5 - q) / den;
double a3 = (q*sx4 / sx5 - p) / den;
ArrayInitialize(ARMA, EMPTY_VALUE);
for(i = 0; i <= n; i++)
ARMA[n-i] = a0 + i*a1 + i*i*a2 + i*i*i*a3;
return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| AFIRMA.mq5 |
//| Copyright © 2006, gpwr. |
//| More info: http://plusforex.blogspot.com |
//+------------------------------------------------------------------+
//---- author of the indicator
#property copyright "Copyright © 2006, gpwr."
#property link ""
//---- indicator version
#property version "1.00"
//---- drawing the indicator in the main window
#property indicator_chart_window
//---- two buffers are used for calculation and drawing the indicator
#property indicator_buffers 2
//---- only two plots are used
#property indicator_plots 2
//+----------------------------------------------+
//| Declaration of constants |
//+----------------------------------------------+
#define RESET 0
#define pi 3.141592653589793238462643383279502884197169399375105820974944592
//+----------------------------------------------+
//| Indicator 1 drawing parameters |
//+----------------------------------------------+
//---- drawing indicator 1 as a line
#property indicator_type1 DRAW_LINE
//---- use blue violet color for the indicator 1 line
#property indicator_color1 BlueViolet
//---- line of the indicator 1 is a continuous line
#property indicator_style1 STYLE_SOLID
//---- indicator 1 line width is equal to 2
#property indicator_width1 2
//---- displaying the indicator line label
#property indicator_label1 "FIRMA"
//+----------------------------------------------+
//| Indicator 2 drawing parameters |
//+----------------------------------------------+
//---- drawing the indicator 2 as a line
#property indicator_type2 DRAW_LINE
//---- red color is used for the indicator 2 line
#property indicator_color2 Red
//---- the indicator 2 line is a continuous curve
#property indicator_style2 STYLE_SOLID
//---- indicator 2 line width is equal to 2
#property indicator_width2 2
//---- displaying the indicator line label
#property indicator_label2 "ARMA"
//+----------------------------------------------+
//| Declaration of enumerations |
//+----------------------------------------------+
enum ENUM_WINDOWS // Type of constant
{
Rectangular = 1, // Rectangular window
Hanning1, // Hanning window 1
Hanning2, // Hanning window 2
Blackman, // Blackman window
Blackman_Harris // Blackman-Harris window
};
//+----------------------------------------------+
//| Indicator input parameters |
//+----------------------------------------------+
input int Periods = 4; // LF transmission width 1/(2*Periods)
input int Taps = 21; // Number of delay units in the filter
input ENUM_WINDOWS Window=Blackman; // Window index
input int Shift=0; // Horizontal shift of the indicator in bars
//+----------------------------------------------+
//---- declaration of the integer variables for the start of data calculation
int min_rates_total;
//---- declaration of global variables
int n;
double w[],wsum,sx2,sx3,sx4,sx5,sx6,den;
//---- declaration of dynamic arrays that
//---- will be used as indicator buffers
double FIRMABuffer[],ARMABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
//---- initialization of variables
ArrayResize(w,Taps);
wsum=0.0;
for(int k=0; k<Taps; k++)
{
switch(Window)
{
case Rectangular: w[k]=1.0; break; // Rectangular window
case Hanning1: w[k]=0.50-0.50*MathCos(2.0*pi*k/Taps); break; // Hanning window
case Hanning2: w[k]=0.54-0.46*MathCos(2.0*pi*k/Taps); break; // Hamming window
case Blackman: w[k]=0.42-0.50*MathCos(2.0*pi*k/Taps)+0.08*MathCos(4.0*pi*k/Taps); break; // Blackman window
case Blackman_Harris: w[k]=0.35875-0.48829*MathCos(2.0*pi*k/Taps)+0.14128
*MathCos(4.0*pi*k/Taps)-0.01168*MathCos(6.0*pi*k/Taps); // Blackman - Harris window
}
if(k!=Taps/2.0) w[k]=w[k]*MathSin(pi*(k-Taps/2.0)/Periods)/pi/(k-Taps/2.0);
wsum+=w[k];
}
//---- calculate sums for the least-squares method
n=(Taps-1)/2;
sx2 = (2*n + 1) / 3.0;
sx3 = n*(n + 1) / 2.0;
sx4 = sx2*(3*n*n+3*n - 1) / 5.0;
sx5 = sx3*(2*n*n+2*n - 1) / 3.0;
sx6 = sx2*(3*n*n*n*(n + 2) - 3*n+1) / 7.0;
den = sx6*sx4 / sx5 - sx5;
//---- initialization of variables of the start of data calculation
min_rates_total=Taps;
//---- set FIRMABuffer[] dynamic array as an indicator buffer
SetIndexBuffer(0,FIRMABuffer,INDICATOR_DATA);
//---- shifting the indicator 1 horizontally by Shift
PlotIndexSetInteger(0,PLOT_SHIFT,Shift);
//---- performing shift of the beginning of counting of drawing the indicator 1 by min_rates_total
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- setting the indicator values that won't be visible on a chart
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- indexing the elements in the buffer as timeseries
ArraySetAsSeries(FIRMABuffer,true);
//---- set ARMABuffer[] dynamic array as an indicator buffer
SetIndexBuffer(1,ARMABuffer,INDICATOR_DATA);
//---- shifting the indicator 2 horizontally by Shift
PlotIndexSetInteger(1,PLOT_SHIFT,Shift);
//---- performing shift of the beginning of counting of drawing the indicator 2 by min_rates_total+1
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,min_rates_total);
//---- setting the indicator values that won't be visible on a chart
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- indexing the elements in the buffer as timeseries
ArraySetAsSeries(ARMABuffer,true);
//---- initializations of a variable for the indicator short name
string shortname;
StringConcatenate(shortname,
"AFIRMA(",Periods,", ",Taps,", ",EnumToString(Window),", ",Shift,")");
//--- creation of the name to be displayed in a separate sub-window and in a tooltip
IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//--- determination of accuracy of displaying the indicator values
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//----
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, // number of bars in history at the current tick
const int prev_calculated,// number of bars calculated at previous call
const int begin, // bars reliable counting beginning index
const double &price[]) // price array for the indicator calculation
{
//---- checking the number of bars to be enough for the calculation
if(rates_total<min_rates_total+begin) return(RESET);
//---- declarations of local variables
int limit,bar;
double a0,a1,a2,a3,sx2y,sx3y,p,q;
//---- calculation of the 'limit' starting index for the bars recalculation loop
if(prev_calculated>rates_total || prev_calculated<=0)// checking for the first start of the indicator calculation
{
limit=rates_total-1-min_rates_total-begin; // starting index for calculation of all bars
//---- performing the shift of the beginning of the indicators drawing
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total+begin);
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,min_rates_total+begin);
}
else limit=rates_total-prev_calculated; // starting index for calculation of new bars
//---- indexing elements in arrays as timeseries
ArraySetAsSeries(price,true);
//---- main cycle of calculation of FIRMA indicator
for(bar=limit; bar>=0; bar--)
{
FIRMABuffer[bar+n]=0.0;
for(int k=0; k<Taps; k++) FIRMABuffer[bar+n]+=price[bar+k]*w[k]/wsum;
}
//---- initialize indicator buffers
for(bar=limit; bar>=0; bar--)
{
if(bar<n) FIRMABuffer[bar]=EMPTY_VALUE;
ARMABuffer[bar]=EMPTY_VALUE;
}
//---- calculate regressive MA for the remaining n bars
a0 = FIRMABuffer[n];
a1 = FIRMABuffer[n]-FIRMABuffer[n+1];
sx2y = 0.0;
sx3y = 0.0;
for(int i=0; i<=n; i++)
{
sx2y += i*i*price[n-i];
sx3y += i*i*i*price[n-i];
}
sx2y = 2.0*sx2y / n / (n + 1);
sx3y = 2.0*sx3y / n / (n + 1);
p = sx2y - a0*sx2 - a1*sx3;
q = sx3y - a0*sx3 - a1*sx4;
a2 = (p*sx6 / sx5 - q) / den;
a3 = (q*sx4 / sx5 - p) / den;
for(int k=0; k<=n; k++) ARMABuffer[n-k]=a0+k*a1+k*k*a2+k*k*k*a3;
//----
return(rates_total);
}
//+------------------------------------------------------------------+