This script is designed to generate a sophisticated technical analysis indicator for trading charts, specifically focusing on tracking price trends with high adaptability. It produces two primary moving averages—the MAMA (Mixed Adaptive Moving Average) and the FAMA (Filtered Adaptive Moving Average)—which are displayed as distinct lines on the chart.
Core Logic and Methodology
Unlike standard moving averages that use a fixed time window (like a 50-day or 200-day average), this script uses "adaptive" logic. This means it automatically adjusts its sensitivity based on the current behavior of the market.
The underlying process follows these key steps:
1. Data Pre-processing and Smoothing The indicator begins by analyzing the midpoint price (the average of the High and Low) of the bars. It applies a series of weighted smoothing calculations to filter out minor "noise" from the market, ensuring that the resulting lines represent broader trends rather than erratic fluctuations.
2. Frequency and Phase Analysis To determine how quickly the indicator should react, the script employs complex mathematical techniques (similar to signal processing used in physics and engineering):
- Detrending: It strips away the long-term trend to focus on the immediate cyclical movement of the price.
- Phase Calculation: It analyzes the "phase" or cycle of the price movement. By comparing these phases over time, the script determines if the market is moving in a stable cycle, accelerating, or trending linearly.
3. Dynamic Adaptation (The "Alpha" Factor) The heart of the logic lies in calculating a variable called Alpha.
- When the market is moving steadily and predictably, the algorithm decreases the adaptation speed to provide a smooth, stable line.
- When it detects a sudden change or a sharp turn in the market cycle, the algorithm increases the adaptation speed. This allows the indicator to "pivot" quickly to follow new price action without being too sensitive to insignificant wiggles.
4. The Two Output Lines The script provides two distinct layers of information:
- MAMA (Primary Line): This is the direct result of the adaptive logic. It reacts quickly to changes in trend direction while maintaining smoothness.
- FAMA (Filtered Line): This is a further smoothed version of the MAMA. By applying an additional layer of filtering, it lags slightly behind the MAMA but provides a much "cleaner" visual representation of the overall market momentum.
Summary for the User
In practical terms, this script allows a trader to see a moving average that "knows" when to speed up and when to slow down. It aims to stay glued to the price during strong trends while remaining less reactive during choppy, sideways markets. By using two lines (MAMA and FAMA), it helps users distinguish between immediate price shifts and the overarching market direction.
//+------------------------------------------------------------------+
//| Version July 20, 2006 |
//| Editing Nikolay Kositsin 15.06.2006 farria@mail.redcom.ru |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| #MAMA_NK.mq4 |
//| |
//| http://forex.kbpauk.ru/ |
//+------------------------------------------------------------------+
#property link "http://forex.kbpauk.ru/"
//---- îòðèñîâêà èíäèêàòîðà â ãëàâíîì îêíå
#property indicator_chart_window
//---- êîëè÷åñòâî èíäèêàòîðíûõ áóôôåðîâ
#property indicator_buffers 2
//---- öâåòà èíäèêàòîðà
#property indicator_color1 Blue
#property indicator_color2 Red
//---- òîëùèíà èíäèêàòîðíûõ ëèíèé
#property indicator_width1 1
#property indicator_width2 1
//---- ÂÕÎÄÍÛÅ ÏÀÐÀÌÅÒÐÛ ÈÍÄÈÊÀÒÎÐÀ
extern double FastLimit = 0.5;
extern double SlowLimit = 0.05;
//---- èíäèêàòîðíûå áóôôåðû
double FABuffer[];
double MABuffer[];
//+------------------------------------------------------------------+
//| #MAMA initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- Ñòèëü èñïîëíåíèÿ ãðàôèêà
SetIndexStyle(0, DRAW_LINE, 0, 2);
SetIndexStyle(1, DRAW_LINE, 0, 2);
//---- 2 èíäèêàòîðíûõ áóôôåðà èñïîëüçîâàíû äëÿ ñ÷¸òà
SetIndexBuffer(0, FABuffer);
SetIndexBuffer(1, MABuffer);
//---- óñòàíîâêà çíà÷åíèé èíäèêàòîðà, êîòîðûå íå áóäóò âèäèìû íà ãðàôèêå
SetIndexEmptyValue(0, 0.0);
SetIndexEmptyValue(1, 0.0);
//---- èìÿ äëÿ îêîí äàííûõ è ëýéáà äëÿ ñóáúîêîí
IndicatorShortName("#MAMA_NK");
SetIndexLabel(0, "#FAMA_NK");
SetIndexLabel(1, "#MAMA_NK");
//---- óñòàíîâêà íîìåðà áàðà, íà÷èíàÿ ñ êîòîðîãî áóäåò îòðèñîâûâàòüñÿ èíäèêàòîð
SetIndexDrawBegin(0, 50);
SetIndexDrawBegin(1, 50);
//---- çàâåðøåíèå èíèöèàëèçàöèè
return(0);
}
//+------------------------------------------------------------------+
//| #MAMA |
//+------------------------------------------------------------------+
int start()
{
//---- ïðîâåðêà êîëè÷åñòâà áàðîâ íà äîñòàòî÷íîñòü äëÿ ðàñ÷¸òà
if(Bars <= 7)
return(0);
//---- ââåäåíèå ïåðåìåííûõ ïàìÿòè
static int time2;
static double Price[4][2], Smooth[7][2], Detrender[7][2], Q1[7][2];
static double I1[7][2], I2[2][2], Q2[2][2];
static double Re[2][2], Im[2][2], SmoothPeriod[2][2], Period_[2][2];
static double Phase[2][2], MAMA[2][2], FAMA[2][2];
//----+ Ââåäåíèå öåëûõ ïåðåìåííûõ è ïîëó÷åíèå óæå ïîäñ÷èòàííûõ áàðîâ
int MaxBar, limit, bar, iii, counted_bars = IndicatorCounted();
//---- ïðîâåðêà íà âîçìîæíûå îøèáêè
if(counted_bars < 0)
return(-1);
//---- ïîñëåäíèé ïîäñ÷èòàííûé áàð äîëæåí áûòü ïåðåñ÷èòàí
if(counted_bars > 0)
counted_bars--;
//----+ Ââåäåíèå ïåðåìåííûõ ñ ïëàâàþùåé òî÷êîé
double jI, jQ, DeltaPhase, alpha, ttime;
//---- îïðåäåëåíèå íîìåðà ñàìîãî ñòàðîãî áàðà, íà÷èíàÿ ñ êîòîðîãî áóäåò ïðîèçâåä¸í ïîëíûé ïåðåñ÷¸ò âñåõ áàðîâ
MaxBar = Bars - 1 - 7;
//---- îïðåäåëåíèå íîìåðà ñàìîãî ñòàðîãî áàðà, íà÷èíàÿ ñ êîòîðîãî áóäåò ïðîèçåä¸í ïåðåñ÷¸ò òîëüêî íîâûõ áàðîâ
limit = Bars - 1 - counted_bars;
//---- èíèöèàëèçàöèÿ íóëÿ
if(limit >= MaxBar)
{
for(iii = Bars - 1; iii > MaxBar; iii--)
{
FABuffer[bar] = 0;
MABuffer[bar] = 0;
limit = MaxBar;
}
}
//+--- âîññòàíîâëåíèå çíà÷åíèé ïåðåìåííûõ +====+
int Tnew = Time[limit+1];
if(limit < MaxBar)
if(Tnew == time2)
{
for(iii = 0; iii < 4; iii++)
Price[iii][0] = Price[iii][1];
for(iii = 0; iii < 7; iii++)
{
Smooth[iii][0] = Smooth[iii][1];
Detrender[iii][0] = Detrender[iii][1];
Q1[iii][0] = Q1[iii][1];
I1[iii][0] = I1[iii][1];
}
for(iii = 0; iii < 2; iii++)
{
I2[iii][0] = I2[iii][1];
Q2[iii][0] = Q2[iii][1];
Re[iii][0] = Re[iii][1];
Im[iii][0] = Im[iii][1];
SmoothPeriod[iii][0] = SmoothPeriod[iii][1];
Period_[iii][0] = Period_[iii][1];
Phase[iii][0] = Phase[iii][1];
MAMA [iii][0] = MAMA [iii][1];
FAMA [iii][0] = FAMA [iii][1];
}
}
else
{
if(Tnew > time2)
Print("ERROR01");
else
Print("ERROR02");
return(-1);
}
//----
bar = limit;
while(bar >= 0)
{
//+--- Ñîõðàíåíèå çíà÷åíèé ïåðåìåííûõ +==========+
if(bar == 1)
if(((limit == 1) && (time2 == Time[2])) || (limit > 1))
{
for(iii = 0; iii < 4; iii++)
Price[iii][1] = Price[iii][0];
//----
for(iii = 0; iii < 7; iii++)
{
time2 = Time[2];
Smooth[iii][1] = Smooth[iii][0];
Detrender[iii][1] = Detrender[iii][0];
Q1[iii][1] = Q1[iii][0];
I1[iii][1] = I1[iii][0];
}
//----
for(iii = 0; iii < 2; iii++)
{
I2[iii][1] = I2[iii][0];
Q2[iii][1] = Q2[iii][0];
Re[iii][1] = Re[iii][0];
Im[iii][1] = Im[iii][0];
SmoothPeriod[iii][1] = SmoothPeriod[iii][0];
Period_[iii][1] = Period_[iii][0];
Phase[iii][1] = Phase[iii][0];
MAMA [iii][1] = MAMA [iii][0];
FAMA [iii][1] = FAMA [iii][0];
}
}
//+---+==========================================+
for(iii = 0; iii < 4; iii++)
Price[iii][0] = (High[bar+iii] + Low[bar+iii]) / 2;
Smooth[0][0] = (4*Price[0][0] + 3*Price[1][0] + 2*Price[2][0] + Price[3][0]) / 10;
Detrender[0][0] = (0.0962*Smooth[0][0] + 0.5769*Smooth[2][0] - 0.5769*Smooth[4][0] -
0.0962*Smooth[6][0])*(0.075*Period_[2][0] + 0.54);
// {Compute InPhase and Quadrature components}
Q1[0][0] = (0.0962*Detrender[0][0] + 0.5769*Detrender[2][0] - 0.5769*Detrender[4][0] -
0.0962*Detrender[6][0])*(0.075*Period_[2][0] + 0.54);
I1[0][0] = Detrender[3][0];
// {Advance the phase of I1 and Q1 by 90 degrees}
jI = (0.0962*I1[0][0] + 0.5769*I1[2][0] - 0.5769*I1[4][0] -
0.0962*I1[6][0])*(0.075*Period_[1][0] + 0.54);
jQ = (0.0962*Q1[0][0] + 0.5769*Q1[2][0] - 0.5769*Q1[4][0] -
0.0962*Q1[6][0])*(0.075*Period_[1][0] + 0.54);
// {Phasor addition for 3 bar averaging)}
I2[0][0] = I1[0][0] - jQ;
Q2[0][0] = Q1[0][0] + jI;
// {Smooth the I and Q components before applying the discriminator}
I2[1][0] = 0.2*I2[1][0] + 0.8*I2[2][0];
Q2[1][0] = 0.2*Q2[1][0] + 0.8*Q2[2][0];
// {Homodyne Discriminator}
Re[0][0] = I2[0][0]*I2[1][0] + Q2[0][0]*Q2[1][0];
Im[0][0] = I2[0][0]*Q2[1][0] - Q2[0][0]*I2[1][0];
Re[0][0] = 0.2*Re[0][0] + 0.8*Re[1][0];
Im[0][0] = 0.2*Im[0][0] + 0.8*Im[1][0];
//----
if(Im[0][0] != 0 && Re[0][0] != 0)
Period_ [0][0]= 360 / MathArctan(Im[0][0] / Re[0][0]);
//----
if(Period_[0][0] > 1.5*Period_[1][0])
Period_[0][0] = 1.5*Period_[1][0];
//----
if(Period_[0][0] < 0.67*Period_[1][0])
Period_[0][0] = 0.67*Period_[1][0];
//----
if(Period_[0][0] < 6)
Period_[0][0] = 6;
//----
if(Period_[0][0] > 50)
Period_[0][0] = 50;
//----
Period_[0][0] = 0.2*Period_[0][0] + 0.8*Period_[1][0];
SmoothPeriod[0][0] = 0.33*Period_[0][0] + 0.67*SmoothPeriod[1][0];
//----
if(I1[0][0] != 0)
Phase[0][0] = (MathArctan(Q1[0][0] / I1[0][0]));
DeltaPhase = Phase[1][0] - Phase[0][0];
//----
if(DeltaPhase < 1)
DeltaPhase = 1;
alpha = FastLimit / DeltaPhase;
//----
if(alpha < SlowLimit)
alpha = SlowLimit;
MAMA[0][0] = alpha*Price[0][0] + (1 - alpha)*MAMA[1][0];
FAMA[0][0] = 0.5*alpha*MAMA[0][0] + (1 - 0.5*alpha)*FAMA[1][0];
//----
if(bar <= Bars - 50)
{
FABuffer[bar] = MAMA[0][0];
MABuffer[bar] = FAMA[0][0];
}
else
{
FABuffer[bar] = 0;
MABuffer[bar] = 0;
}
//----
bar--;
//----
if(bar < 0)
break;
//----
Smooth[6][0] = Smooth[5][0];
Smooth[5][0] = Smooth[4][0];
Smooth[4][0] = Smooth[3][0];
Smooth[3][0] = Smooth[2][0];
Smooth[2][0] = Smooth[1][0];
Smooth[1][0] = Smooth[0][0];
//----
Detrender[6][0] = Detrender[5][0];
Detrender[5][0] = Detrender[4][0];
Detrender[4][0] = Detrender[3][0];
Detrender[3][0] = Detrender[2][0];
Detrender[2][0] = Detrender[1][0];
Detrender[1][0] = Detrender[0][0];
//----
Q1[6][0] = Q1[5][0];
Q1[5][0] = Q1[4][0];
Q1[4][0] = Q1[3][0];
Q1[3][0] = Q1[2][0];
Q1[2][0] = Q1[1][0];
Q1[1][0] = Q1[0][0];
//----
I1[6][0] = I1[5][0];
I1[5][0] = I1[4][0];
I1[4][0] = I1[3][0];
I1[3][0] = I1[2][0];
I1[2][0] = I1[1][0];
I1[1][0] = I1[0][0];
//----
Q2[1][0] = Q2[0][0];
I2[1][0] = I2[0][0];
Re[1][0] = Re[0][0];
Im[1][0] = Im[0][0];
SmoothPeriod[1][0] = SmoothPeriod[0][0];
Phase[1][0] = Phase[0][0];
Period_[1][0] = Period_[0][0];
MAMA[1][0] = MAMA[0][0];
FAMA[1][0] = FAMA[0][0];
//----
}
return(0);
}
//+------------------------------------------------------------------+
Comments