Рождение эксперта. Простейший индикатор на MQL4.

Для того, чтобы научиться самому писать индикаторы на MQL4, необходимо разобраться в том, как происходит построение линий индикатора. Зачем нужны те или иные функции и параметры. Сложного в этом ничего нет, просто надо сесть и попробовать написать свой первый индикатор.

Главное - начать.
Предлагаю начать с самого простого – нарисовать индикатор, который рисует линию, соединяющую цены High баров на графике. Этот, достаточно простой пример, позволит понять принцип построения индикаторов на графике.

Для начала определим специфические параметры индикатора с помощью указателя #property:

#property  copyright "autoforex"
#property  link ""

С этими значениями все понятно, они обычно вставляются во все программы MQL4 и не являются обязательными, но лучше их все же вписать в программу (естественно подставляя свои значения). Эти данные нужны лишь для того, чтобы определить автора скомпилированного файла. Сам файл зашифрован и единственное, что можно разобрать в начале этого файла, открыв его в текстовом редакторе, это информацию, описанную в этих двух строчках.

Внешние настройки индикатора.
Далее определяем основные настройки, влияющие на рисование индикатора:

#property  indicator_chart_window

Указываем терминалу, что индикатор необходимо рисовать в том же окне, где и сам график. Для того, чтобы индикатор строился в отдельном окне необходимо заменить эту строку на - #property indicator_separate_window.

Затем, определяем количество буферов для расчета индикатора:

#property  indicator_buffers 1

Или, другими словами - определяем, сколько линий мы будем рисовать на графике. В нашем простейшем случае, это будет одна линия, поэтому нам нужен всего один буфер. В случае, например, с индикатором "Alligator" на графике изображаются три линии – поэтому требуется три буфера и в коде alligator.mq4, который поставляется вместе с MetaTrader 4, вы обнаружите следующую строчку кода: #property indicator_buffers 3.

Далее задаем цвет - Red (красный), которым будет отображаться линия:

#property  indicator_color1  Red

Для каждой линии можно задать свой цвет. В нашем случае будет использована только одна линия для индикатора, поэтому и цвет задаем только для одной - первой линии. В том же alligator.mq4 цвет линий задан следующим образом:

#property indicator_color1 Blue
#property indicator_color2 Red
#property indicator_color3 Lime

Три линии – три цвета.

Далее определяем толщину линии:

#property  indicator_width1 2

Здесь мы задаем толщину линии индикатора равную 2. Теперь линия под номером один будет изображаться на графике толщиной равной 2.

Затем определяем стиль рисования линии:

#property  indicator_style1 0

Стиль рисования линии 0 – простая линия. Можно выбрать из пяти различных стилей – пунктирная линия, штрихпунктирная и др. Заметьте, что различные стили рисования линии можно применять только в том случае, если ширина данной линии равна единице. Если ширина линии больше единицы, то терминал позволяет рисовать только сплошной линией. Поэтому в нашем случае, т.к. выбрана толщина линии 2 пикселя, мы ставим нулевой стиль. Поставь мы другой стиль, наш индикатор все равно будет нарисован простой линией.

Это были основные настройки индикатора, которые чаще всего используются. Если эти параметры не прописать в коде программы, то при наложении индикатора на график появится окно, в котором будет предложено выбрать цвет и толщину линии, а так же другие внешние настройки индикатора, в том числе и стиль линии.

Если внешние значения индикатора прописать в коде программы, как это сделали мы для цвета, толщины линии и стиля рисования, то при наложении индикатора на график так же появится окно с настройками. Но в окне уже будут выбраны соответствующие цвет толщина линии и стиль ее рисования, поэтому останется лишь подтвердить выбор, нажав "ОК". Это существенно экономит время даже в нашем, простейшем случае, я уже не говорю об индикаторах, в которых отображаются все восемь линий.

Затем, в программе идет объявление массива Buffer1[]:

double     Buffer1[];

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

Для чего нужен этот массив. Этот массив мы, с помощью функции SetIndexBuffer(), свяжем с предопределенным буфером индикатора. И затем, чтобы нарисовать линию на графике, мы просто запишем в массив Buffer1[] соответствующие значения для данной линии. А терминал, воспринимая наш массив Buffer1[], как массив со значениями, которые следует отобразить на графике, нарисует линию. И любые изменения в массиве Buffer1[] будут отображаться на графике.

