English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
Использование ресурсов в MQL5

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

MetaTrader 5Примеры | 14 марта 2011, 07:01
9 297 15
MetaQuotes
MetaQuotes


Важность интерфейса в современных программах

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

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

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


Возможности языка MQL5

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

Именно использование графических элементов делает программу более интересной и удобной для управления с точки зрения пользователя. Терминал MetaTrader 5 помимо классических инструментов технического анализа предоставляет большой выбор графических объектов, из которых как из кубиков можно собирать свой собственный графический интерфейс.


Использование графических файлов для создания интерфейса

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

  • OBJ_BITMAP - объект "Рисунок" позволяет загрузить и отобразить на графике рисунок из файла в формате BMP;
  • OBJ_BITMAP_LABEL - объект "Графическая метка" фактически представляет из себя кнопку, меняющей свое отображение в зависимости от своего состояния (нажата/отжата).

Эти два объекта позволяют создать огромное разнообразие элементов управления и сопоставить им обработчики события "Нажатие мышки"(CHARTEVENT_OBJECT_CLICK). Чтобы установить требуемое изображение для OBJ_BITMAP или OBJ_BITMAP_LABEL, необходимо в свойстве OBJPROP_BMPFILE  указать нужный BMP-файл. Это можно сделать вручную на закладке "Параметры" графического объекта.

Второй и основной способ для программиста на MQL5 - указать для свойства OBJPROP_BMPFILE имя файла с помощью функции ObjectSetString(). Например:

   //--- загрузим картинку для состояния кнопки "Нажата"
   bool set=ObjectSetString(0,object_name,OBJPROP_BMPFILE,0,bmp_file_name);

Стандартный алгоритм использования объектов OBJ_BITMAP или OBJ_BITMAP_LABEL:

  1. Создать объект с помоью функции ObjectCreate().
  2. Привязать функцией ObjectSetInteger() объект к нужному углу графика, если это необходимо. Относительно этого угла будут задаваться координаты точки привязки X и Y в пикселях.
  3. Задать в ObjectSetInteger() значения координат X и Y (OBJPROP_XDISTANCE и OBJPROP_YDISTANCE).
  4. Задать графическому объекту с помощью ObjectSetString()  значение свойства OBJPROP_BMPFILE (одно для BITMAP или два для OBJ_BITMAP_LABEL).
  5. Можно для объекта OBJ_BITMAP_LABEL с помощью ObjectSetInteger() задать начальное состояние кнопки - нажата или отжата (OBJPROP_STATE равно true или false).

После создания и настройки объекта в процессе работы MQL5-программы можно динамически менять не только координаты и состояние графического объекта, но и изменять значение свойства OBJ_BITMAP_LABEL для отображения картинок. Таким образом, интерфейс программы может быть очень гибким и перенастраиваемым.


Воспроизведение звуков

Дополнительным востребованным удобством в программах является возможность запрашивать у пользователя действие при возникновении той или иной ситуации. Для осуществления такого обратного взаимодействия часто используется проигрывание тех или иных звуков в зависимости от случившегося события. Это позволит избавить трейдера от непрерывного наблюдения за ценовыми графиками и привлечь его внимание только в необходимых случаях. Для проигрывания звуковых файлов в языке MQL5 есть функция PlaySound().

Функция PlaySound() очень проста в использовании, ей требуется только указать путь к звуковому файлу для воспроизведения:

//--- путь к звуковому файлу  
string wav_file_name="Ok.wav";
...
//--- проиграем звук из файла каталог_терминала\Sounds\Ok.wav
bool played=PlaySound(wav_file_name);
if(!played)
  //--- попытка воспроизведения оказалась неудачной, сообщим об этом
  {
   PrintFormat("Не удалось воспроизвести файл %s. Код ошибки=%d", wav_file_name, GetLastError());
  }


Где размещать звуковые и графические файлы

Функции ObjectSetString() и PlaySound() требуют указать путь к файлу. Все файлы, которые используются в программах на MQL5, из соображений безопасности находятся в пределах "файловой песочницы". Это означает, что файлы могут находиться только в определенных каталогах, работа с файлами из других каталогов пресекается. Прежде всего необходимо усвоить какие каталоги доступны для файловых операций и функций, и как они именуются.

