Вопрос по весам ЕМА

 

По просьбе форумчан переношу свою писанину в отдельную ветку, чтобы не захламлять ту ветку, которая была создана для того чтобы не захламлять форум.

 Разбирая алгоритм ЕМА с целью в т.ч. возможной оптимизации, решил исследовать генерируемые ею веса. Как известно, там рекурсия. По оригиналу кода:

//+------------------------------------------------------------------+
//| Exponential Moving Average                                       |
//+------------------------------------------------------------------+
void ema()
  {
   double pr=2.0/(MA_Period+1);
   int    pos=Bars-2;
   if(ExtCountedBars>2) pos=Bars-ExtCountedBars-1;
//---- main calculation loop
   while(pos>=0)
     {
      if(pos==Bars-2) ExtMapBuffer[pos+1]=Close[pos+1];
      ExtMapBuffer[pos]=Close[pos]*pr+ExtMapBuffer[pos+1]*(1-pr);
        pos--;
     }
  }

 Взял маткад:

 

 Возник следующий вопрос: зачем надо так высоко задирать последний вес, если можно просто обернуть степенную функцию на по возрастанию, если последующий вес так важнее предыдущего? Попробовал написать скрипт, чтобы протестировать миллисекунды для расчёта ЕМА по рекурсии и по выведенной формуле конечных весов после её окончания (см. F(n,x) в маткадовской портянке)

int ms1, ms2;
double ema1, ema2;

int start(){
        for(int i=2; i<(Bars-1)/2; i++){
                ms1=GetTickCount();
                for(int j=0; j<=i; j++){
                        if(j==0) ema1=Close[0];
                        ema1=Close[j]*(2/(i+1))+ema1*(1-(2/(i+1)));
                }
                ms1=GetTickCount()-ms1;
                ms2=GetTickCount();
                for(j=0; j<i; j++){
                        ema2=ema2+(2/(i+1))*MathPow((i-1)/(i+1),j)*Close[j];
                }
                ema2=ema2+MathPow((i-1)/(i+1),j)*Close[j];//j, а не j+1, т.к. инкремент при выходе из цикла уже ПРОИЗОШЁЛ
                ms2=GetTickCount()-ms2;
                Print("Период=", i, ", время выполнения(мс): ema1=", ms1, ", ema2=", ms2);
        }
        Alert("всё");
}

  - разницу что-то не ощутил, всё укладывается в нормальное распределение. Значит, можно рассчитывать как рекурсией, так и по формуле (в т.ч. какой-то другой для этой машки, напр. y(n, x) или инвертированной), на быстродействие они влияют одинаково. Вот выборка из лога:

18:33:08 ProverkaEMA EURUSD,M1: Период=2839, время выполнения(мс): ema1=78, ema2=47
18:33:40 ProverkaEMA EURUSD,M1: Период=3764, время выполнения(мс): ema1=47, ema2=63
18:34:16 ProverkaEMA EURUSD,M1: Период=4520, время выполнения(мс): ema1=63, ema2=187
18:34:16 ProverkaEMA EURUSD,M1: Период=4530, время выполнения(мс): ema1=94, ema2=63
18:34:27 ProverkaEMA EURUSD,M1: Период=4727, время выполнения(мс): ema1=47, ema2=94
18:34:33 ProverkaEMA EURUSD,M1: Период=4854, время выполнения(мс): ema1=47, ema2=47
18:34:35 ProverkaEMA EURUSD,M1: Период=4878, время выполнения(мс): ema1=125, ema2=265
18:34:38 ProverkaEMA EURUSD,M1: Период=4949, время выполнения(мс): ema1=78, ema2=109
18:34:50 ProverkaEMA EURUSD,M1: Период=5156, время выполнения(мс): ema1=297, ema2=47
18:34:58 ProverkaEMA EURUSD,M1: Период=5286, время выполнения(мс): ema1=78, ema2=125
18:35:07 ProverkaEMA EURUSD,M1: Период=5438, время выполнения(мс): ema1=47, ema2=47
18:35:10 ProverkaEMA EURUSD,M1: Период=5495, время выполнения(мс): ema1=62, ema2=47
18:35:19 ProverkaEMA EURUSD,M1: Период=5628, время выполнения(мс): ema1=188, ema2=78
18:35:25 ProverkaEMA EURUSD,M1: Период=5719, время выполнения(мс): ema1=109, ema2=78
18:35:26 ProverkaEMA EURUSD,M1: Период=5740, время выполнения(мс): ema1=93, ema2=94
18:35:26 ProverkaEMA EURUSD,M1: Период=5743, время выполнения(мс): ema1=78, ema2=47
18:35:36 ProverkaEMA EURUSD,M1: Период=5874, время выполнения(мс): ema1=47, ema2=78
18:35:37 ProverkaEMA EURUSD,M1: Период=5891, время выполнения(мс): ema1=62, ema2=78
18:35:37 ProverkaEMA EURUSD,M1: Период=5902, время выполнения(мс): ema1=109, ema2=47
18:35:41 ProverkaEMA EURUSD,M1: Период=5958, время выполнения(мс): ema1=94, ema2=109
18:35:43 ProverkaEMA EURUSD,M1: Период=5986, время выполнения(мс): ema1=47, ema2=47
18:35:45 ProverkaEMA EURUSD,M1: Период=6001, время выполнения(мс): ema1=109, ema2=250
18:35:48 ProverkaEMA EURUSD,M1: Период=6045, время выполнения(мс): ema1=141, ema2=312

 Лог прикрепляю. Там я убрал все строки со значениями ema1 или ema2, равными 0, 15, 16 (погрешность GetTickCount() по Рошу), а в вышеприведённой выборке из той выборки убраны и все значения с 31, 32.

 Кстати говоря, как постскриптум: теперь я понял, почему во многих индикаторах, использующих "экспотенциальную" машку (хотя правильнее её назвать степенной), стоит период равный 14...

