Графическое управление внешними параметрами индикаторов

Vladimir | 26 мая, 2009

Введение

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


Графическое управление параметрами

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

Для примера используем индикатор ZigZag стандартной поставки метатрейдера. В свойствах выберем названия переменных.

Параметры индикатора

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

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

// Первоначальные значения индикатора
int               ExtDepth=12;
int               ExtDeviation=5;
int               ExtBackstep=3;
//---- indicator buffers
double            ZigzagBuffer[];
double            HighMapBuffer[];
double            LowMapBuffer[];
// Массив переменных параметров индикатора
string            ArrExt[3,3]    ={"12","21","34", "5","8","21", "3","13","34"};
// Массивы указателей
string            Array_Index[]={"Dep -> ","Dev -> ","Back ->"};
int               Coordinats_IndexUp[]={65,160,260};
int               Coordinats_Index[]  ={35,130,230};
int               Coordinats_IndexDn[]={5, 100,200};
// Цвет для блоков параметров и указателей
color             Color_[]={Blue,Green,Red};

Я думаю на этом этапе вопросов не возникнет.

"Dep -> ","Dev -> ","Back ->"

это соответственно ExtDepth, ЕxtDeviation и ExtBackstep. В таком виде будут отображены указатели на графике.

Для каждого параметра используем по три переменных значения

string            ArrExtDepth[]    ={"12","15","20"};
string            ArrExtDeviation[]={"5",  "8","21"};
string            ArrExtBackstep[] ={"3", "13","34"};

которые запакуем, для удобства в трехмерный массив:

string            ArrExt[3,3]    ={"12","21","34", "5","8","21", "3","13","34"};

3, 5, 12 - это стандартные величины, указанные по умолчанию в параметрах стандартного "Зиг-Зага".

Остальные величины приведены для примера. Они будут использованы в качестве переменных параметров для управления индикатором.

Учитывая то, что "рисовать" придется много, выделим в отдельный блок функцию создания и перемещения объектов:

void Obj_CreateMove_Text (int CreateMove, string Name, int Type, string Number,  color text_color, 
                          int DistX, int DistY)
   {
      if (CreateMove==0)
      ObjectCreate(Name,Type,0,0,0);
      ObjectSetText(Name,Number,10,"Arial",text_color);
      ObjectSet(Name,101,3);
      ObjectSet(Name, 102, DistX);
      ObjectSet(Name, 103, DistY);
   }

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

Теперь "нарисуем" в окне графика все объекты.

Правая часть графика у нас менее загружена, поэтому переменные выводим вертикально по правой границе окна. Для каждого параметра используем свой указатель, для чего сами переменные параметра и цвет указателя к этим переменным сделаем одного цвета.

Таким образом нам необходимо создать три указателя и три переменных значения к каждому параметру.

Создаем на экране значки параметров индикатора. Выводим числовые значения переменных этих параметров. И рядом для каждого блока параметров создаем соответствующие указатели.

// Строим объекты
   for( ii=0;ii<3;ii++)
      for( i=0;i<3;i++)
      Obj_CreateMove_Text (0, Array_Index[ii]+i, 23, (ArrExt[ii,i]), Color_[ii], 5, Coordinats_IndexDn[ii]+30*i);
      for( i=0;i<3;i++)
      Obj_CreateMove_Text (0, "Index"+Array_Index[i], 23, (Array_Index[i]),   Color_[i], 25, Coordinats_Index[i]);


Рисунок 1

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

У нас есть точки привязки наших значков к графику. В соответствии с этим мы поочередно считываем параметры указателей и определяем логику поведения программы.

// Считываем координаты указателей на графике
      for( i=0;i<3;i++)
           {
            Coordinats[i]=ObjectGet("Index"+Array_Index[i],OBJPROP_YDISTANCE);
               if (Coordinats[i]==0)//Если за переделами графика, то устанавливаем заново
                  Obj_CreateMove_Text (1, "Index"+Array_Index[i], 23, Array_Index[i], Color_[i], 25, Coordinats_IndexDn[i]);
           }    

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

OBJPROP_YDISTANCE

из

ObjectGet()
// Анализируем местоположение указателей
      for( i=0;i<3;i++)
         {
            if (Coordinats[i]>Coordinats_IndexUp[i]) 
                  {Move[i] = Coordinats_IndexUp[i]; index[i]=2;}// Указатель вверху
            if (Coordinats[i]>Coordinats_IndexDn[i]  && 
                Coordinats[i]<Coordinats_IndexUp[i])
                  {Move[i] = Coordinats_Index[i];   index[i]=1;}// Указатель в средине
            if (Coordinats[i]<Coordinats_IndexDn[i]) 
                  {Move[i] = Coordinats_IndexDn[i]; index[i]=0;}// Указатель внизу
            if (Move[i]!=0)

Далее мы выравниваем те объекты, которые перемещались.

Запоминаем новые параметры для построения Зиг-Зага.

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

// В зависимости от расположения объектов - перемещаем и выравниваем их
            Obj_CreateMove_Text (1, "Index"+Array_Index[i], 23, Array_Index[i], Color_[i], 25, Move[i]);    
// Запоминаем параметры Зигзага
            switch (i)   
               {
                case 0:  ExtDepth =     StrToInteger(ArrExt[0,index[i]]);  break;
                case 1:  ExtDeviation = StrToInteger(ArrExt[1,index[i]]);  break;
                case 2:  ExtBackstep =  StrToInteger(ArrExt[2,index[i]]);  break;                  
               }/**/
          }
 // Передаем параметры в пользовательский индикатор и из полученных значений строим Зиг-Заг
     for(i=300;i>0;i--)
            {
               ZigzagBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,0,i);
               HighMapBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,1,i);
               LowMapBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,2,i);
            }

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


