Статьи по MQL4
Построение средней

Построение средней


например, forex

Мы узнали, как создать индикатор, который рисует символы/стрелки на пересечениях двух средних с разным периодом. Теперь мы напишем индикатор, который строит простую скользящую среднюю. Скользящие средние одни из самых важных в техническом анализе, на их основе строится подавляющая часть других индикаторов, как стандартных, так и разрабатываемых самими трейдерами. Скользящая средняя характеризуется периодом расчета, типом цен, по которым рассчитывается и смещением. Если мы хотим рассчитать простую среднюю с периодом 3 по ценам закрытия, то мы должны взять сумму: ( цена закрытия сегодня + цена закрытия вчера + цена закрытия позавчера)/3.
МА(3,Close)=(Close[0]+Close[1]+Close[2])/3.
Обратимся опять к «Мастеру создания Советника». Создадим параметр PeriodMA и ShiftMA (смещение).

 
 

Следующим шагом добавим индекс , тип и цвет оставим как есть, жмем «Готово».

 
 

Получили стандартный шаблон:

 
 

Добавим в блок start() часть кода из индикатора CrossMA-3, чтобы не писать заново цикл и служебные переменные.

 
 


Мы уже хорошо представляем как происходит работа в цикле for(), теперь мы можем заменить цикл for() на цикл while(). Выносим объявление переменной i (int i=limit;) за пределы for() перед циклом, операцию декремента (i--;) вносим в тело цикла в самый конец, цикл for переименовываем на while:

 
 

Как видим, цикл while() полностью заменил цикл for(). Также производится проверка выражения в скобках на истинность, и если оно соблюдается, то выполняется тело цикла. При этом важно не забыть вставить в цикл оператор уменьшения счетчика i, иначе мы получим бесконечный цикл. Компилятор такую ошибку обнаружить не сможет (так как она не синтаксическая, а логическая), и при использовании такого неправильного индикатора (с бесконечным циклом) терминал просто зависнет и перестанет реагировать на действия пользователя. Единственный способ выхода из такой ситуации – закрыть принудительно из диспетчера задач терминал, открыть MetaEditor, исправить индикатор и можно снова запускать MetaTrader4. Но в скриптах использовать бесконечный цикл можно.

 
 

Применение цикла while() или for() обычно является делом вкуса, хотя бывают ситуации, когда while() предпочтительней , например, если необходимо двигаясь от текущего бара в глубь истории (в сторону увеличения индекса бара) найти некий бар, удовлетворяющий какому-то условию. При этом необходимо не забыть, что искомый бар может и не быть найденным, а индекс бара будет расти до бесконечности. И чтобы избежать зацикливания, необходимо добавить проверку индекса на превышение числа Bars. Пример такого цикла:

 
 

Цикл у нас есть, теперь осталось написать алгоритм вычисления суммы на количестве баров PeriodMA, то есть что-то подобное:

val=(Close[i]+Close[i+1]+Close[i+2]+… Close[i+n])/PeriodMA

Чему будет равно n, если известно PeriodMA (период нашей средней)? Есть люди, которые легко вычислят нужную формулу в уме, я много раз ошибался сам, когда проделывал это без помощи бумаги и ручки, поэтому более надежно будет пойти методом индукции. Времени займет минуту, а правильность результата гарантирует.
Возьмем частный случай, n=5, то есть как будто мы ищем среднее за 5 баров. Тогда наша формула выглядит так:

Val=(Close[i]+Close[i+1]+Close[i+2]+Close[i+3]+Close[i+4])/5

или по-другому:

Val=(Close[i]+Close[i+1]+…+Close[i+PeriodMA-2]+Close[i+PeriodMA-1])/PeriodMA

Такое механическое суммирование мы легко поместим опять-таки в цикл for().

 
 