Существуют три каталога, которые необходимо различать:

  • каталог терминала - папка установки клиентского терминала. Из нее запускается MetaTrader 5, для просмотра папки выберите в терминале пункт меню "Файл"-"Открыть каталог данных".
  • каталог данных терминала - папка, в которой хранятся данные конкретного пользователя Windows. Встроенные защитные механизмы операционной системы разграничивают доступ пользователей, поэтому данные каждого пользователя могут храниться отдельно от данных других пользователей. Именно в ней в подпапке MQL5 хранятся все индикаторы, советники и скрипты, отображаемые в окне Навигатора.
  • общая папка всех терминалов (установленных на компьютере клиентских терминалов MetaTrader 5) - папка для проведения файловых операций  с помощью флага FILE_COMMON.

Выяснить расположение этих каталогов можно с помощью скрипта WhereMyFolders.mq5:

//+------------------------------------------------------------------+
//|                                               WhereMyFolders.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Папка, из которой запущен терминал - каталог_терминала
   string terminal_path=TerminalInfoString(TERMINAL_PATH);
//--- Папка, в которой хранятся данные терминала - каталог_данных_терминала
   string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);
//--- Общая папка всех клиентских терминалов - общая_папка_терминалов
   string common_data_path=TerminalInfoString(TERMINAL_COMMONDATA_PATH);   
   //--- Выведем все пути 
   Print("TERMINAL_PATH(каталог_терминала) = ",TerminalInfoString(TERMINAL_PATH));
   Print("TERMINAL_DATA_PATH(каталог_данных_терминала) = ",TerminalInfoString(TERMINAL_DATA_PATH));
   Print("TERMINAL_COMMONDATA_PATH(общая_папка_терминалов) = ",TerminalInfoString(TERMINAL_COMMONDATA_PATH));   
  }

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

Графические и звуковые файлы ищутся исполняющей системой терминала в следующем порядке:

  • если в начале пути стоит разделитель "\" (пишется "\\"), то файл ищется относительно каталог_данных_терминала\MQL5\;
  • если обратной косой черты в начале пути нет, то файл ищется относительно расположения файла EX5, из которого вызывается функция ObjectSetString(... , OBJPROP_BMPFILE, ...) или PlaySound();
Для функции PlaySound() есть одно дополнение: если файл не был найден ни одним из двух вышеуказанных способов, то звуковой файл ищется относительно каталог_терминала\Sounds\.


Примеры для звуковых файлов:

  • файл one.wav будет искаться в папке каталог_данных_терминала\MQL5\
    PlaySound("\\one.wav");
  • файл two.wav будет искаться в папке каталог_данных_терминала\MQL5\Files\
    PlaySound("\\Files\\two.wav");
  • файл three.wav будет искаться в папке каталог_данных_терминала\MQL5\MySounds\
    PlaySound("\\MySounds\\three.wav");
  • файл four.wav будет искаться в папке, из которой запущен исполняемый файл EX5. Если в этой папке файл не будет найден, то будет сделана попытка найти файл в папке каталог_терминала\Sounds\.
    PlaySound("four.wav");


Примеры для графических файлов:

  • файл bird.bmp будет искаться в папке каталог_данных_терминала\MQL5\
    //--- установка картинки для объекта OBJ_BITMAP_LABEL
    bool res=ObjectSetString(0,object_name,OBJPROP_BMPFILE,0,"bird.bmp");// указан модификатор 0
  • файл swan.bmp будет искаться в папке каталог_данных_терминала\MQL5\Files\
    //--- установка картинки для объекта OBJ_BITMAP
    bool set=ObjectSetString(0,object_name,OBJPROP_BMPFILE,"\\Files\\swan.bmp");// нет модификатора
  • файл dog.bmp будет искаться в папке каталог_данных_терминала\MQL5\MyPictures\
    //--- установка картинки для объекта OBJ_BITMAP
    bool done=ObjectSetString(0,object_name,OBJPROP_BMPFILE,"\\MyPictures\\dog.bmp");// нет модификатора
  • файл cat.bmp будет искаться в папке, из которой запущен исполняемый файл EX5
    //--- установка картинки для объекта OBJ_BITMAP
    bool result=ObjectSetString(0,object_name,OBJPROP_BMPFILE,"cat.bmp");// нет модификатора

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

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


Новая возможность - ресурсы

