Русский

Учебник по MQL4  Стандартные функции  Операции с графиками

Операции с графиками


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


Рис. 140. Расположение подокон в окне финансового инструмента.

Количество подокон можно легко вычислить с помощью функции:

int WindowsTotal()

Функция возвращает количество подокон индикаторов на графике, включая главное окно графика. Максимальный номер (самого нижнего) окна всегда на 1 меньше, чем общее количество подокон (включая основное, с номером 0) в окне финансового инструмента. Если в ситуации, изображённой на рис. 140, из любой прикладной программы вызвать для исполнения функцию WindowsTotal(), то возвращённое ею значение будет равно 3, в то время как максимальный номер (самого нижнего) подокна равен 2.

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

В MQL4 предусмотрена возможность создавать графические объекты (и изменять их свойства) в любом из имеющихся подокон. Для этого в функции ObjectCreate() предусмотрен параметр window, согласно которому объект создаётся в указанном подокне окна финансового инструмента. Текущий номер подокна можно вычислить с помощью функции:

int WindowFind(string name)

Функция возвращает номер подокна графика, содержащего индикатор с указанным именем name, если он найден, иначе возвращается -1. Функция также возвращает -1, если пользовательский индикатор ищет сам себя в процессе инициализации init().

Параметры:

name - короткое имя индикатора.


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

Задача 34. Используя графические объекты, отобразить сообщения о показаниях двух индикаторов. Если в окне финансового инструмента установлен соответствующий индикатор, то графический объект выводить в окно индикатора, в противном случае - в основное окно.

Для решения задачи выберем индикаторы RSI и Momentum. Общий алгоритм построения эксперта сводится к следующему. В функции init() можно задать тексты, которые будут выводиться на экран в зависимости от показаний индикаторов, т.е. выполнить те вычисления, которые выполняются в программе один раз. В функции start() необходимо вычислить показания индикаторов, определить наличие необходимых подокон и их номера, а затем, в зависимости от ситуации, выдать то или иное сообщение в то или иное подокно. При исполнении функции deinit() необходимо удалить все графические объекты, созданные в процессе работы программы. Ниже представлен эксперт charts.mq4, управляющий графическими объектами в подокнах окна финансового инструмента.