В данном случае мы использовали оба типа циклов, получилось удобное визуальное разделение алгоритма прохода по барам графика и алгоритма суммирования цен. Теперь опять вернемся к началу блока start(). Как видно из рисунка, устанавливать ограничитель расчета limit при первом вызове индикатора в значение Bars-1 нет никакого обоснования, баров в глубине истории нет и усреднять еще нечего. Если мы для примера хотим рассчитать среднюю с периодом 5, то вычислять эту среднюю мы можем начать только с бара Bars-5 (см. статью «Что такое графики»).

 
 

Поэтому, в первый раз, когда counted_bars равно нулю логично записать:

 
 

На этом создание индикатор простой скользящей средней по ценам закрытия можно считать законченным, но иногда возникает соблазн создать максимально оптимизированный индикатор, и делается попытка улучшить и ту часть блока start(), где counted_bars уже больше нуля, то есть первоначальный расчет индикатора уже проводился. Исходя из соображений, что после первого прогона индикатора Bars не изменился, расчет индикатора производился на количестве баров от Bars-PeriodMA до нуля (то есть counted_bars предполагается равным примерно Bars-PeriodMA), пишется следующее :

 
 

Так как преследуется цель считать только на нулевом баре, то можно предположить, что limit=0 и 0=Bars-counted_bars-PeriodMA. Отсюда следует, что мы исходим из того, что при втором прогоне индикатора counted_bars+PeriodMA==Bars. На самом деле это не так, это вторая ошибка оптимизации, я называю такой индикатор пережатым. Функция IndicatorCounted() не возвращает количество баров, для которых был сделан расчет значений данным конкретным индикатором, а возвращает количество баров, которые не изменились с последнего вызова индикатора (нулевой бар менялся, иначе бы не пришел этот тик, на котором мы и производим проверку). Поэтому, если Bars=1000, то при первом вызове индикатора IndicatorCounted() вернет 0 (индикатор еще не рассчитывался), а при втором вызове IndicatorCounted() вернет уже Bars-1. Вы сами может проверить это , создав пустой индикатор (в котором не производится вообще никаких расчетов) и вставив в блок start() вызов
Print("Bars=",Bars,"  counted_bars=",counted_bars);
Если мы все же не заметим этой ошибки и оставим наш индикатор таким как есть(переоптимизированным или пережатым) то произойдет следующее ( пусть у нас Barsравно 1000, а PeriodMA равно 5):
  1. в первый раз индикатор рассчитается правильно от бара Bars-PeriodMA до нулевого бара
  2. на следующем тике проверка counted_bars окажется больше нуля и ограничитель расчета станет равным limit=1000-999-5= 1-5=-4
  3. в блок while() (или for(), вид цикла не имеет значения) поступает ограничитель, который меньше нуля и производится проверка while(-4>=0) , проверка оказывается неудачной , и пересчет на нулевом баре не производится.

Выявить такую ошибку можно двумя способами:
  1. запустить индикатор на мелком тайм-фрейме и наблюдать его поведение
  2. прогнать в тестере советник, содержащий вызов нашего индикатора.
Для данного индикатора наиболее простым вариантом проверки будет первый. Компилируем неправильный индикатор и набрасываем на EURUSD M15, ждем полчаса, чтобы появилось два новых бара и видим такую картину.

 
 


К счастью, в данном случае ошибка расчета индикатора при работе в он-лайн быстро становится явной(индикатор просто не рисуется), но в более сложных случаях значение индикатора просто плывет и на глаз увидеть это не всегда можно. Скачать индикаторы Simply MA.mq4 и Simply MA wrong.mq4 можно здесь .


Перейти к статье «Построение средней (окончание)».
 
+7 (495) 710-76-76
8 (800) 200-01-31
по России бесплатно

закрыть

Вход в личный кабинет

Для счета alpari.classic введите номер счета (буква и 4 цифры) и пароль в ЛК.

Для счетов alpari.micro и alpari.partner введите логин и пароль в МТ.

Зарегистрироваться!Забыли пароль?

 
Rambler's Top100