AFIRMA
Download scriptThis script provides a sophisticated mathematical approach to analyzing price trends by utilizing advanced signal processing techniques. Instead of relying on standard moving averages, it employs a combination of Finite Impulse Response (FIR) and Autoregressive Moving Average (ARMA) models to create a smoother, more accurate representation of market movement.
Core Logic and Methodology
The indicator operates through two distinct phases to ensure the data presented on your chart is both mathematically sound and visually responsive:
1. Signal Filtering (FIR Component) The script begins by applying a "Windowing Function." In technical terms, this acts as a filter that determines how much importance is given to past price data versus recent data. By utilizing different window types—such as Hanning, Hamming, or Blackman—the script can minimize "noise" and prevent the erratic jumps often seen in traditional indicators. It calculates a weighted average of prices, ensuring that the resulting trend line remains stable even during periods of high market volatility.
2. Regression Analysis (ARMA Component) To address the limitation of "lag" (the delay between a price move and the indicator's reaction), the script performs a secondary calculation known as a least-squares regression. It looks at the most recent data points and calculates a polynomial curve that best fits the current trajectory. This allows the indicator to "project" the trend more fluidly, effectively bridging the gap between historical averages and real-time price action.
Key Features for the User
- Precision Filtering: By adjusting the "Periods," "Taps," and "Window" settings, users can customize how aggressively the indicator filters out market noise. This allows for a balance between smoothness and responsiveness depending on the trading style (e.g., scalping vs. swing trading).
- Dual-Layer Accuracy: Because the script combines a weighted history (FIR) with a mathematical curve fit (ARMA), it provides a more "organic" view of price movement. It seeks to identify the underlying momentum rather than just reacting to every individual tick of the market.
- Visual Clarity: The result is presented as two distinct lines on the chart, allowing traders to visualize the core trend with high clarity, helping to filter out emotional trading based on minor, insignificant price fluctuations.
//+------------------------------------------------------------------+
//| 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);
}
//+------------------------------------------------------------------+
Comments