Инициализация.
Далее в коде следует функция инициализации индикатора:

int init()
  {
   SetIndexBuffer(0,Buffer1);
   SetIndexStyle(0,DRAW_LINE);
   return(0);
  }

Функция init() – функция инициализации, в данном случае индикатора, вызывается один раз при наложении индикатора на график. Внутри этой функции производят настройку индикатора – выполняют операции, которые необходимо выполнить один раз до запуска индикатора.

SetIndexBuffer(0,Buffer1); - как упоминалось ранее, эта функция связывает массив Buffer1[] с нулевым буфером индикатора. Всего буферов – 8 (считая с 0 до 7), т.е. с помощью одного индикатора можно нарисовать на графике восемь линий. Но т.к. в нашем случае отображается всего лишь одна линия, то нам требуется только один буфер – буфер номер 0. Теперь, чтобы записать информацию в нулевой буфер, тем самым, отобразив ее на графике, необходимо записать ее в массив Buffer1[].

SetIndexStyle(0,DRAW_LINE); - устанавливаем новый тип, стиль, ширину и цвет для линии индикатора (нулевой буфер индикатора). Первый параметр, равный 0 - номер буфера линии. Второй параметр, равный DRAW_LINE задает тип рисования линии. В нашем случае – простая линия. Третий, четвертый и пятый параметры этой функции – необязательные параметры. С их помощью можно изменить стиль, толщину и цвет отображения линии соответственно. В нашем случае в этом нет необходимости, т.к. нужные нам значения уже определены в начале программы с помощью инструкций #property и поэтому эти параметры отсутствуют в вызове функции SetIndexStyle().

return(0); – завершаем выполнение функции init();

Индикатор.
Теперь переходим к самому главному – рисованию линии индикатора на графике. Давайте, для начала соединим значения High первых семи баров на графике, при этом полный код индикатора примет вид:

#property  copyright "autoforex"
#property  link      ""

#property  indicator_chart_window
#property  indicator_buffers 1
#property  indicator_color1  Red
#property  indicator_width1 2
#property  indicator_style1 0

double     Buffer1[];

int init()
  {
   SetIndexBuffer(0,Buffer1);
   SetIndexStyle(0,DRAW_LINE);
   return(0);
  }

int start()
  {
         Buffer1[0]=High[0];
         Buffer1[1]=High[1];
         Buffer1[2]=High[2];
         Buffer1[3]=High[3];
         Buffer1[4]=High[4];
         Buffer1[5]=High[5];
         Buffer1[6]=High[6];
         Buffer1[7]=High[7];
         Buffer1[8]=High[8];

         return(0);
  }

Вот что мы получим в результате, когда прикрепим индикатор к графику:

Построение индикатора на графике

На рисунке представлен наш индикатор, который нарисован по следующим значениям:

Buffer1[0]=1.4767
Buffer1[1]=1.4707
Buffer1[2]=1.4784
Buffer1[3]=1.4842
Buffer1[4]=1.4857
Buffer1[5]=1.4906
Buffer1[6]=1.4886
Buffer1[7]=1.4966
Buffer1[8]=1.4872
Buffer1[9]=Empty_Value
Buffer1[10]=Empty_Value
и т.д.

Как видите, первые девять баров в точках High, начиная с нулевого, соединены линией индикатора.

Массив Buffer1[].
Несколько слов по поводу размера массива Buffer1[]. Размер массива Buffer1[] равняется количеству баров на текущем графике (т.е. на том, на котором находится индикатор). И, соответственно, совпадает со значением предопределенной переменной Bars. Если, например, у вас на текущем графике 56300 минутных баров, и вы запускаете индикатор на этом графике, то размер массива Buffer1[] будет равен 56300 ячеек. Это также означает, что на этом графике мы сможем построить линию состоящую из 56300 точек.

В нашем простейшем случае мы определили значения первых девяти точек нашего индикатора, поэтому они были построены на графике. Все остальные ячейки массива Buffer1[], по умолчанию, принимают значение равное EMPTY_VALUE (значение пустой величины). Пустые значения не рисуются на графике, вот почему мы видим линию индикатора только до восьмого бара. Все остальные значения индикатора равны пустому значению EMPTY_VALUE и не отображаются на графике.

