На просторах интернета есть несколько разработанных кодов, имеющих отношение к АМА.
Прежде всего это код индикатора АМА:
- Код: выделить все
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Sienna
input int intAMAPe = 9; // Период скользящей средней Кауфмана
input int nfast = 2;
input int nslow = 30;
input double G = 2.0; // Показатель степени
//---- buffers
double AMABuffer[];
int cbars = 0, prevbars = 0;
double slowSC, fastSC;
//*********************************************************************************************
int init()
{
SetIndexStyle(0, DRAW_LINE, 0, 2);
SetIndexBuffer(0, AMABuffer);
IndicatorDigits(4);
return(0);
}
//*********************************************************************************************
int start()
{
int pos = 0;
double noise = 0.000000001, AMA, AMA0, signal, ER;
double dSC, ERSC, SSC;
if(prevbars == Bars) return(0);
//---- TODO: add your code here
slowSC = (2.0 / (nslow + 1));
fastSC = (2.0 / (nfast + 1));
cbars = IndicatorCounted();
if(Bars <= (intAMAPe + 2)) return(0);
//---- check for possible errors
if(cbars < 0) return(-1);
//---- last counted bar will be recounted
if(cbars > 0) cbars--;
pos = Bars - intAMAPe - 2;
AMA0 = Close[pos + 1];
while(pos >= 0)
{
if(pos == Bars - intAMAPe - 2) AMA0 = Close[pos + 1];
signal = MathAbs(Close[pos] - Close[pos + intAMAPe]);
noise = 0.000000001;
for(int i = 0; i < intAMAPe; i++)
{
noise = noise + MathAbs(Close[pos + i] - Close[pos + i + 1]);
}
ER = signal / noise; // коэффициент эффективности
dSC = (fastSC - slowSC);
ERSC = ER * dSC;
SSC = ERSC + slowSC;
AMA = AMA0 + (MathPow(SSC, G) * (Close[pos] - AMA0));
AMABuffer[pos] = AMA;
AMA0 = AMA;
pos--;
}
prevbars = Bars;
return(0);
}
Данный индикатор рисует на графике собственно АМА. Однако, для применения в коде советника далеко не всегда удобно обращаться отдельно к файлам индикаторов и т.п., а желательно иметь реализацию в виде функции.
Есть функция разработанная Кимом (см. код далее).
- Код: выделить все
//+------------------------------------------------------------------+
//| Индикатор AМА (средняя Кауфмана) |
//| Параметры: |
//| sym - наименование инструмента |
//| tf - таймфрейм (количество минут) |
//| nbi - номер буфера индикатора |
//| nb - номер бара
// |
//+------------------------------------------------------------------+
double iAMA(string sym, int tf, int nbi, int nb)
{
double noise = 0.000000001, AMA, AMA0, signal, ER;
double dSC, ERSC, SSC, ddK;
double slowSC, fastSC, vbi[3];
int nfast = 2;
int nslow = 30;
double G = 2.0;
double dK = 2.0;
int i;
slowSC = (2.0 / (nslow + 1));
fastSC = (2.0/ (nfast + 1));
AMA0 = iClose(sym, tf, nb + 1);
signal = MathAbs(iClose(sym, tf, nb) - iClose(sym, tf, nb + AMA_Period));
for(i = 0; i < AMA_Period; i++)
{
noise = noise + MathAbs(iClose(sym, tf, nb + i) - iClose(sym, tf, nb + i + 1));
}
ER = signal / noise;
dSC = (fastSC - slowSC);
ERSC = ER * dSC;
SSC = ERSC + slowSC;
AMA = AMA0 + (MathPow(SSC, G) * (iClose(sym, tf, nb) - AMA0));
vbi[0] = AMA;
ddK = AMA - AMA0;
if(MathAbs(ddK) > dK * Point && ddK > 0) vbi[1] = AMA; else vbi[1] = 0;
if(MathAbs(ddK) > dK * Point && ddK < 0) vbi[2] = AMA; else vbi[2] = 0;
return(vbi[nbi]);
}
Однако, в данной реализации есть как неудобства так и неправильный расчет АМА. Это и не удивительно - автор берет предыдущее значение необходимому при расчете АМА в качестве начального, а это очень неточная реализация, т.к. расчет АМА рекурсивный и для того, чтобы вычислить очередное значение АМА необходимо провести значительно больше предыдущих расчетов АМА. Также, автор использует переменную период АМА как внешний параметр и если мы запустим данную функцию в своем коде, то нам придется формировать эту переменную как внешнюю с уже указанным именем, а это не всякому новичку при изучении MQL может быть понятно. Зато другие переменные, которые обязательно должны быть параметрами, передающимися в функцию, сделаны внутренними переменными функции, что неправильно в принципе. Также присутствует фильтр по значения АМА, который совершенно не нужен, т.к. фильтрация делается отдельно (если необходимо), а сама функция АМА должна выводить фактические значения АМА. Поэтому данная реализация никак не может быть приемлемой.
Таким образом, за основу создания прототипа функции для расчета АМА можно взять код из реализации индикатора АМА, рассмотренный в начале статьи:
- Код: выделить все
double f_AMA(int per, int efp, int esp, int shi)
{
/*
Автор: Haos (http://www.investforum.ru)
Описание:
Функция осуществляет расчет адаптированной скользящей средней Кауфмана (АМА)
Параметры:
per - период скользящей средней Кауфмана
efp - период быстрой экспоненциальной скользящей средней
esp - период медленной экспоненциальной скользящей средней
shi - номер бара на котором рассчитывается АМА
*/
double dbl_Noise = 0, dbl_Signal, dbl_ER, dbl_SSC;
double dbl_AMA[];
ArrayResize(dbl_AMA, Bars - per - 1);
double dbl_SlowSC = (2.0 / (esp + 1));
double dbl_FastSC = (2.0 / (efp + 1));
if(Bars <= (per + 2)) return(0);
int pos = Bars - per - 2;
double dbl_AMA0 = Close[pos + 1];
while(pos >= 0)
{
if(pos == Bars - per - 2) dbl_AMA0 = Close[pos + 1];
dbl_Signal = MathAbs(Close[pos] - Close[pos + per]);
dbl_Noise = 0;
for(int i = 0; i < per; i++)
{
dbl_Noise = dbl_Noise + MathAbs(Close[pos + i] - Close[pos + i + 1]);
}
dbl_ER = dbl_Signal / dbl_Noise; // коэффициент эффективности
dbl_SSC = dbl_ER * (dbl_FastSC - dbl_SlowSC) + dbl_SlowSC;
dbl_AMA[pos] = dbl_AMA0 + (MathPow(dbl_SSC, 2) * (Close[pos] - dbl_AMA0));
dbl_AMA0 = dbl_AMA[pos];
pos--;
}
return(dbl_AMA[shi]);
}
Данная функция вычисляет значения АМА, фактически, начиная от начала графика (с учетом длины периода АМА), т.е. с избытком на все случаи "программистских задач". Обычно для получения сигнала на пересечение средних и т.п. достаточно данных от последних 3 баров. Функция возвращает значение АМА на заданном номере бара.
В качестве тестируемого примера можно написать скрипт (см. ниже), установить на график индикатор АМА и запустить скрипт. Далее сравнить значения последних 3 значений АМА с данными индикатора и убедиться в правильности расчетов:
- Код: выделить все
//| SC-Test-AMA.mq4 |
//| Haos |
//| http://www.investforum.ru |
//+------------------------------------------------------------------+
#property copyright "Haos"
#property link "http://www.investforum.ru"
#property version "1.00"
#property strict
#property show_inputs
input int intAMAPe = 9; // Период скользящей средней Кауфмана
input int intMAFPe = 2; // Период быстрой экспоненциальной скользящей средней
input int intMASPe = 30; // Период медленной экспоненциальной скользящей средней
//*********************************************************************************************
void OnStart()
{
double dblAMA0 = f_AMA(intAMAPe, intMAFPe, intMASPe, 0);
double dblAMA1 = f_AMA(intAMAPe, intMAFPe, intMASPe, 1);
double dblAMA2 = f_AMA(intAMAPe, intMAFPe, intMASPe, 2);
Comment( "\n", "AMA[0]: ", DoubleToStr(dblAMA0, 4),
"\n", "AMA[1]: ", DoubleToStr(dblAMA1, 4),
"\n", "AMA[2]: ", DoubleToStr(dblAMA2, 4));
}
//*********************************************************************************************
double f_AMA(int per, int efp, int esp, int shi)
{
/*
Описание:
Функция осуществляет расчет адаптированной скользящей средней Кауфмана (АМА)
Параметры:
per - период скользящей средней Кауфмана
efp - период быстрой экспоненциальной скользящей средней
esp - период медленной экспоненциальной скользящей средней
shi - номер бара на котором рассчитывается АМА
*/
double dbl_Noise = 0, dbl_Signal, dbl_ER, dbl_SSC;
double dbl_AMA[];
ArrayResize(dbl_AMA, Bars - per - 1);
double dbl_SlowSC = (2.0 / (esp + 1));
double dbl_FastSC = (2.0 / (efp + 1));
if(Bars <= (per + 2)) return(0);
int pos = Bars - per - 2;
double dbl_AMA0 = Close[pos + 1];
while(pos >= 0)
{
if(pos == Bars - per - 2) dbl_AMA0 = Close[pos + 1];
dbl_Signal = MathAbs(Close[pos] - Close[pos + per]);
dbl_Noise = 0;
for(int i = 0; i < per; i++)
{
dbl_Noise = dbl_Noise + MathAbs(Close[pos + i] - Close[pos + i + 1]);
}
dbl_ER = dbl_Signal / dbl_Noise; // коэффициент эффективности
dbl_SSC = dbl_ER * (dbl_FastSC - dbl_SlowSC) + dbl_SlowSC;
dbl_AMA[pos] = dbl_AMA0 + (MathPow(dbl_SSC, 2) * (Close[pos] - dbl_AMA0));
dbl_AMA0 = dbl_AMA[pos];
pos--;
}
return(dbl_AMA[shi]);
}