//--------------------------------------------------------------------
// charts.mq4
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------- 1 --
int Win_Mom_old=0, // Старый номер подокна Moment.
Win_RSI_old=0; // Старый номер подокна RSI
color Color[5]; // Объявление массива цветов
string Text[5]; // Объявление строков. массива
//--------------------------------------------------------------- 2 --
int init() // Спец. функция init()
{
Win_RSI_old=0; // Технический момент
Win_Mom_old=0; // Технический момент

Text[0]= "RSI(14) ниже 30. Buy"; // Тексты для ситуаций RSI
Text[1]= "RSI(14) выше 70. Sell"; // Тексты для ситуаций RSI
Text[2]= "RSI(14) между 30 и 70"; // Тексты для ситуаций RSI
Text[3]= "Моментум(14) повышается"; // Тексты для ситуаций Моментум
Text[4]= "Моментум(14) снижается"; // Тексты для ситуаций Моментум
Color[0]= DeepSkyBlue; // Цвет объектов для ..
Color[1]= LightPink; // .. различных ситуаций ..
Color[2]= Orange; // .. индикатора RSI
Color[3]= Color[0]; // Те же цвета для Моментум
Color[4]= Color[1]; // Те же цвета для Моментум

Create_RSI(0); // Создание первого объекта
Create_Mom(0); // Создание второго объекта
Main(); // Вызов пользовательской ф-ии
return; // Выход из init()
}
//--------------------------------------------------------------- 3 --
int start() // Спец. функция start
{
Main(); // Вызов пользовательской ф-ии
return; // Выход из start()
}
//--------------------------------------------------------------- 4 --
int deinit() // Спец. функция deinit()
{
ObjectDelete("Obj_RSI"); // Удаление объекта
ObjectDelete("Obj_Mom"); // Удаление объекта
return; // Выход из deinit()
}
//--------------------------------------------------------------- 5 --
int Main() // Пользовательская функция
{
int // Целые переменные
Win_RSI_new=0, // Новый номер подокна RSI
Win_Mom_new=0, // Новый номер подокна Moment.
Ind_RSI, Ind_Mom; // Индексы для ситуаций
double // Действительные переменные
RSI, // Значение RSI на 0 баре
Mom_0, Mom_1; // Значение Mom на 0 и 1 барах
//--------------------------------------------------------------- 6 --
RSI=iRSI(NULL,0,14,PRICE_CLOSE,0); // RSI(14) на нулевом баре
Ind_RSI=2; // RSI между уровнями 30 и 70
if(RSI < 30)Ind_RSI=0; // RSI внизу. Нужно покупать
if(RSI > 70)Ind_RSI=1; // RSI вверху. Нужно продавать
//--------------------------------------------------------------- 7 --
Win_RSI_new=WindowFind("RSI(14)"); // Номер окна индикатора RSI
if(Win_RSI_new==-1) Win_RSI_new=0; // Если нет индик, то осн. окно
if(Win_RSI_new!=Win_RSI_old) // Удалено или установлено ..
{ // .. окно индикатора RSI
ObjectDelete("Obj_RSI"); // Удаление объекта
Create_RSI(Win_RSI_new); // Создаём объект в нужном окне
Win_RSI_old=Win_RSI_new; // Запомним это окно
} // Изменяем текстовое описание:
ObjectSetText("Obj_RSI",Text[Ind_RSI],10,"Arial",Color[Ind_RSI]);
//--------------------------------------------------------------- 8 --
Mom_0=iMomentum(NULL,0,14,PRICE_CLOSE,0);// Значен. на нулевом баре
Mom_1=iMomentum(NULL,0,14,PRICE_CLOSE,1);// Знач. на предыдущ. баре
if(Mom_0 >=Mom_1)Ind_Mom=3; // Индик. линия поднимается
if(Mom_0 < Mom_1)Ind_Mom=4; // Индик. линия опускается
//--------------------------------------------------------------- 9 --
Win_Mom_new=WindowFind("Momentum(14)");// Номер окна индик. Momen
if(Win_Mom_new==-1) Win_Mom_new=0; // Если нет индик, то осн. окно
if(Win_Mom_new!=Win_Mom_old) // Удалено или установлено ..
{ // .. окно индикатора Momentum
ObjectDelete("Obj_Mom"); // Удаление объекта
Create_Mom(Win_Mom_new); // Создаём объект в нужном окне
Win_Mom_old=Win_Mom_new; // Запомним это окно
} // Изменяем текстовое описание:
ObjectSetText("Obj_Mom",Text[Ind_Mom],10,"Arial",Color[Ind_Mom]);
//-------------------------------------------------------------- 10 --
WindowRedraw(); // Перерисовка изображения
return; // Выход из пользоват. функции
}
//-------------------------------------------------------------- 11 --
int Create_RSI(int Win) // Пользовательс ф-ия
{ // ..создания объекта
ObjectCreate("Obj_RSI",OBJ_LABEL, Win, 0,0); // Создание объекта
ObjectSet("Obj_RSI", OBJPROP_CORNER, 0); // Привязка к углу
ObjectSet("Obj_RSI", OBJPROP_XDISTANCE, 3); // Координата Х
if (Win==0)
ObjectSet("Obj_RSI",OBJPROP_YDISTANCE,20);// Координата Y
else
ObjectSet("Obj_RSI",OBJPROP_YDISTANCE,15);// Координата Y
return; // Выход из польз.ф-ии
}
//-------------------------------------------------------------- 12 --
int Create_Mom(int Win) // Пользовательс ф-ия
{ // ..создания объекта
ObjectCreate("Obj_Mom",OBJ_LABEL, Win, 0,0); // Создание объекта
ObjectSet("Obj_Mom", OBJPROP_CORNER, 0); // Привязка к углу
ObjectSet("Obj_Mom", OBJPROP_XDISTANCE, 3); // Координата Х
if (Win==0)
ObjectSet("Obj_Mom",OBJPROP_YDISTANCE, 5);// Координата Y
else
ObjectSet("Obj_Mom",OBJPROP_YDISTANCE,15);// Координата Y
return; // Выход из польз.ф-ии
}
//-------------------------------------------------------------- 13 --