Чтобы использовать в своей MQL5-программе графику и звук нужно позаботиться о том, чтобы все используемые в ней медиафайлы находились в нужных папках. Это накладывает определенное неудобство при переносе скомпилированного EX5-файла с одного терминала на другой. Но есть возможность решить этот вопрос еще на стадии написании кода. Используйте в таких случаях ресурсы.

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

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

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

Любой EX5-файл может содержать ресурсы, и любая EX5-программа может использовать ресурсы из другой EX5-программы. То есть эксперт может использовать ресурсы, которые находятся в индикаторе или  EX5-библиотеке. Это еще одно удобство от использования ресурсов.

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


Поиск ресурса компилятором

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

 #resource "<путь_к_файлу_ресурса>"
Длина константной строки <путь_к_файлу_ресурса> не должна превышать 63 символа. Компилятор ищет ресурс по указанному пути в следующей последовательности:
  • если в начале пути стоит разделитель обратная косая черта "\", то ресурс ищется относительно папки каталог_данных_терминала\MQL5\,
  • если обратной косой черты нет, то ресурс ищется относительно расположения исходного файла, в котором этот ресурс прописывается.

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

Примеры включения ресурсов из раздела справки Ресурсы:

//--- правильное указание ресурсов
#resource "\\Images\\euro.bmp" // euro.bmp находится в каталог_данных_терминала\MQL5\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\\cat.bmp"           // имя ресурса - Images\cat.bmp
#resource "dog.bmp"                     // имя ресурса - dog.bmp
#resource "Resource\\map.bmp"           // имя ресурса - Resource\map.bmp
#resource "\\Files\\Pictures\\bird.bmp" // имя ресурса - Files\Pictures\bird.bmp
#resource "\\Files\\good.wav"           // имя ресурса - Files\good.wav"
#resource "\\Sounds\\thrill.wav"        // имя ресурса - Sounds\thrill.wav"

Имена ресурсов не зависят от регистра, в котором написаны -  для компилятора имена dog.bmp и DOG.bmp будут означать одно и то же.


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

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

//--- использование ресурсов
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\cat.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::dog.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\bird.bmp");
...
PlaySound("::Files\\good.wav");
...
PlaySound("::Sounds\\thrill.wav");

Можно использовать не только свои ресурсы (из своего EX5 файла), но и из любых библиотек и модулей EX5. Таким образом, можно создавать хранилища ресурсов и использовать их во многих других mql5-программах.

Чтобы использовать ресурс из другого EX5-файла, имя ресурса нужно указать в виде <путь_имя_файла_EX5>::<имя_ресурса>. Пусть в скрипте Draw_Triangles_Script.mq5 указан ресурс на картинку в файле triangle.bmp:

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

Тогда его имя для использования в самом скрипте будет выглядеть как "Files\triangle.bmp", а для использования к имени ресурса нужно добавить  специальный признак "::" - "::Files\triangle.bmp". Чтобы использовать этот же ресурс из другой программы  нужно к имени ресурса дополнительно добавить путь к EX5-файлу относительно папки каталог_данных_терминала\MQL5\ и имя EX5-файла этого скрипта - Draw_Triangles_Script.ex5. Пусть скрипт лежит в стандартной папке каталог_данных_терминала\MQL5\Scripts\, тогда вызов нужно написать таким образом:

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

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

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


Сжатие ресурсов в EX5 файлах - как это работает

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

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

Важно: дополнительным преимуществом использования ресурсов является автоматическое сжатие файлов WAV и BMP при упаковке в исполняемый EX5. Это уменьшает не только количество, но и размер используемых для работы программы файлов.

Рассмотрим для примера небольшую программу Animals_EA.mq5. Небольшой блок кода по использованию ресурсов представлен ниже:

//+------------------------------------------------------------------+
//|                                                   Animals_EA.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- объявим ресурсы картинок
#resource "\\Images\\cat.bmp"
#resource "\\Images\\dog.bmp"
#resource "\\Images\\cow.bmp"
#resource "\\Images\\bird.bmp"
//--- объявим ресурсы звуков
#resource "\\Files\\MySounds\\cat.wav"
#resource "\\Files\\MySounds\\dog.wav"
#resource "\\Files\\MySounds\\cow.wav"
#resource "\\Files\\MySounds\\bird.wav"
//--- имена объектов
string cat_dog="cat_dog";
string cow_bird="cow_bird";
string canvas="canvas";
string text="text";
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- создадим подложку
   CreateCanvas(canvas,50,50,500,500);
