Рождение эксперта. Простейший индикатор на 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); } |
Вот, в принципе, и все. Простейший индикатор построен и теперь, вы можете поэкспериментировать с настройками и параметрами, влияющими на рисование индикатора.
Продолжение следует …