Прежде чем рассматривать представленный код, необходимо указать на специфику работы программы. Предполагается, что однажды созданный графический объект (в данном случае отображающий текст) будет присутствовать на экране постоянно (непрерывно), и его текстовое описание будет характеризовать ситуацию. Изменять содержание текстового описания необходимо при исполнении функции start(), на каждом тике. В то же время, при переключении таймфреймов для окна, к которому прикреплён эксперт, программа проходит стадии deinit(), init(), (ожидание тика) и start(). Если первый раз объект создаётся в процессе исполнения start(), то всякий раз при переключении таймфрейма до появления объекта будет проходить некоторое время, равное времени ожидания очередного тика. Это очень неудобно, в особенности, если происходит частое переключение таймфреймов.

В правильно построенной программе необходимые сообщения выводятся на экран в момент присоединения программы к окну финансового инструмента или в момент переключения таймфрейма (т.е. ещё до поступления нового тика). Для этого на этапе исполнения специальной функции init(), как правило, необходимо выполнить все действия, которые будут выполняться на каждом тике при запуске специальной функции start(). Чтобы не повторять в разных специальных функциях один и тот же программный код, его можно организовать в виде отдельной функции. Для этой цели в эксперте создана пользовательская функция Main(). Она вызывается для исполнения один раз на этапе инициализации (блок 2-3) и на каждом тике в процессе последующей работы эксперта (блок 3-4).

В программе (блок 11-13) имеются ещё две пользовательские функции - Create_RSI() и Create_Mom(), предназначенные для создания и изменения свойств объектов. При исполнении функции init() с помощью этих функций создаются необходимые объекты, а вызов на исполнение функции Main() приводит к наделению объектов необходимыми свойствами (отражение в нужном окне объектов с нужным текстовым описанием нужного цвета).

Рассмотрим функцию Main() (блок 5-11) подробно. В блоке 6-7 вычисляются показания индикатора RSI. В зависимости от того, находится ли конец индикаторной линии выше 70, ниже 30 или в промежутке между ними, переменной Ind_RSI присваивается то или иное значение. В дальнейшем это значение используется в качестве индекса массивов Color[] и Text[] (в блоке 7-8) для изменения свойств графического объекта с именем "Obj_RSI".

Блок 7-8. Номер окна индикатора RSI вычисляется в строке:

   Win_RSI_new = WindowFind("RSI(14)");// Номер окна индикатора RSI

В качестве передаваемого параметра используется строковое значение "RSI(14)". Это - короткое имя индикатора, номер которого определяется. В данном случае вся последовательность литер в указанной строке, включая скобки и цифры, является названием. Нужно заметить, что в общем случае в окне финансового инструмента могут находиться несколько однотипных индикаторов, например, RSI(14), RSI(21) и RSI(34). Каждое из подокон, в которых отражаются эти индикаторы, имеет свой номер. Поэтому технические индикаторы разработаны таким образом, что каждый из них формирует своё короткое имя согласно установленным значениям настраиваемых параметров. Короткое имя каждого технического индикатора совпадает с тем, которое отображается в верхнем левом углу его подокна (короткое имя пользовательского индикатора устанавливается программистом по своему усмотрению с помощью функции IndicatorShortName()).

Если в окне финансового инструмента не установлен искомый индикатор, то переменная Win_RSI_new (номер подокна, в котором этот объект должен быть отображён на текущий момент) получит значение -1, т.е. в несуществующее окно. В этом случае в программе предусмотрено выводить графический объект в основное окно графика, номер которого всегда 0:

   if(Win_RSI_new == -1) Win_RSI_new=0;// Если нет индик, то осн. окно

В процессе работы пользователь может установить недостающий индикатор или удалить имеющийся. Для того чтобы определить, какие действия нужно выполнить, в программе используются глобальные переменные Win_RSI_old и Win_Mom_old. Значение каждой из этих переменных - это номер подокна, в котором ранее был создан объект. Если значения переменных Win_RSI_new и Win_RSI_old не совпадают, то это означает, что окно индикатора либо добавлено (а раньше его не было), либо удалено (а на предыдущем тике ещё было). И в том, и в другом случае необходимо удалить ранее созданный графический объект и создать новый в нужном окне:

      ObjectDelete("Obj_RSI");         // Удаление объекта
