Как уже было показано ранее, мы можем рисовать на графике символа не только диаграммы индикатора, но и добавлять различные графические объекты с помощью функции ObjectCreate:
bool ObjectCreate (
long chart_id, // идентификатор графика
string name, // имя объекта
ENUM_OBJECT type, // тип объекта
int sub_window, // индекс окна
datetime time1, // время первой точки привязки
double price1, // цена первой точки привязки
datetime timeN=0, // время N-ой точки привязки
double priceN=0, // цена N-ой точки привязки
datetime time30=0, // время 30-й точки привязки
double price30=0 // цена 30-точки привязки
);
Здесь параметр sub_window это индекс главного окна графика символа со значением 0 или индекс подокна другого индикатора, присоединенного к графику символа.
Например, если в предыдущем примере мы изменим код, и присоединим к графику символа, скажем, индикатор ADX, мы увидим следующее:
for (int i=start; i <rates_total &&!IsStopped ();i++)
{
if (close [i-1]> open [i-1] &&close [i-1]> EMA34HBuffer [i-1] &&close [i-1]> EMA34LBuffer [i-1] &&low [i-1]> EMA125Buffer [i-1] &&low [i-1]> PSARBuffer [i-1] &&EMA125Buffer [i-1] <EMA34LBuffer [i-1] &&EMA125Buffer [i-1] <EMA34HBuffer [i-1]) {
if (!ObjectCreate (0,«Buy»+i, OBJ_ARROW,0,time [i-1],high [i-1]))
{
return (false);
}
if (!ObjectCreate (0,«Buy1»+i, OBJ_ARROW,1,time [i-1],high [i-1]))
{
return (false);
}
ObjectSetInteger (0,«Buy»+i, OBJPROP_COLOR, clrGreen);
ObjectSetInteger (0,«Buy»+i, OBJPROP_ARROWCODE,233);
ObjectSetInteger (0,«Buy»+i, OBJPROP_WIDTH,2);
ObjectSetInteger (0,«Buy»+i, OBJPROP_ANCHOR, ANCHOR_UPPER);
ObjectSetInteger (0,«Buy»+i, OBJPROP_HIDDEN, true);
ObjectSetString (0,«Buy»+i, OBJPROP_TOOLTIP, close [i-1]);
ObjectSetInteger (0,«Buy1»+i, OBJPROP_COLOR, clrGreen);
ObjectSetInteger (0,«Buy1»+i, OBJPROP_ARROWCODE,233);
ObjectSetInteger (0,«Buy1»+i, OBJPROP_WIDTH,2);
ObjectSetInteger (0,«Buy1»+i, OBJPROP_ANCHOR, ANCHOR_UPPER);
ObjectSetInteger (0,«Buy1»+i, OBJPROP_HIDDEN, true);
ObjectSetString (0,«Buy1»+i, OBJPROP_TOOLTIP, close [i-1]);
}
if (close [i-1] <open [i-1] &&close [i-1] <EMA34HBuffer [i-1] &&close [i-1] <EMA34LBuffer [i-1] &&high [i-1] <EMA125Buffer [i-1] &&high [i-1] <PSARBuffer [i-1] &&EMA125Buffer [i-1]> EMA34LBuffer [i-1] &&EMA125Buffer [i-1]> EMA34HBuffer [i-1]) {
if (!ObjectCreate (0,«Sell»+i, OBJ_ARROW,0,time [i-1],low [i-1]))
{
return (false);
}
if (!ObjectCreate (0,«Sell1»+i, OBJ_ARROW,1,time [i-1],low [i-1]))
{
return (false);
}
ObjectSetInteger (0,«Sell»+i, OBJPROP_COLOR, clrRed);
ObjectSetInteger (0,«Sell»+i, OBJPROP_ARROWCODE,234);
ObjectSetInteger (0,«Sell»+i, OBJPROP_WIDTH,2);
ObjectSetInteger (0,«Sell»+i, OBJPROP_ANCHOR, ANCHOR_LOWER);
ObjectSetInteger (0,«Sell»+i, OBJPROP_HIDDEN, true);
ObjectSetString (0,«Sell»+i, OBJPROP_TOOLTIP, close [i-1]);
ObjectSetInteger (0,«Sell1»+i, OBJPROP_COLOR, clrRed);
ObjectSetInteger (0,«Sell1»+i, OBJPROP_ARROWCODE,234);
ObjectSetInteger (0,«Sell1»+i, OBJPROP_WIDTH,2);
ObjectSetInteger (0,«Sell1»+i, OBJPROP_ANCHOR, ANCHOR_LOWER)
ObjectSetInteger (0,«Sell1»+i, OBJPROP_HIDDEN, true);
ObjectSetString (0,«Sell1»+i, OBJPROP_TOOLTIP, close [i-1]);
}
}
Нумерация подокон идет сверху вниз в порядке отображения.
Тип отображаемого объекта задается перечислением ENUM_OBJECT, которое можно посмотреть в справочнике.
После добавления графических объектов, не забываем их удалять в функции обратного вызова OnDeinit (), используя функцию ObjectDelete:
bool ObjectDelete (
long chart_id, // chart identifier
string name // object name
);
Или используя функцию ObjectsDeleteAll:
int ObjectsDeleteAll (
long chart_id, // chart identifier
int sub_window=-1, // window index
int type=-1 // object type
);
Помимо вышеупомянутых функций ObjectCreate, ObjectDelete и ObjectsDeleteAll, MQL5 предлагает набор функций для работы с графическими объектами: ObjectName, ObjectFind, ObjectGetTimeByValue, ObjectGetValueByTime, ObjectMove, ObjectsTotal, ObjectGetDouble, ObjectGetInteger, ObjectGetString, ObjectSetDouble, ObjectSetInteger, ObjectSetString, TextSetFont, TextOut, TextGetSize.
Функции ObjectName, ObjectFind, ObjectGetTimeByValue, ObjectGetValueByTime, ObjectsTotal, ObjectGetDouble, ObjectGetInteger, ObjectGetString, TextGetSize – это функции возвращающие информацию.
Функции ObjectSetDouble, ObjectSetInteger, ObjectSetString, TextSetFont – это функции устанавливающие свойства объекта.
Функция ObjectMove перемещает объект в окне.
Функция TextOut выводит текст в пиксельный массив для отображения объектом OBJ_BITMAP_LABEL или OBJ_BITMAP.
После добавления графических объектов рекомендуется принудительно перерисовать график символа с помощью функции ChartRedraw:
void ChartRedraw (
long chart_id=0 // идентификатор графика
);
Функция ObjectCreate позволяет создавать программным способом те графические объекты, которые вы можете вручную нарисовать на графике символа, пользуясь панелью инструментов клиентского терминала.
С помощью функции ObjectSetDouble устанавливаются такие свойства графического объекта, как OBJPROP_PRICE – изменение параметра price функции ObjectCreate, OBJPROP_LEVELVALUE – определение уровней для таких объектов, как инструменты Фиббоначи и Вилы Эндрюса, OBJPROP_SCALE – определение масштаба для таких объектов, как инструменты Ганна и Дуги Фибоначчи, OBJPROP_ANGLE – определение угла объекта, т.е. возможность повернуть объект, который изначально не имеет жесткой привязки, например, повернуть текст, OBJPROP_DEVIATION – определение отклонения для объекта Канал стандартного отклонения.
Пример использования OBJPROP_PRICE:
int OnCalculate (const int rates_total,
const int prev_calculated,
const datetime &time [],
const double &open [],
const double &high [],
const double &low [],
const double &close [],
const long &tick_volume [],
const long &volume [],
const int &spread [])
{
// – —
ArraySetAsSeries (time, true);
ArraySetAsSeries (high, true);
ArraySetAsSeries (low, true);
ArraySetAsSeries (close, true);
ObjectDelete (0,«Price»);
if (!ObjectCreate (0,«Price», OBJ_HLINE,0,time [1],close [1]))
{
return (false);
}
ObjectSetInteger (0,«Price», OBJPROP_COLOR, clrGreen);
ObjectSetInteger (0,«Price», OBJPROP_WIDTH,1);
ObjectSetString (0,«Price», OBJPROP_TOOLTIP, close [1]);
if (open [1]> close [1])
ObjectSetDouble (0,«Price», OBJPROP_PRICE, low [1]);
if (open [1] <close [1])
ObjectSetDouble (0,«Price», OBJPROP_PRICE, high [1]);
// – - return value of prev_calculated for next call
return (rates_total);
}
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
void OnDeinit (const int reason) {
ObjectsDeleteAll (0, -1, -1);
}
В этом коде создается горизонтальный уровень, показывающий минимальную или максимальную цену предыдущего бара, в зависимости от того, является ли этот бар бычьим или медвежьим.
Пример использования OBJPROP_ANGLE:
int OnCalculate (const int rates_total,
const int prev_calculated,
const datetime &time [],
const double &open [],
const double &high [],
const double &low [],
const double &close [],
const long &tick_volume [],
const long &volume [],
const int &spread [])
{
// – —
ArraySetAsSeries (time, true);
ArraySetAsSeries (high, true);
ArraySetAsSeries (low, true);
ArraySetAsSeries (close, true);
ObjectDelete (0,«Line»);
ObjectDelete (0,«Price»);
if (!ObjectCreate (0,«Line», OBJ_VLINE,0,time [1],close [1]))
{
return (false);
}
ObjectSetInteger (0,«Line», OBJPROP_COLOR, clrBlue);
ObjectSetInteger (0,«Line», OBJPROP_WIDTH,1);
ObjectSetString (0,«Line», OBJPROP_TOOLTIP, close [1]);
if (!ObjectCreate (0,«Price», OBJ_TEXT,0,time [3],high [1]))
{
return (false);
}
ObjectSetString (0,«Price», OBJPROP_TEXT, close [1]);
ObjectSetInteger (0,«Price», OBJPROP_COLOR, clrBlack);
ObjectSetDouble (0,«Price», OBJPROP_ANGLE,90);
ObjectSetString (0,«Price», OBJPROP_TOOLTIP, close [1]);
// – - return value of prev_calculated for next call
return (rates_total);
}
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
void OnDeinit (const int reason) {
ObjectsDeleteAll (0, -1, -1);
}
Этот код создает вертикальную линию с подписью цены закрытия предыдущего бара.
С помощью функции ObjectSetInteger устанавливаются такие свойства графического объекта, как цвет, стиль, размер и др.
С помощью функции ObjectSetString можно изменить имя объекта, при этом объект со старым именем будет удален и будет создан объект с новым именем, установить текст для таких объектов, как текст, кнопка, метка, поле ввода, событие, установить текст всплывающей подсказки для объекта, описание уровня для объектов, имеющих уровни, шрифт, имя BMP-файла для объекта «Графическая метка» и «Рисунок», символ для объекта «График».
Функция TextSetFont позволяет установить тип шрифта текста, его размер, стиль и угол наклона для объектов, содержащих текст.
Как уже было сказано, функция TextOut позволяет скомбинировать текст и изображение. Например, следующий код выводит текст в изображение, залитое одним цветом:
uint ExtImg [10000];
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
//| Custom indicator initialization function |
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
int OnInit ()
{
ObjectCreate (0,«Image», OBJ_BITMAP_LABEL,0,0,0);
ObjectSetString (0,«Image», OBJPROP_BMPFILE,»:: IMG»);
ArrayFill (ExtImg,0,10000,0xffffff);
TextOut («Text», 10,10,TA_LEFT|TA_TOP, ExtImg,100,100,0x000000,COLOR_FORMAT_XRGB_NOALPHA);
ResourceCreate (»:: IMG», ExtImg,100,100,0,0,0,COLOR_FORMAT_XRGB_NOALPHA);
ChartRedraw ();
// – —
return (INIT_SUCCEEDED);
}
Здесь ExtImg это пиксельный массив, представляющий изображение 100х100 пикселей.
Функция ObjectCreate создает объект «Графическая метка», а функция ObjectSetString устанавливает для этого объекта файл изображения с именем::IMG. По поводу знака «::» справочник говорит следующее:
Для использования своего ресурса в коде нужно перед именем ресурса добавлять специальный признак "::».
Функция ArrayFill заполняет пиксельный массив пикселями белого цвета.
Функция TextOut выводит в пиксельный массив слово «Text».
Функция ResourceCreate создает из пиксельного массива ресурс с именем::IMG.
В итоге на белом фоне отображается надпись «Text».
Также можно вывести текст на готовое изображение:
#resource "\\Images\\image.bmp»
uint ExtImg [10000];
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
//| Custom indicator initialization function |
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
int OnInit ()
{
ObjectCreate (0,«Image», OBJ_BITMAP_LABEL,0,0,0);
ObjectSetString (0,«Image», OBJPROP_BMPFILE,»:: IMG»);
uint width=100;
uint height=100;
ResourceReadImage("::Images\\image.bmp», ExtImg, width, height);
TextOut («Text», 10,10,TA_LEFT|TA_TOP, ExtImg,100,100,0xffffff, COLOR_FORMAT_XRGB_NOALPHA);
ResourceCreate (»:: IMG», ExtImg,100,100,0,0,0,COLOR_FORMAT_XRGB_NOALPHA);
ChartRedraw ();
// – —
return (INIT_SUCCEEDED);
}
Здесь функция ResourceReadImage считывает существующее изображение из папки Images окна Navigator редактора MQL5 в пиксельный массив::IMG, связанный с объектом «Графическая метка», а функция TextOut выводит в пиксельный массив слово «Text».
То же самое можно проделать и с объектом «Рисунок»:
#resource "\\Images\\image.bmp»
uint ExtImg [10000];
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
//| Custom indicator initialization function |
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
int OnInit ()
{
// – —
return (INIT_SUCCEEDED);
}
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
//| Custom indicator iteration function |
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
int OnCalculate (const int rates_total,
const int prev_calculated,
const datetime &time [],
const double &open [],
const double &high [],
const double &low [],
const double &close [],
const long &tick_volume [],
const long &volume [],
const int &spread [])
{
// – —
ArraySetAsSeries (time, true);
ArraySetAsSeries (high, true);
ArraySetAsSeries (low, true);
ArraySetAsSeries (close, true);
ObjectDelete (0,«Image»);
ObjectCreate (0,«Image», OBJ_BITMAP,0,time [1],close [1]);
ObjectSetString (0,«Image», OBJPROP_BMPFILE,»:: IMG»);
uint width=100;
uint height=100;
ResourceReadImage("::Images\\image.bmp», ExtImg, width, height);
TextOut («Text», 10,10,TA_LEFT|TA_TOP, ExtImg,100,100,0xffffff, COLOR_FORMAT_XRGB_NOALPHA);
ResourceCreate (»:: IMG», ExtImg,100,100,0,0,0,COLOR_FORMAT_XRGB_NOALPHA);
ChartRedraw ();
// – - return value of prev_calculated for next call
return (rates_total);
}
//+ – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – — – +
void OnDeinit (const int reason) {
ObjectsDeleteAll (0, -1, -1);
}
В качестве примера использования графических объектов, рассмотрим создание индикатора, который выводит в небольшое окно на графике символа тот же график, но с другим временным периодом.
Для этого используем графический объект OBJ_CHART.
В качестве входных параметров индикатора используем символ графика и его период:
#property indicator_chart_window
input string InpSymbol=«EURUSD»; // Символ
input ENUM_TIMEFRAMES InpPeriod=PERIOD_CURRENT; // Период
В функции OnInit () создадим графический объект График:
int OnInit ()
{
if (!ObjectCreate (0,«Chart», OBJ_CHART,0,0,0))
{
return (false);
}
По умолчанию точка привязки этого объекта – левый верхний угол графика.
Определим отступ точки привязки объекта, его размеры, символ и период графика, отображение шкалы времени, размер точки привязки, с помощью которой можно перемещать объект, отображение ценовой шкалы, режим перемещения мышкой, цвет рамки графика:
ObjectSetInteger (0,«Chart», OBJPROP_XDISTANCE,10);
ObjectSetInteger (0,«Chart», OBJPROP_YDISTANCE,20);
ObjectSetInteger (0,«Chart», OBJPROP_XSIZE,300);
ObjectSetInteger (0,«Chart», OBJPROP_YSIZE,200);
ObjectSetString (0,«Chart», OBJPROP_SYMBOL, InpSymbol);
ObjectSetInteger (0,«Chart», OBJPROP_PERIOD, InpPeriod);
ObjectSetInteger (0,«Chart», OBJPROP_DATE_SCALE, true);
ObjectSetInteger (0,«Chart», OBJPROP_WIDTH,1);
ObjectSetInteger (0,«Chart», OBJPROP_PRICE_SCALE, true);
ObjectSetInteger (0,«Chart», OBJPROP_SELECTABLE, true);
ObjectSetInteger (0,«Chart», OBJPROP_SELECTED, true);
ObjectSetInteger (0,«Chart», OBJPROP_COLOR, clrBlue);
С помощью свойства объектов OBJPROP_CHART_ID функции ObjectGetInteger получим идентификатор графика, используя который мы теперь можем применять функции работы с графиками (https://www.mql5.com/ru/docs/chart_operations) и свойства графиков (https://www.mql5.com/ru/docs/constants/chartconstants/enum_chart_property):
long chartId=ObjectGetInteger (0,«Chart», OBJPROP_CHART_ID);
Откроем наш график символа, к которому мы хотим присоединить индикатор, и нажав правой кнопкой мышки, выберем пункт в контекстном меню Шаблоны и Сохранить шаблон.
Теперь мы можем перенести на наш графический объект все настройки и индикаторы графика символа:
ChartApplyTemplate(chartId,"my.tpl»);
ChartRedraw (chartId);
// – —
return (INIT_SUCCEEDED);
}
Присоединив индикатор к графику символа, мы можем нажать на нем правой кнопкой мышки и изменить его свойства, включая его период, размеры и др.