Рисунок 2


Рисунок 3


Рисунок 4

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

//+------------------------------------------------------------------+
//|                                         management_indicator.mq4 |
//|                                  Copyright © 2009, WWW.FIBOOK.RU |
//|                                             http://www.fibook.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, WWW.FIBOOK.RU"
#property link      "http://www.fibook.ru"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
// Первоначальные значения индикатора
int               ExtDepth=12;
int               ExtDeviation=5;
int               ExtBackstep=3;
//---- indicator buffers
double            ZigzagBuffer[];
double            HighMapBuffer[];
double            LowMapBuffer[];
// Массив переменных параметров индикатора
string            ArrExt[3,3]    ={"12","21","34", "5","8","21", "3","13","34"};
// Массивы указателей
string            Array_Index[]={"Dep -> ","Dev -> ","Back ->"};
int               Coordinats_IndexUp[]={65,160,260};
int               Coordinats_Index[]  ={35,130,230};
int               Coordinats_IndexDn[]={5, 100,200};
// Цвет для блоков параметров и указателей
color             Color_[]={Blue,Green,Red};
// Переменные для расчетов
int               i,ii;
int               index[3];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   IndicatorBuffers(3);
//---- drawing settings
   SetIndexStyle(0,DRAW_SECTION);
//---- indicator buffers mapping
   SetIndexBuffer(0,ZigzagBuffer);
   SetIndexBuffer(1,HighMapBuffer);
   SetIndexBuffer(2,LowMapBuffer);
   SetIndexEmptyValue(0,0.0);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
int  Coordinats[3];
int  Move[3];
// Проверяем наличие объектов указателей на графике
   if (ObjectGet("IndexDep -> ",OBJPROP_YDISTANCE)<1||
       ObjectGet("IndexDev -> ",OBJPROP_YDISTANCE)<1||
       ObjectGet("IndexBack ->",OBJPROP_YDISTANCE)<1)
// Если их нет, то строим объекты
               {
      for( ii=0;ii<3;ii++)
       for( i=0;i<3;i++)
        Obj_CreateMove_Text (0, Array_Index[ii]+i, 23, ArrExt[ii,i], Color_[ii], 5, Coordinats_IndexDn[ii]+30*i);
       for( i=0;i<3;i++)
        Obj_CreateMove_Text (0, "Index"+Array_Index[i], 23, Array_Index[i], Color_[i], 25, Coordinats_IndexDn[i]);
               }
// Считываем координаты указателей на графике
      for( i=0;i<3;i++)
           {
            Coordinats[i]=ObjectGet("Index"+Array_Index[i],OBJPROP_YDISTANCE);
               if (Coordinats[i]==0)//Если за переделами графика, то устанавливаем заново
                  Obj_CreateMove_Text (1, "Index"+Array_Index[i], 23, Array_Index[i], Color_[i], 25, Coordinats_IndexDn[i]);
           }    
// Анализируем местоположение указателей
      for( i=0;i<3;i++)
         {
            if (Coordinats[i]>Coordinats_IndexUp[i]) 
                  {Move[i] = Coordinats_IndexUp[i]; index[i]=2;}// Указатель вверху
            if (Coordinats[i]>Coordinats_IndexDn[i]  && 
                Coordinats[i]<Coordinats_IndexUp[i])
                  {Move[i] = Coordinats_Index[i];   index[i]=1;}// Указатель в средине
            if (Coordinats[i]<Coordinats_IndexDn[i]) 
                  {Move[i] = Coordinats_IndexDn[i]; index[i]=0;}// Указатель внизу
            if (Move[i]!=0)
// В зависимости от расположения объектов - перемещаем и выравниваем их
            Obj_CreateMove_Text (1, "Index"+Array_Index[i], 23, Array_Index[i], Color_[i], 25, Move[i]);    
// Запоминаем параметры Зигзага
            switch (i)   
               {
                case 0:  ExtDepth =     StrToInteger(ArrExt[0,index[i]]);  break;
                case 1:  ExtDeviation = StrToInteger(ArrExt[1,index[i]]);  break;
                case 2:  ExtBackstep =  StrToInteger(ArrExt[2,index[i]]);  break;                  
               }/**/
          }
 // Передаем параметры в пользовательский индикатор и из полученных значений строим Зиг-Заг
     for(i=300;i>0;i--)
            {
               ZigzagBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,0,i);
               HighMapBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,1,i);
               LowMapBuffer[i]=iCustom(NULL,0,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep,2,i);
            }
Comment ("ExtDepth =",ExtDepth,", ExtDeviation =",ExtDeviation,", ExtBackstep =",ExtBackstep);        
//----
   return(0);
  }
// Функция построения и перемещения графических объектов
void Obj_CreateMove_Text (int CreateMove, string Name, int Type, string Number,  color text_color, int DistX, int DistY)
   {
      if (CreateMove==0)
      ObjectCreate(Name,Type,0,0,0);
      ObjectSetText(Name,Number,10,"Arial",text_color);
      ObjectSet(Name,101,3);
      ObjectSet(Name, 102, DistX);
      ObjectSet(Name, 103, DistY);
   }


//+------------------------------------------------------------------+


Заключение

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