Create_RSI(Win_RSI_new); // Создаём объект в нужном окне

После создания объекта в окне с номером Win_RSI_new переменной Win_RSI_old присваивается значение, равное номеру этого окна, т.е. программа запоминает номер окна, в котором создан графический объект:

      Win_RSI_old = Win_RSI_new;       // Запомним это окно

Если значения переменных Win_RSI_new и Win_RSI_old совпадают, значит достаточно сообщить объекту (уже сейчас расположенному в нужном окне) новое текстовое описание. Это также необходимо сделать в случае создания нового объекта:

      ObjectSetText("Obj_RSI",Text[Ind_RSI],10,"Arial",Color[Ind_RSI]);

Аналогичные вычисления выполняются и для другого подокна - индикатора Momentum (блоки 8 - 10). В конце функции Main() все имеющиеся графические объекты перерисовываются в результате исполнения WindowRedraw().

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

   Win_RSI_old = 0;                    // Технический момент
Win_Mom_old = 0; // Технический момент

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

Рассмотрим, как будет работать программа, в которой указанные строки отсутствуют. Предположим, что на момент, когда пользователь переключил таймфрейм, в окне финансового инструмента были установлены оба индикатора, с номерами подокон, соответственно, 1 и 2. В рассматриваемом примере при деинициализации программы происходит удаление графических объектов. При исполнении специальной функции init() объекты создаются в нулевом окне. В дальнейшем, при исполнении функции Main(), в блоках 7-8 и 9-10 выполняется сравнение найденного номера окна, в котором должны быть установлены объекты, и номера окна, в котором объекты находились на предыдущем тике. Фактически объекты установлены в нулевом окне, но значения глобальных переменных будут свидетельствовать о другом: их номера будут 1 и 2. В результате графические объекты будут оставаться в основном окне до тех пор, пока пользователь не удалит и вновь не установит соответствующие индикаторы. Для того чтобы предотвратить нежелательное развитие событий, в программе и предусмотрено обнуление глобальных переменных при исполнении функции init(). Таким образом, значения этих переменных поставлены в соответствие ситуации.

В результате исполнения эксперта charts.mq4 можно наблюдать такие варианты сочетания окон и отображения графических объектов:


Рис. 141. Отображение графических объектов в подокнах окна финансового инструмента.

Если в окне финансового инструмента имеются оба индикатора, то соответствующие графические объекты будут отображены в их подокнах. Если ни один из этих индикаторов не установлен, то оба объекта будут созданы программой в основном окне. Добавление или удаление любого из индикаторов, имена которых обрабатываются в программе, приведёт к перемещению соответствующего графического объекта в нужное окно. Добавление или удаление из окна финансового инструмента других индикаторов не повлечёт никаких последствий.

Отдельно нужно заметить, что в данной программе не рассматривается вариант удаления графического объекта пользователем. Практически используемая программа должна содержать анализ такой ситуации с последующим восстановлением объекта (см. решение Задачи 33).


Функции, используемые для работы с графиками


Функция Краткое описание
HideTestIndicators Функция выставляет флаг скрытия индикаторов, вызываемых экспертом. При открытии графика после тестирования индикаторы, помеченные флагом скрытия, не будут выведены на график тестирования. Перед каждым вызовом индикатор помечается текущим установленным флагом скрытия (на график тестирования могут быть выведены только те индикаторы, которые непосредственно вызываются из тестируемого эксперта).
Period Возвращает значение числа минут периода для текущего графика.
RefreshRates Обновление данных в предопределенных переменных и массивах-таймсериях. Эта функция используется, когда эксперт или скрипт производит вычисления в течение долгого времени и нуждается в обновленных данных. Возвращается TRUE, если данные обновлены, иначе FALSE. Данные могут не обновиться только по той причине, что они соответствуют текущему состоянию клиентского терминала.
Symbol Возвращает текстовую строку с именем текущего финансового инструмента.
WindowBarsPerChart Функция возвращает количество баров, помещающихся в окно текущего графика.
WindowExpertName Возвращает имя выполняющегося эксперта, скрипта, пользовательского индикатора или библиотеки, в зависимости от того, из какой MQL4-программы вызвана данная функция.
WindowFind Возвращает номер подокна графика, содержащего индикатор с указанным именем name, если он найден, иначе возвращается -1. WindowFind() возвращает -1, если пользовательский индикатор ищет сам себя в процессе инициализации init().
WindowFirstVisibleBar Функция возвращает номер первого видимого бара в окне текущего графика. Необходимо иметь в виду, что ценовые бары нумеруются задом наперед, от последнего к первому. Текущий бар, самый последний в ценовом массиве, имеет индекс 0. Самый старый бар имеет индекс Bars-1. Если номер первого видимого бара меньше, чем количество видимых баров на графике на 2 и более, это значит, что окно графика заполнено не до конца и имеется поле справа.
WindowHandle Возвращает системный дескриптор окна (window handle), содержащего указанный график. Если график с symbol и timeframe на момент вызова функции не открыт, то возвращается 0.
WindowIsVisible Возвращает TRUE, если подокно графика видимо, иначе возвращает FALSE. Подокно графика может быть скрыто из-за свойств видимости помещенного в него индикатора.
WindowOnDropped Возвращает индекс окна, в которое был брошен эксперт, пользовательский индикатор или скрипт. Это значение будет верным только в том случае, если эксперты, пользовательские индикаторы и скрипты прикреплены с помощью мыши (технология "drag and drop"). Для пользовательских индикаторов, находящихся в процессе инициализации (вызов из функции init()) этот индекс не определен. Возвращаемый индекс является номером окна (0-главное окно графика, подокна индикаторов нумеруются с 1), в котором работает пользовательский индикатор. В процессе инициализации пользовательский индикатор может создать свое собственное новое подокно, и его номер будет отличаться от номера окна, на которое действительно был брошен индикатор.
WindowPriceMax Возвращает максимальное значение вертикальной шкалы указанного подокна текущего графика (0-главное окно графика, подокна индикаторов нумеруются с 1). Если индекс подокна не указан, то возвращается максимальное значение ценовой шкалы главного окна графика.
WindowPriceMin Возвращает минимальное значение вертикальной шкалы указанного подокна текущего графика (0-главное окно графика, подокна индикаторов нумеруются с 1). Если индекс подокна не указан, то возвращается минимальное значение ценовой шкалы главного окна графика.
WindowPriceOnDropped Возвращает значение цены в точке графика, на которой был брошен эксперт или скрипт. Значение будет верным только в случае, если эксперт или скрипт перемещены с помощью мыши (технология "drag and drop"). Для пользовательских индикаторов это значение не определено.
WindowRedraw Принудительно перерисовывает текущий график. Обычно применяется после изменения свойств объектов.
WindowScreenShot Сохраняет изображение текущего графика в файле формата GIF. В случае неудачи возвращает FALSE.
WindowTimeOnDropped Возвращает значение времени в точке графика, на которой был брошен эксперт или скрипт. Значение будет верным только в случае, если эксперт или скрипт перемещены с помощью мыши (технология "drag and drop"). Для пользовательских индикаторов это значение не определено.
WindowsTotal Возвращает количество окон индикаторов на графике, включая главное окно графика.
WindowXOnDropped Возвращает значение координаты по оси X в пикселах точки клиентской области окна графика, на которой был брошен эксперт или скрипт. Значение будет верным только в случае, если эксперт или скрипт перемещены с помощью мыши (технология "drag and drop").
WindowYOnDropped Возвращает значение координаты по оси Y в пикселах точки клиентской области окна графика, на которой был брошен эксперт или скрипт. Значение будет верным только в случае, если эксперт или скрипт перемещены с помощью мыши (технология "drag and drop").

Для получения подробного описания этих и других функций необходимо обратиться к справочной документации на MQL4.community, сайте MetaQuotes Software Corp. или к разделу "Справка" в редакторе MetaEditor.