//--- создадим кнопки
   CreateObjectBITMAP_LABEL(cat_dog,110,120,"::Images\\cat.bmp","::Images\\dog.bmp");
   CreateObjectBITMAP_LABEL(cow_bird,110,330,"::Images\\cow.bmp","::Images\\bird.bmp");
   CreateText(text,"Кликните мышкой на любом графическом объекте",200,90,clrTan);
//--- отдадим команду графику на немедленное обновление, чтобы увидеть наши объекты
   ChartRedraw();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//|  создает объект OBJ_BITMAP_LABEL с указанными рисунками          |
//+------------------------------------------------------------------+
bool CreateObjectBITMAP_LABEL(string obj_name,int X,int Y,string res_name1,string res_name2)
  {
//--- если такого объекта еще нет на графике
   if(ObjectFind(0,obj_name)==-1)
     {
      //--- создадим его
      bool res=ObjectCreate(0,obj_name,OBJ_BITMAP_LABEL,0,0,0);
      //--- проверим результат
      if(!res)
        {
         PrintFormat("%s: Не удалось создать объект OBJ_BITMAP_LABEL с именем %s. Код ошибки=%d",
                     __FUNCTION__,
                     GetLastError());
         return false;
        }
     }

//--- зададим координаты
   ObjectSetInteger(0,obj_name,OBJPROP_XDISTANCE,X);
   ObjectSetInteger(0,obj_name,OBJPROP_YDISTANCE,Y);
//--- отключим отображение на заднем фоне
   ObjectSetInteger(0,obj_name,OBJPROP_BACK,false);
//--- обнулим код ошибки
   ResetLastError();
//--- установим картинку для нажатого состояния кнопки
   bool res=ObjectSetString(0,obj_name,OBJPROP_BMPFILE,0,res_name1);
//--- проверим результат операции
   if(!res)
     {
      PrintFormat("%s: Не удалось загрузить картинку из ресурса %s. Код ошибки=%d",
                  __FUNCTION__,
                  res_name1,
                  GetLastError());
      return false;
     }
//--- установим картинку для отжатого состояния кнопки
   res=ObjectSetString(0,obj_name,OBJPROP_BMPFILE,1,res_name2);
//--- проверим результат операции
   if(!res)
     {
      PrintFormat("%s: Не удалось загрузить картинку из ресурса %s. Код ошибки=%d",
                  __FUNCTION__,
                  res_name2,
                  GetLastError());
      return false;
     }
//--- установим кнопку нажатой
   ObjectSetInteger(0,obj_name,OBJPROP_STATE,true);
   return true;
  }
//+------------------------------------------------------------------+

Задача программы - нарисовать на синем фоне (подложке) две графические кнопки, которые меняют свое отображение по клику мышки. При клике мышкой на подложке она меняет свой цвет с синего на бежевый и наоборот. При каждом изменении раздается звук, событие клика мышкой обрабатывается в функции OnChartEvent(). Вид графика сразу после запуска советника Animals_EA.mq5 показан на рисунке.


Посмотрите свойства объекта OBJ_BITMAP_LABEL, например,  cat_dog. Изменение свойств Bitmap File (On) и Bitmap File (Off) теперь невозможно через диалоговое окно, эти поля недоступны и выделены серым цветом.

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

Общий объем картинок, используемых советником Animals_EA.mq5, составляет 430 kb.


Размер же получившегося исполняемого файла Animals_EA.ex5, который содержит в себе все указанные рисунки, составляет 339 kb. Таким образом, вместо 9 файлов (один MQ5-файл, четыре BMP-файла и четыре WAV-файла) у нас есть теперь один EX5-файл, который содержит все необходимые для работы программы ресурсы.

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

Файл эксперта Animals_EA.mq5, картинки и звуки прикреплены внизу статьи:

  • Картинки распаковать их архива images.zip в папку каталог_данных_терминала\MQL5\Images\
  • Звуки из архива MySounds.zip распаковать в папку каталог_данных_терминала\MQL5\Files\MySounds\

