|
|
|
|
|
|
|
|
|
Теперь мы вплотную подошли к пониманию пользовательских индикаторов в МТ4. Сделаем настоящий, а не графический индикатор по сигналам пересечения двух скользящих средних (МА). Файл CrossMA.csv содержит столбцы «Стрелка вверх» и «Стрелка вниз». Каждому бару однозначно в текущий момент времени соответствует время открытия бара (Time[]), номер бара (который будет увеличиваться с каждым новым завершенным баром) и значения из двух столбцов/массивов, указывающих на наличие красной или синей стрелки, или отсутствие обеих (нулевое значение). Создадим пользовательский индикатор с помощью «Мастера создания советника».
|
|
|
|
Укажем имя индикатора (CrossMA), автора, линк. Рядом с таблицей параметров жмем кнопку «Добавить», появляется новый параметр ExtParam1 (имя параметра по умолчанию ), даем новому параметру более осмысленное название LongPeriod, как в нашем предыдущем скрипте, тип int оставляем неизменным, начальное значение задаем равным 21.
|
|
|
|
Добавляем еще один параметр ShortPeriod, работа с внешними параметрами нашего индикатора на этом закончена. Идем «Далее». Чек-бокс «Индикатор в отдельном окне» не трогаем, наши стрелки будут располагаться на графике цен (Чек-боксы «Минимум» и «Максимум» поэтому нам недоступны). Опять жмем «Добавить», в списке индексов на строчке 1 появляется индекс типа «Line» и красного цвета («Red»), меняем тип на «Arrow» цвет на голубой «Blue». Тип символа 217(стрелка вверх) поменяем на 241 для полного сходства со скриптом.
|
|
|
|
Добавим второй индекс, также изменим все его данные (тип, цвет, символ).
|
|
|
|
#property copyright "MetaQuotes"
#property link "http://forum.alpari-idc.ru/viewtopic.php?t=48186"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
//---- input parameters
extern int LongPeriod=21;
extern int ShortPeriod=13;
//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
//----
int init()
{
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,241);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexEmptyValue(0,0.0);
SetIndexStyle(1,DRAW_ARROW);
SetIndexArrow(1,242);
SetIndexBuffer(1,ExtMapBuffer2);
SetIndexEmptyValue(1,0.0);
//----
return(0);
}
//----
int deinit()
{
//----
//----
return(0);
}
//----
int start()
{
int counted_bars=IndicatorCounted();
return(0);
}
Мастер по созданию советников сделал черновую работу, мы видим, что индикатор будет выводиться на графике цен, а не в отдельном окне, индикатор содержит два служебных буфера, указаны их цвета, объявлены массивы
double ExtMapBuffer1[];
double ExtMapBuffer2[];
в которых, видимо, и будут храниться значения индикатора.
Также созданы два входных параметра.
|
|
|
|
По сравнению с тем, как мы создавали скрипт, при создании индикатора была также создана функция init(), в которой производится окончательная настройка нашего индикатора. Индикаторы в МТ4 обладают очень большой гибкостью, каждый индикатор может «нести» в себе до 8 служебных(индикаторных) буферов. При этом достаточно только правильно объявить эти буфера, а остальную заботу о размере этих буферов возьмет на себя терминал. Эти буфера также называются индексами, пользовательский индикатор может выдавать значения для нулевого индекса, первого индекса , второго и так далее до седьмого индекса. Количество индексов мы задаем директивой
#property indicator_buffers N
но цвета при этом задаются не с нуля, а с единицы
#property indicator_color1 Blue
#property indicator_color2 Red
С помощью SetIndexStyle(номер_индекса, стиль) мы задаем каждому индексу необходимый стиль (каждый индикатор может иметь несколько индексов с разными стилями рисования), указав на стиль Arrow мы далее уточнили код символа (241 и 242) для каждого индекса, и только потом было указано, что индекс 0 – это массив ExtMapBuffer1, индекс 1 – это данные из массива ExtMapBuffer2. Без такого связывания индекса и массива функцией SetIndexBuffer(номер_индекса, имя_массива_буфера) индикатор работать не будет, это одна из ошибок при написании индикаторов. Вторая возможная ошибка (которую очень сложно бывает обнаружить) – объявление буферов типом, отличным от double, например int .
|
|
|
|
Последней строчкой идет функция SetIndexEmptyValue(номер_индекса, Пустое_Значение). В языках программирования обычно нет понятия "отсутствия значения", если у нас есть понятие "Свет", то понятие "Тьма" в программировании будет не отсутствие Света, а очень мало Света. Поэтому важно указать, что какое-то определенное значение будет означать отсутствие значения (в нашем случае – отсутствие стрелки), обычно таким значением бывает 0.0 (ноль с точностью до одного знака после запятой), хотя можно использовать и другие значения. Осталось только написать алгоритм, который и заполнит индикаторные буфера (индексы) значениями, на которых будут располагаться стрелки.
Для этого обратимся к последнему скрипту CrossMASignals-5, скопируем все из блока start(), уберем операции с нанесением стрелок на график и записью в файл. Я также добавил функции Print() в блоки init() и deinit(). Мы практически сделали индикатор, не написав еще кода, а только скопировав некоторые куски из скрипта и закомментировав ненужные места. Если поставить /* в начале фрагмента, а */ в конце фрагмента, то весь фрагмент станет комментарием, которые, как мы знаем, не компилируются. Это бывает удобно при поисках ошибок и необходимости отключать при компиляции большие куски кода.
|
|
|
|
#property copyright "MetaQuotes"
#property link "http://forum.alpari-idc.ru/viewtopic.php?t=48186"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
//---- input parameters
extern int LongPeriod=21;
extern int ShortPeriod=13;
//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
//----
int init()
{
//---- indicators
Print("Выполняется init()");
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,241);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexEmptyValue(0,0.0);
SetIndexStyle(1,DRAW_ARROW);
SetIndexArrow(1,242);
SetIndexBuffer(1,ExtMapBuffer2);
SetIndexEmptyValue(1,0.0);
return(0);
}
//----
int deinit()
{
Print("Выполняется deinit()");
return(0);
}
//----
int start()
{
int counted_bars=IndicatorCounted();
//----
double maLongCur, maLongPrev, maShortCur, maShortPrev;
/*
string arrowName; // здесь будут назначаться уникальное имя объекта-стрелки
int arrowCounter=0;// счетчик стрелок
*/
// объявим служебные переменные, в которых будем хранить ценовые координаты стрелок
double value1,value2;
Print("Выполняется start()");
for(int i=Bars-1;i>=0;i--)
{
// обнулим службные переменные
value1=0.0;
value2=0.0;
maLongCur=iMA(NULL,0,LongPeriod,0,MODE_SMA,PRICE_CLOSE,i+1);// медленная средняя на предыдущем баре
maLongPrev=iMA(NULL,0,LongPeriod,0,MODE_SMA,PRICE_CLOSE,i+2);// медленная средняя на предпредыдущем баре
maShortCur=iMA(NULL,0,ShortPeriod,0,MODE_SMA,PRICE_CLOSE,i+1);// быстрая средняя на предпредыдущем баре
maShortPrev=iMA(NULL,0,ShortPeriod,0,MODE_SMA,PRICE_CLOSE,i+2);// быстрая средняя на предыдущем баре
//Если есть сигнал к покупке на предыдущем баре - поставим синюю стрелку вверх
// по цене открытия бара
if((maShortCur>maLongCur)&&(maShortPrev<maLongPrev))
{
/*
// Поставим стрелку
// имя объекта - arrowName
// тип объекта - OBJ_ARROW
// координата по горизонтали - Time[i] время открытия бара
// координата по вертикали - Open[i] цена открытия бара
arrowName="arrow"+arrowCounter;
ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 241 , стрелка вверх
ObjectSet(arrowName,OBJPROP_ARROWCODE,241);
// зададим цвет стрелке - голубой
ObjectSet(arrowName,OBJPROP_COLOR,Blue);
// увеличить счетчик стрелок
arrowCounter++;
*/
value1=Open[i];//запомним цену голубой стрелки
}
//Если есть сигнал к продаже на предыдущем баре - поставим красную стрелку вниз
// по цене открытия бара
if((maShortCur<maLongCur)&&(maShortPrev>maLongPrev))
{
/*
// Поставим стрелку
// имя объекта - arrowName
// тип объекта - OBJ_ARROW
// координата по горизонтали - Time[i] время открытия бара
// координата по вертикали - Open[i] цена открытия бара
arrowName="arrow"+arrowCounter;
ObjectCreate(arrowName,OBJ_ARROW,0,Time[i],Open[i]);
// зададим тип стрелки - 242 , стрелка вниз
ObjectSet(arrowName,OBJPROP_ARROWCODE,242);
// зададим цвет стрелке - красный
ObjectSet(arrowName,OBJPROP_COLOR,Red);
// увеличить счетчик стрелок
arrowCounter++;
*/
value2=Open[i];//запомним цену красной стрелки
}
/*
//запишем данные для текущего бара в файл
FileWrite(FileHandle,TimeToStr(Time[i]),i,value1,value2);
*/
}
return(0);
}
Код отлично компилируется, но рисовать наш индикатор ничего не будет. Для этого нам необходимо добавить только две строчки:
ExtMapBuffer1[i]=value1;
ExtMapBuffer2[i]=value2;
Насколько мы помним, CrossMA.csv(после выполнения скрипта CrossMASignals-5) содержит два столбца : «Стрелка вверх» и «Стрелка вниз». Теперь эти столбцы у нас находятся в буферах ExtMapBuffer1[] и ExtMapBuffer2[] .
Компилируем индикатор и запускаем его опять на графике EURUSD D1. У нас снова имеется на графике два набора стрелок (красные и синие), но только стрелки меньше размером и они уже не являются графическими объектами, доступными для редактирования, стрелки стали неотъемлемой частью индикатора и будут перерисовываться при смене тайм-фрейма.
Откроем панель «Окно данных» и наведем перекрестие на последнюю синюю стрелку вверх (чтобы получить режим перекрестия, достаточно нажать среднюю кнопку мыши или колесико). Напротив CrossMA находится значение 1.1886 – это и есть значение буфера ExtMapBuffer1 на данном баре, value2 – это значение буфера ExtMapBuffer2 на данном баре, значение для него отсутствует, так как 0.0 является пустым значением
(
помните
SetIndexEmptyValue(0,0.0);
SetIndexEmptyValue(1,0.0);
?
)
|
|
|
|
Как видите, ничего сложного в создании индикатора нет.
Сам индикатор можно скачать здесь
Перейти к статье «Оптимизация индикатора».
|
|
|
|
|
|