Построение индикатора.
Теперь давайте разберемся, как происходит построение индикатора на графике.
Мы скомпилировали наш индикатор и наложили его на график, например, EUR/USD H1 для которого уже загружено, например, 674 бара (цифра взята из головы, просто для демонстрации примера).

При этом произойдет следующее:

Будет создан массив Buffer1[] размером 674 ячейки, во все ячейки по умолчанию запишется значение EMPTY_VALUE. Затем выполнится функция start() и в ней первым девяти ячейкам массива Buffer1[] будут присвоены определенные значения цен, которые и отобразятся в виде индикатора на графике.

С приходом нового тика, продолжающего формировать нулевой бар, будет выполнена функция start(). И снова в ней первым девяти ячейкам массива Buffer1[] будут присвоены те же самые значения цен, которые уже записаны в этом массиве (т.к. бары на графике не изменились и значения High этих баров так же не изменились). Исключение составляет лишь нулевая ячейка массива – Buffer[0]. В нее будет записано новое значение величины High нулевого бара (если, конечно, оно изменилось с приходом нового тика).

Получается, что большинство точек индикатора не нуждаются в пересчете и перерисовке. Для того, чтобы оптимизировать построение индикатора, пользуются функцией IndicatorCounted(), … но об этом в другой статье.

Появление нового бара на графике.
Теперь, давайте разберем ситуацию, когда с приходом нового тика начинает формироваться новый бар. В этом случае новый бар, который выглядит как черточка, автоматически становится нулевым баром, а тот, что был нулевым – становится теперь первым, и таким образом смещается вся нумерация баров. При этом значение переменной Bars увеличивается на 1 и становится равной 675, и размер массива Buffer1[] также увеличивается на 1 и тоже становится равным 675.

Кроме того, что размер массива Buffer1[] увеличивается на единицу, все значения хранимые в нем смещаются на одну ячейку – то, что раньше хранилось в ячейке Buffer1[0], копируется в ячейку Buffer1[1], то, что раньше хранилось в Buffer1[1] копируется в Buffer1[2] и т.д. Из ячейки Buffer1[8] значение копируется в Buffer1[9]. Более наглядно этот процесс показан на рисунках:

Построение индикатора на графике Построение индикатора на графике

Все эти смещения нумераций и перемещения данных в массиве Buffer1[] происходят в автоматическом режиме. После этого начинает выполняться функция start() индикатора. В ней происходит присвоение значений первым девяти ячейкам массива Buffer1[]. Таким образом, первые девять точек индикатора (Buffer1[0] – Buffer1[8]) будут заново определены. Но, т.к. в результате смещения нумерации баров в ячейку Buffer1[9] уже скопировано значение из ячейки Buffer1[8], то наш индикатор будет уже состоять из десяти точек соединенных линией.

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

Функцию start() можно значительно сократить и записать так:

int start()
  {
    Buffer1[0]=High[0];
    return(0);
  }

Такой индикатор будет соединять линией цены High всех вновь появляющихся баров, в реальном времени.

Индикатор на весь график.
Для того чтобы построить линию на протяжении всего графика, а не только на первых или появляющихся в реальном времени барах, нужно воспользоваться циклом и присвоить все необходимые значения соответствующим ячейкам массива Buffer1[]. Для этого перепишем функцию start() следующим образом:

int start()
  {
   for(int i=0;i<Bars;i++)
   {
      Buffer1[i]=High[i];
   }
   return(0);
  }

В данном случае мы перебираем все бары от 0 до Bars-1 и присваиваем ячейкам массива Buffer1[] значения High соответствующего бара. При этом линия индикатора будет нарисована на протяжении всего ценового графика.

Наш индикатор выглядит теперь так:

#property  copyright "autoforex"
#property  link      ""

#property  indicator_chart_window
#property  indicator_buffers 1
#property  indicator_color1  Red
#property  indicator_width1 2
#property  indicator_style1 0

double     Buffer1[];

int init()
  {
   SetIndexBuffer(0,Buffer1);
   SetIndexStyle(0,DRAW_LINE);
   return(0);
  }
int start()
  {
   for(int i=0;i<Bars;i++)
   {
      Buffer1[i]=High[i];
   }
   return(0);
  }

Вот, в принципе, и все. Простейший индикатор построен и теперь, вы можете поэкспериментировать с настройками и параметрами, влияющими на рисование индикатора.

Продолжение следует …