Чтобы самостоятельно протестировать эту программу в своем терминале достаточно загрузить приложенный скомпилированный советник Animals_EA.ex5, который содержит в себе все ресуры. В этом случае скачивать и устанавливать графические и звуковые файлы не требуется.


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

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

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

//+------------------------------------------------------------------+
//|                                                     SampleEA.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#resource "\\Indicators\\SampleIndicator.ex5"
int handle_ind;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   handle_ind=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex5");
   if(handle_ind==INVALID_HANDLE)
     {
      Print("Expert: iCustom call: Error code=",GetLastError());
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

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

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

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

//+------------------------------------------------------------------+
//|                                              SampleIndicator.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_plots 0
int handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- неправильный способ указания ссылки на себя
//--- string path="\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5";   
//--- правильный способ получения ссылки на себя
  string path=GetRelativeProgramPath();
//--- indicator buffers mapping
   handle=iCustom(_Symbol,_Period,path,0,0);
   if(handle==INVALID_HANDLE)
     {
      Print("Indicator: iCustom call: Error code=",GetLastError());
      return(INIT_FAILED);
     }
   else Print("Indicator handle=",handle);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| GetRelativeProgramPath                                           |
//+------------------------------------------------------------------+
string GetRelativeProgramPath()
  {
   int pos2;
//--- получаем абсолютный путь к программе
   string path=MQLInfoString(MQL_PROGRAM_PATH);
//--- находим позицию подстроки "\MQL5\"
   int    pos =StringFind(path,"\\MQL5\\");
//--- подстрока не найдена - ошибка
   if(pos<0)
      return(NULL);
//--- пропускаем каталог "\MQL5"
   pos+=5;
//--- пропускаем лишние '\'
   while(StringGetCharacter(path,pos+1)=='\\')
      pos++;
//--- если это ресурс, возвращаем путь относительно MQL5-каталога
   if(StringFind(path,"::",pos)>=0)
      return(StringSubstr(path,pos));
//--- найдем разделитель для первого подкаталога в MQL5 (например, MQL5\Indicators)
//--- если его нет, то вернем путь относительно MQL5-каталога
   if((pos2=StringFind(path,"\\",pos+1))<0)
      return(StringSubstr(path,pos));
//--- вернем путь относительно подкаталога (например, MQL5\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);
  }


Экономия памяти терминала

Каждый ресурс загружается в память терминала только один раз. В то время как при обычном использовании каждое обращение к файлу вызывает дополнительную загрузку этого файла в память. Например, пусть у нас имеется 50 объектов OBJ_BITMAP, каждый из их содержит одну и ту же картинку размером 100 kb. Тогда при обычном использовании эти 50 объектов потребуют памяти 50*100kb=5Mb.

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

Важно: ресурсы загружаются в память только один раз и позволяют сэкономить память при многократном их использовании


Заключение

Использование ресурсов облегчает пользование и распространение MQL5-программ. Создание удобных современных инструментов для торговли требует широкого использования мультимедийных средств на основе графики и звуковых файлов. Концепция ресурсов в MQL5 проста и удобна для понимания, попробуйте и оцените ее.

Рисунки в формате BMP с глубиной цвета 32 бита могут содержать альфа-канал, в этом случае они будут накладываться на график с прозрачностью.

Ресурсы дают нам следующие удобства:

  • компактность - все файлы упакованы в одном исполняемом EX5-файле, программу легко переносить и запускать;
  • экономичность в работе - память терминала всегда содержит только один экземпляр каждого ресурса вне зависимости от частоты его использования в программе;
  • удобство в хранении - один EX5-файл со всеми ресурсами занимает меньший объем, чем сумма исходных графических и звуковых файлов.
Прикрепленные файлы |
wheremyfolders.mq5 (1.52 KB)
mysounds.zip (65.89 KB)
animals_ea.mq5 (18.89 KB)
images.zip (214.29 KB)
animals_ea.ex5 (393.38 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (15)
MetaQuotes
Renat Fatkhullin | 27 июн. 2013 в 09:51
fyords:
Подскажите, пожалуйста, как можно в индикаторе, загруженном из ресурсов, создать графический объект типа OBJ_BITMAP_LABEL и наложить на него текст из TextOut?
Может только для TextOut сделать исключение - возможность работать со своими ресурсами программ загруженных из ресурсов?
А в каком месте именно проблема? Что именно не получается?
Dmitriy Parfenovich
Dmitriy Parfenovich | 27 июн. 2013 в 09:59
Renat:
А в каком месте именно проблема? Что именно не получается?

Есть индикатор, из него запускается дочерний, из ресурсов.
В дочернем используется TextOut, а результат загружается на OBJ_BITMAP_LABEL через ResourceCreate, но использование ресурсов в ресурсе нет возможности. 

Результат - объект появляется, в свойствах ресурс указан, но сам текст не выводится. 

MetaQuotes
Renat Fatkhullin | 27 июн. 2013 в 12:47
fyords:

Есть индикатор, из него запускается дочерний, из ресурсов.
В дочернем используется TextOut, а результат загружается на OBJ_BITMAP_LABEL через ResourceCreate, но использование ресурсов в ресурсе нет возможности. 

Результат - объект появляется, в свойствах ресурс указан, но сам текст не выводится. 

Да, на текущий момент загрузить ресурсы из ресурсного объекта нельзя.

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

Dmitriy Parfenovich
Dmitriy Parfenovich | 27 июн. 2013 в 13:17
Renat:

... Мы сейчас думаем над этом проблемой и скорее всего решим ее.

Спасибо, буду ждать.
Denis Kirichenko
Denis Kirichenko | 22 апр. 2019 в 10:51

Прошу помочь. Не могу разобраться вот в какой ситуации.

Есть простенький индикатор и советник, его вызывающий. Оба лежат в папке общих проектов "Shared Projects\Testing\Indicator\".

Подключаю в советник индикатор в виде ресурса. И хочу создать хэндл с помощью ресурса.

Вот блок кода:

//--- ресурс
#resource "Indicator.ex5";
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   string path=GetRelativeProgramPath();
   path=path+"::Indicator.ex5"; 
//--- индикатор
   int ha=iCustom(_Symbol,_Period,path);
   if(ha==INVALID_HANDLE)
      return INIT_FAILED;
//---
   return INIT_SUCCEEDED;
  }

Компиляция проходит успешно, значит индикатор в виде ресурса прицеплен.

В итоге путь к индикатору получается такой: Shared Projects\Testing\Indicator\TestingEA.ex5::Indicator.ex5. Вроде всё правильно. Скомпилированный файл индикатора там в папке есть.

Функция GetRelativeProgramPath() - это пример из статьи

Как ни крутил, хэндл не могу создать. Спасибо.

Статистические оценки Статистические оценки
Оценка статистических параметров последовательности очень важна, так как большинство математических моделей и методов строятся исходя из различного рода предположений, например, о нормальности закона распределения, или требуют знания значения дисперсии или других параметров. В статье кратко рассматриваются простейшие статистические параметры случайной последовательности и некоторые методы ее визуального анализа. Предлагается реализация этих методов на MQL5 и способ визуализации результатов расчета при помощи программы Gnuplot.
Реализация автоматического анализа волн Эллиотта на MQL5 Реализация автоматического анализа волн Эллиотта на MQL5
Одним из самых популярных методов анализа рынка является волновой анализ. Однако данный процесс является достаточно сложным, что приводит к использованию дополнительных инструментов. Одним из таких инструментов является автоматический разметчик. В данной статье рассматривается создание автоматического анализатора волн Эллиотта на языке MQL5.
Трассировка, отладка и структурный анализ кода Трассировка, отладка и структурный анализ кода
Весь комплекс задач создания структуры работающего кода и его трассировки можно решить без особых сложностей. Эта возможность появилась в MetaTrader 5 благодаря новому свойству языка MQL5 - автоматическое создание переменных сложного типа данных (структуры и классы) и их уничтожение при выходе из локальной области видимости. В статье описана методика и предоставлен готовый инструмент.
Фильтрация сигналов на основе статистических данных о корреляции цен Фильтрация сигналов на основе статистических данных о корреляции цен
Есть ли связь между поведением цены в прошлом и будущими трендами? Почему сегодня цена повторяет характер движения вчерашнего дня? Возможно ли использовать статистические данные как метод прогнозирования динамики цен? Ответ есть, и он положительный. Если вы ещё сомневаетесь, эта статья для вас. Я расскажу о том, как создать рабочий фильтр для торговой системы на MQL5, обнаружив интересную закономерность в изменении цен.