Прикрепляю также маткад, всё в архиве. Маткад одиннадцатый. Итак - зачем нужно задирать последний вес? Или я где-то глупо ошибся?... 

Файлы:
logs.zip  37 kb
 
не вдаваясь в детали- где то ошибка с весами (https://ru.wikipedia.org/wiki/%D0%AD%D0%BA%D1%81%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%81%D0%B3%D0%BB%D0%B0%D0%B6%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
 
YOUNGA:
не вдаваясь в детали- где то ошибка с весами (экспотенциальное сглаживание)

Получается то же самое. Это только другая форма записи, в маткадовской портянке ЕМА описана так же. Благодарю, значит с весами в портянке ошибки нет. 

 

Сначала комент по преобразованиям

(1) Вас не смущает такие тестовые выводы по вашей формуле

и      

Явное расхождение между количеством членов цВР и количеством весовых коэффициентов. Похоже напутали с индексами. Ниже свой вариант



(2) Откуда вы вывели  формулу  F(n,x) (" разложение этой рекурсии в ряд " )

Отсюда


P.S. Я с EMA  не работал, могу ошибаться, проверяйте

 

По замеру времени вычисления с помощью GetTickCount() на таких малых промежутках времени ничего не скажу. По моему это одна из тех фич что делает нашу жизнь ... веселее )

А вот это заинтересовало

gyfto: ... Кстати говоря, как постскриптум: теперь я понял, почему во многих индикаторах, использующих "экспотенциальную" машку (хотя правильнее её назвать степенной), стоит период равный 14...
Объясните
 
GaryKa:

А вот это заинтересовало

Объясните

Это с ходу могу. Смотрите. Так как (по моему варианту, согласен) имеем разложение рекурсии в ряд, состоящий из трёх узловых значений: первое, последнее и предпоследнее (или первое, последнее и второе, смотря с какого конца считать), то, если смотреть графики функций их изменения (этих узловых точек от рекурсии к рекурсии), то они пересекаются в точках 3 и 14. Вторая функция - это вес Close[0], третья - Close[Bars-2], четвёртая - Close[Bars-1]. Первая это лишнее, формула рекурсии без остаточного члена.

 

 Тут необходимое пояснение. Как такового периода в смысле окна свечей у ЕМА нет. То, что передаётся как период в ЕМА - это просто договорённость, возможность хоть какого-то управления функцией. Это значение, период больше единицы, инвертируется в значение меньше единицы, которое и используется как множитель эдакой геометрической прогрессии, суммой которой и является ЕМА. То есть например в SMA и WMA период - это окно свечей, т.е. заданное этим периодом их количество, из которых берётся средняя величина, например Close, и отображается как точка непрерывной линии на месте правой границы этого диапазона (окна). В ЕМА количество свечей для подсчёта их среднего значения увеличивается с каждым шагом рекурсии. То есть, говоря простыми словами, с появлением нового бара и продолжением ЕМА вправо возникающая точка машки - это среднее значение всех баров истории. Это я не вам объясняю, это я говорю то, что сам понял, осознал.

По поводу того, зачем так высоко забирать последний вес (это вес Close[Bars-1] кстати). Так пока и не понял, но увидел, что будет, если не забирать. Итак, немного меняем формулу рекурсии:

β=1-α. По левую сторону у нас старый вариант, по правую - чуть-чуть, самую малость изменённый, и что из этого получается. Получается вообщем-то искомый вариант без забора высоты. Меняем код ЕМА. Изменения касаются только формулы начального члена:

//+------------------------------------------------------------------+
//| Exponential Moving Average                                       |
//+------------------------------------------------------------------+
void ema()
  {
   double pr=2.0/(MA_Period+1);
   int    pos=Bars-2;
   if(ExtCountedBars>2) pos=Bars-ExtCountedBars-1;
//---- main calculation loop
   while(pos>=0)
     {
      if(pos==Bars-2) ExtMapBuffer[pos+1]=pr*Close[pos+1];
      ExtMapBuffer[pos]=Close[pos]*pr+ExtMapBuffer[pos+1]*(1-pr);
        pos--;
     }
  }

 Вешаем обе ЕМА, обычную и модифицированную, ставим shift=1 и разный цвет чтобы не путаться, идём на начало истории, смотрим:


 Видал подобную картинку где-то здесь на форуме, но не помню где, может кто-то напомнит.

 Сейчас буду разбираться в предложенных материалах.

 
gyfto:

Это с ходу могу. Смотрите. Так как (по моему варианту, согласен) имеем разложение рекурсии в ряд, состоящий из трёх узловых значений: первое, последнее и предпоследнее (или первое, последнее и второе, смотря с какого конца считать), то, если смотреть графики функций их изменения (этих узловых точек от рекурсии к рекурсии), то они пересекаются в точках 3 и 14. Вторая функция - это вес Close[0], третья - Close[Bars-2], четвёртая - Close[Bars-1]. Первая это лишнее, формула рекурсии без остаточного члена.

 


Дык неправильно у вас, последний член никуда не задирается, он ведет себя точно так же, как и все остальные (уменьшается), ни с чем не пересекается и в пределе равен 0. Ищите ошибку в расчетах.


Как такового периода в смысле окна свечей у ЕМА нет. То, что передаётся как период в ЕМА - это просто договорённость, возможность хоть какого-то управления функцией.

Называетя "характерный временной параметр". Подбирается так, чтобы средняя временая задержка SMA и EMA с одинаковыми периодами была примерно одинакова.

 
GaryKa:

(2) Откуда вы вывели  формулу  F(n,x) (" разложение этой рекурсии в ряд "

Отсюда


P.S. Я с EMA  не работал, могу ошибаться, проверяйте

alsu:

последний член никуда не задирается



Упростите кто-нибудь подчёркнутое выражение и вынесите альфа за общие скобки, а то у меня ничего не получается.

GaryKa:

Явное расхождение между количеством членов цВР и количеством весовых коэффициентов. Похоже напутали с индексами.


 Совершенно верно. Я понял, в чём была ошибка - в привычке. У меня привычка начинать счёт с нуля. Соответственно от нуля до двух будет три элемента. Здесь же мы считаем элементы не по порядку их расположения (0, 1, 2...), а по их количеству (1, 2, 3...).

 
gyfto:



Упростите кто-нибудь подчёркнутое выражение и вынесите альфа за общие скобки, а то у меня ничего не получается.


Не вынесется она, да и не надо.

Кстати, быстрый способ посчитать коэффициенты рекурсивного фильтра - через z-преобразование.

Я, кажется, понял, почему у вас "задирается". Чем "медленнее" машка, тем медленнее должны убывать коэффициенты, следовательно, остаточный член (сумма всего того, что вы выбрасываете) тем больше, чем больше период маши. Проблема в расчетах в том, что вы начинаете с c0 (начальная инициализация), а положено начинать с EMA0. Понятно, что ее еще нет до начала истории баров, поэтому в коде обычно заменяют на SMA. По-моему в стандартной машке МТ так и написано, поправьте, если я неправ.

 
gyfto: Упростите кто-нибудь подчёркнутое выражение и вынесите альфа за общие скобки, а то у меня ничего не получается.

А чего тут упрощать-то. Выражение в квадратных скобках - это EMA2 (смотри формулу). Соответственно

EMA3 = alpha*c3 + (1-alpha)*EMA2.

Альфу за общие скобки выносить не надо.

 
Mathemat:

А чего тут упрощать-то. Выражение в квадратных скобках - это EMA2 (смотри формулу). Соответственно

EMA3 = alpha*c3 + (1-alpha)*EMA2.

Альфу за общие скобки выносить не надо.


Угу, и приходим опять к формуле рекурсии)))

Так, я кажется разобрался. Причина была в неправильном объявлении функций. У ЕМА (только под скальпелем, конечно) три параметра: период, шаг рекурсии и порядковый номер веса в многочлене, генерируемом рекурсией на этом шаге. Период и обратная ему альфа нигде, никоим образом, никем и никак не меняются, это константы. Шаг рекурсии и порядковый номер веса легко спутать, т.к. максимальное значение порядкового номера веса равно этому шагу рекурсии. Соответственно имеем (это только заголовок портянки):

  

Сама портянка выглядит вот так:

 

Ничто нигде у машки на Close[0] после прохождения порядка двух тысяч итераций рекурсии после Close[Bars-1] не задирается... 

Портянку маткада прикрепляю, там можно и поэкспериментировать с периодом. Маткад, повторюсь, одиннадцатый. Проверяйте, вдруг где-то ошибся.

Файлы:
4.zip  128 kb
Причина обращения: