Справочник MQL4

Ресурсы

Использование графики и звука в программах на MQL4

Программы на MQL4 позволяют работать со звуковыми и графическими файлами:

PlaySound() воспроизводит звуковой файл;

ObjectCreate() позволяет с помощью графических объектов OBJ_BITMAP и OBJ_BITMAP_LABEL создавать пользовательские интерфейсы.

 

PlaySound()

Пример вызова функции PlaySound():

//+------------------------------------------------------------------+
//| Функция вызывает штатную OrderSend() и проигрывает звук          |
//+------------------------------------------------------------------+
void OrderSendWithAudio()
  {
      double price=Ask;
      //--- размещение рыночного ордера на покупку 1 лота текущего символа
      int ticket=OrderSend(Symbol(),OP_BUY,1,price,3,0,0,"My order",16384,0,clrGreen);
      if(ticket<0)
        {
         Print("Вызов OrderSend завершился с ошибкой #",GetLastError());
         //--- при ошибке проигрывает звук из файла  timeout.wav
         PlaySound("timeout.wav");
        }
      else
        {
         Print("Ордер успешно размещен");
         //--- при удачном размещении ордера проигрывает звук из файла Ok.wav      
         PlaySound("Ok.wav");
        }
  }

В данном примере показано как проигрывать звуки из файлов Ok.wav и timeoit.wav, входящих в стандартную поставку терминала. Эти файлы находятся в папке каталог_терминала\Sounds. Здесь каталог_терминала означает папку, из которой запущен клиентский терминал MetaTrader 4.  Программным путем из mql4-программы каталог терминала можно узнать следующим образом:

//--- Папка, в которой хранятся данные терминала
   string terminal_path=TerminalInfoString(TERMINAL_PATH);

Можно использовать звуковые файлы не только из папки каталог_терминала\Sounds, но и из любой подпапки, находящейся в папке каталог_данных_терминала\MQL4. Расположение каталога данных терминала на компьютере можно выяснить через меню терминала "Файл"-"Открыть каталог данных" или программным путем:

//--- Папка, в которой хранятся данные терминала
   string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);

Например, если звуковой файл Demo.wav лежит в папке каталог_данных_терминала\MQL4\Files, то вызов PlaySound() должен быть записан таким образом:

//--- проиграем звуковой файл Demo.wav из папки каталог_данных_терминала\MQL4\Files\Demo.wav
   PlaySound("\\Files\\Demo.wav");

Обратите внимание на то, что в комментарии путь к файлу написан с использованием символа "\", а в самой функции для разделения папок в пути используется последовательность "\\".

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

Для остановки воспроизведения файла нужно вызвать функцию PlaySound() с параметром NULL:

//--- вызов PlaySound с параметром NULL останавливает воспроизведение звука
   PlaySound(NULL);

 

ObjectCreate()

Пример эксперта, который с помощью функции  ObjectCreate() создает объект "Графическая метка" (OBJ_BITMAP_LABEL).

string label_name="currency_label";        // имя объекта OBJ_BITMAP_LABEL 
string euro      ="\\Images\\euro.bmp";    // путь к файлу каталог_данных_терминала\MQL4\Images\euro.bmp
string dollar    ="\\Images\\dollar.bmp";  // путь к файлу каталог_данных_терминала\MQL4\Images\dollar.bmp
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- создадим кнопку OBJ_BITMAP_LABEL, если ее еще нет
   if(ObjectFind(0,label_name)<0)
     {
      //--- попробуем создать объект OBJ_BITMAP_LABEL
      bool created=ObjectCreate(0,label_name,OBJ_BITMAP_LABEL,0,0,0);
      if(created)
        {
         //--- привяжем кнопку к правому верхнему углу графика
         ObjectSetInteger(0,label_name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
         //--- теперь настроим свойства объекта
         ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,100);
         ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,50);
         //--- сбросим код последней ошибки в 0
         ResetLastError();
         //--- загрузим картинку для состояния кнопки "Нажата"
         bool set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,0,euro);
         //--- проверим результат
         if(!set)
           {
            PrintFormat("Не удалось загрузить картинку из файла %s. Код ошибки %d",euro,GetLastError());
           }
         ResetLastError();
         //--- загрузим картинку для состояния кнопки "Отжата"
         set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,1,dollar);
         
         if(!set)
           {
            PrintFormat("Не удалось загрузить картинку из файла %s. Код ошибки %d",dollar,GetLastError());
           }
         //--- отдадим графику команду на обновление, чтобы кнопка появилась сразу же, не дожидаясь тика
         ChartRedraw(0);
        }
      else
        {
         //--- объект создать не удалось, сообщим об этом
         PrintFormat("Не удалось создать объект OBJ_BITMAP_LABEL. Код ошибки %d",GetLastError());
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- удалим объект с графика 
   ObjectDelete(0,label_name);
  }

Создание и настройка графического объекта с именем currency_label происходят в функции OnInit(). Пути к загружаемым графическим файлам заданы в глобальных переменных euro и dollar, в качестве разделителя использована двойная обратная косая черта:

string euro      ="\\Images\\euro.bmp";    // путь к файлу каталог_данных_терминала\MQL4\Images\euro.bmp
string dollar    ="\\Images\\dollar.bmp";  // путь к файлу каталог_данных_терминала\MQL4\Images\dollar.bmp

Сами файлы при этом находятся в папке каталог_данных_терминала\MQL4\Images.

Объект OBJ_BITMAP_LABEL фактически представляет собою кнопку, которая в зависимости от состояния (нажата или отжата) может отображать одну из двух картинок: euro.bmp или dollar.bmp.

Свойства объекта OBJ_BITMAP_LABEL

Размеры кнопки с графическим интерфейсом автоматически устанавливаются под размер отображаемой картинки. Смена изображения производится при нажатии левой кнопкой мышки на объекте OBJ_BITMAP_LABEL (в свойствах должен быть выбрано  "Отключить выделение"). Объект OBJ_BITMAP создается аналогичным образом и предназначен для создания фона с требуемым рисунком.

Значение свойства OBJPROP_BMPFILE, которое отвечает за вид объектов OBJ_BITMAP и OBJ_BITMAP_LABEL, можно менять динамически. Это позволяет создавать разнообразные интерактивные пользовательские интерфейсы для mql4-программ.

 

Включение ресурсов в исполняемые файлы при компиляции mql4-программ

Для работы mql4-программы может потребоваться множество разнообразных загружаемых ресурсов в виде файлов изображений и звуков. Для того чтобы исключить необходимость переноса всех этих файлов при передаче исполняемой программы на MQL4, следует использовать директиву компилятора #resource:

 #resource путь_к_файлу_ресурса

Команда #resource указывает компилятору, что ресурс по указанному пути путь_к_файлу_ресурса нужно включить в исполняемый файл EX4. Таким образом, все необходимые картинки и звуки можно поместить непосредственно в EX4-файл и для запуска программы в другом терминале не потребуется передавать все используемые в ней отдельные файлы. Любой EX4-файл может содержать ресурсы, и любая EX4-программа может использовать ресурсы из другой EX4-программы.

Файлы в формате BMP и WAV перед включением в исполняемый EX4 файл автоматически сжимаются. Это означает, что использование ресурсов не только позволяет создавать полноценные программы на MQL4, но и уменьшает общий размер требуемых терминалу файлов при использовании графики и звука по сравнению с обычным способом написания mql4-программ.

Размер файла ресурса не может быть больше 16 Mb.

 

Поиск компилятором указанных ресурсов

Ресурс вставляется командой #resource "<путь к файлу ресурса>"

 #resource "<путь_к_файлу_ресурса>"

Длина константной строки <путь_к_файлу_ресурса> не должна превышать 63 символа.

Имена всех файлов и каталогов, включаемых в ресурсы, должны быть на английском языке.

Компилятор ищет ресурс по указанному пути в следующей последовательности:

если в начале пути стоит разделитель обратная косая черта "\" (пишется "\\"), то ресурс ищется относительно каталога каталог_данных_терминала\MQL4\,

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

В пути ресурса недопустимо использовать подстроки "..\\" и ":\\".

Примеры включения ресурсов:

//--- правильное указание ресурсов
#resource "\\Images\\euro.bmp" // euro.bmp находится в каталог_данных_терминала\MQL4\Images\
#resource "picture.bmp"        // picture.bmp находится в том же каталоге, где и исходный файл
#resource "Resource\\map.bmp"  // ресурс находится в папке каталог_исходного_файла\Resource\map.bmp
 
//--- неправильное указание ресурсов
#resource ":picture_2.bmp"     // нельзя использовать ":"
#resource "..\\picture_3.bmp"  // нельзя использовать ".."
#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" //больше 63 символов

 

Использование ресурсов

Имя ресурса

После того как ресурс объявлен директивой #resource, его можно использовать в любой части программы. Именем ресурса становится его путь без косой черты в начале строки, задающей путь к ресурсу. Для использования своего ресурса в коде нужно перед именем ресурса добавлять специальный признак "::".

Примеры:

//--- примеры указания ресурсов и их имена в комментарии
#resource "\\Images\\euro.bmp"          // имя ресурса - Images\euro.bmp
#resource "picture.bmp"                 // имя ресурса - picture.bmp
#resource "Resource\\map.bmp"           // имя ресурса - Resource\map.bmp
#resource "\\Files\\Pictures\\good.bmp" // имя ресурса - Files\Pictures\good.bmp
#resource "\\Files\\Demo.wav";          // имя ресурса - Files\Demo.wav"
#resource "\\Sounds\\thrill.wav";       // имя ресурса - Sounds\thrill.wav"
...                                  
 
//--- использование ресурсов
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\euro.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::picture.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\good.bmp");
...
PlaySound("::Files\\Demo.wav");
...
PlaySound("::Sounds\\thrill.wav");

Необходимо отметить, что при установке объектам OBJ_BITMAP и OBJ_BITMAP_LABEL изображения из ресурса, значение свойства OBJPROP_BMPFILE уже нельзя менять вручную. Например, пусть мы используем для создания OBJ_BITMAP_LABEL ресурсы файлов euro.bmp и dollar.bmp.

#resource "\\Images\\euro.bmp";    // euro.bmp находится в каталог_данных_терминала\MQL4\Images\
#resource "\\Images\\dollar.bmp";  // dollar.bmp находится в каталог_данных_терминала\MQL4\Images\

Тогда при просмотре свойств этого объекта мы увидим, что свойства BitMap File (On) и BitMap File (Off) имеют серый цвет и недоступны для изменения вручную:

using_resource

 

Использование ресурсов других mql4-программ

Использование ресурсов имеет и другое преимущество – в любой mql4-программе можно использовать ресурсы из любого файла EX4. Таким образом, ресурсы из одного файла EX4 можно использовать во многих других mql4-программах.

Для того чтобы использовать имя ресурса из стороннего файла, его нужно указать в виде <путь_имя_файла_EX4>::<имя_ресурса>. Например, пусть в скрипте Draw_Triangles_Script.mq5 указан ресурс на картинку в файле triangle.bmp:

 #resource "\\Files\\triangle.bmp"

Тогда его имя для использования в самом скрипте будет выглядеть как "Files\triangle.bmp", а для использования к имени ресурса нужно добавить  специальный признак "::".

//--- использование ресурса в самом скрипте
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"::Files\\triangle.bmp");

Чтобы использовать этот же ресурс из другой программы, например, эксперта, нужно к имени ресурса дополнительно добавить путь к EX4-файлу относительно папки каталог_данных_терминала\MQL4\ и имя EX4-файла этого скрипта - Draw_Triangles_Script.ex4. Пусть скрипт лежит в стандартной папке каталог_данных_терминала\MQL4\Scripts\, тогда вызов нужно написать таким образом:

//--- использование ресурса скрипта в эксперте
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex4::Files\\triangle.bmp");

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

//--- запрос ресурса скрипта в эксперте без указания пути
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex4::Files\\triangle.bmp");

то файл будет искаться в папке каталог_данных_терминала\MQL4\Experts\, если сам советник находится в папке каталог_данных_терминала\MQL4\Experts\.

 

Работа с пользовательскими индикаторами, подключенными в качестве ресурсов

Для работы mql4-программ может потребоваться один или несколько пользовательских индикаторов, все они могут быть включены в код исполняемой mql4-программы. Включение индикаторов в качестве ресурсов позволяет упростить распространение программ.

Пример подключения и использования пользовательского индикатора SampleIndicator.ex4, расположенного в папке: каталог_данных_терминала\MQL4\Indicators\:

//+------------------------------------------------------------------+
//|                                                     SampleEA.mq4 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#resource "\\Indicators\\SampleIndicator.ex4"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- получим значение пользовательского индикатора
   double value=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex4",0,0);
   PrintFormat("Indicator: iCustom value=%f",value);
//--- ...
   return(INIT_SUCCEEDED);
  }

Случай, когда пользовательский индикатор в функции OnInit() создает одну или несколько копий себя, требует отдельного рассмотрения. Напомним, что для использования ресурса из mql4-программы его необходимо указывать в виде: <путь_имя_файла_EX4>::<имя_ресурса>.

Например, если индикатор SampleIndicator.ex4 включается в советник SampleEA.ex4 в качестве ресурса, то путь к самому себе, указанный при вызове iCustom() в функции инициализации пользовательского индикатора, будет выглядеть следующим образом: "\\Experts\\SampleEA.ex4::Indicators\\SampleIndicator.ex4". При явном указании данного пути пользовательский индикатор SampleIndicator.ex4 будет жестко привязан к советнику SampleEA.ex4 и теряет способность самостоятельной работы.

Путь до самого себя можно получить при помощи функции GetRelativeProgramPath(), пример использования которой приведен ниже:

//+------------------------------------------------------------------+
//|                                              SampleIndicator.mq4 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
int handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- неправильный способ указания ссылки на себя
//--- string path="\\Experts\\SampleEA.ex4::Indicators\\SampleIndicator.ex4";
//--- правильный способ получения ссылки на себя
   string path=GetRelativeProgramPath();
   double value=iCustom(_Symbol,_Period,path,0,0);
   PrintFormat("Path=%s, iCustom value=%f",path,value);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| GetRelativeProgramPath                                           |
//+------------------------------------------------------------------+
string GetRelativeProgramPath()
  {
   int pos2;
//--- получаем абсолютный путь к программе
   string path=MQLInfoString(MQL_PROGRAM_PATH);
//--- находим позицию подстроки "\MQL4\"
   int    pos =StringFind(path,"\\MQL4\\");
//--- подстрока не найдена - ошибка
   if(pos<0)
      return(NULL);
//--- пропускаем каталог "\MQL4"
   pos+=5;
//--- пропускаем лишние '\'
   while(StringGetCharacter(path,pos+1)=='\\')
      pos++;
//--- если это ресурс, возвращаем путь относительно MQL4-каталога
   if(StringFind(path,"::",pos)>=0)
      return(StringSubstr(path,pos));
//--- найдем разделитель для первого подкаталога в MQL4 (например, MQL4\Indicators)
//--- если его нет, то вернем путь относительно MQL4-каталога
   if((pos2=StringFind(path,"\\",pos+1))<0)
      return(StringSubstr(path,pos));
//--- вернем путь относительно подкаталога (например, MQL4\Indicators)
   return(StringSubstr(path,pos2+1));
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,        
                const double& price[])
  {
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Смотри также

ResourceCreate(), ResourceSave(), PlaySound(), ObjectSetInteger(), ChartApplyTemplate(), Файловые операции


История просмотров