Скачать MetaTrader 5

Изменяем параметры эксперта с пользовательской панели "на лету"

16 ноября 2012, 14:39
Anatoli Kazharski
49
5 019

Содержание

Введение
1. Рассматриваемые вопросы
2. Структура эксперта
3. Взаимодействие с пользовательской панелью
Заключение


Введение

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

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


1. Рассматриваемые вопросы

В качестве примера создадим простого эксперта, который открывает позицию по направлению индикатора JMA. Эксперт будет работать по сформировавшимся барам на текущем символе и таймфрейме. Во внешних параметрах будут такие опции, как период индикатора (Indicator Period), Stop Loss, Take Profit, переворот уже открытой позиции по противоположному сигналу индикатора (Reverse) и объём позиции (Lot). Для примера этого будет вполне достаточно.

Добавим ещё два дополнительных параметра, с помощью которых можно открыть/убрать панель (On/Off Info Panel) и включить/отключить режим изменения настроек эксперта (Setting "On The Fly"). Дополнительные опции при большом количестве параметров всегда удобнее размещать в самом верху или в конце списка, чтобы иметь к ним быстрый доступ.

Рис. 1. Инфо-панель с параметрами эксперта

Рис. 1. Инфо-панель с параметрами эксперта

По умолчанию, изменение настроек "на лету" отключено. Включив этот режим в первый раз, эксперт создаст файл, в который запишет текущие параметры эксперта. То же самое будет, если файл был случайно удалён. Эксперт обнаружит это и снова создаст файл. При отключенном режиме изменения настроек эксперт будет опираться на внешние параметры.

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


2. Структура эксперта

Хоть это и небольшая программа, и все функции можно было бы уместить в одном файле, всё-таки намного удобнее ориентироваться в проекте, когда всё разложено по своим местам. Поэтому, изначально функции лучше распределять по типу в разных файлах и подключать их к основному. На рисунке ниже показано как эксперт OnTheFly и все подключенные файлы располагаются в общей папке проекта. Подключенные файлы находятся в отдельной папке (Include).

Рис. 2. Файлы проекта в навигаторе редактора MetaEditor

Рис. 2. Файлы проекта в навигаторе редактора MetaEditor

Когда подключаемые файлы находятся в одной папке с основным, в коде это выглядит так:

//+------------------------------------------------------------------+
//| СВОИ БИБЛИОТЕКИ                                                  |
//+------------------------------------------------------------------+
#include "Include/!OnChartEvent.mqh"
#include "Include/CREATE_PANEL.mqh"
#include "Include/FILE_OPERATIONS.mqh"
#include "Include/ERRORS.mqh"
#include "Include/ARRAYS.mqh"
#include "Include/TRADE_SIGNALS.mqh"
#include "Include/TRADE_FUNCTIONS.mqh"
#include "Include/GET_STRING.mqh"
#include "Include/GET_COLOR.mqh"
#include "Include/ADD_FUNCTIONS.mqh"

Более подробную информацию по подключению файлов можно посмотреть в Справке по MQL5.

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

// КОПИЯ ВНЕШНИХ ПАРАМЕТРОВ
int    gPeriod_Ind = 0;
double gTakeProfit = 0.0;
double gStopLoss   = 0.0;
bool   gReverse    = false;
double gLot        = 0.0;

Как и во всех экспертах, будут основные функции OnInit, OnTick и OnDeinit. Также будет функция OnTimer. В ней каждую секунду будет производиться проверка существования файла с параметрами и его восстановление, если его случайно удалили. Поскольку нам нужно взаимодействие с пользовательской панелью, то будет ещё функция OnChartEvent. Эту функцию и некоторые другие связанные с ней функции я поместил в отдельный файл (!OnChartEvent.mqh).

Основной код главного файла:

#define szArrIP 5 // Размер массива параметров
#define NAME_EXPERT MQL5InfoString(MQL5_PROGRAM_NAME) // Имя эксперта
#define TRM_DP TerminalInfoString(TERMINAL_DATA_PATH) // Папка, в которой хранятся данные терминала
//+------------------------------------------------------------------+
//| СТАНДАРТНЫЕ БИБЛИОТЕКИ                                           |
//+------------------------------------------------------------------+
#include <Trade/SymbolInfo.mqh>
#include <Trade/Trade.mqh>
//+------------------------------------------------------------------+
//| СВОИ БИБЛИОТЕКИ                                                  |
//+------------------------------------------------------------------+
#include "Include/!OnChartEvent.mqh"
#include "Include/CREATE_PANEL.mqh"
#include "Include/FILE_OPERATIONS.mqh"
#include "Include/ERRORS.mqh"
#include "Include/ARRAYS.mqh"
#include "Include/TRADE_SIGNALS.mqh"
#include "Include/TRADE_FUNCTIONS.mqh"
#include "Include/GET_STRING.mqh"
#include "Include/GET_COLOR.mqh"
#include "Include/ADD_FUNCTIONS.mqh"
//+------------------------------------------------------------------+
//| СОЗДАНИЕ ЭКЗЕМПЛЯРОВ КЛАССОВ                                     |
//+------------------------------------------------------------------+
CSymbolInfo mysymbol; // Объект класса CSymbolInfo
CTrade      mytrade;  // Объект класса CTrade
//+------------------------------------------------------------------+
//| ВНЕШНИЕ ПАРАМЕТРЫ                                                |
//+------------------------------------------------------------------+
input int    Period_Ind      = 10;    // Indicator Period
input double TakeProfit      = 100;   // Take Profit (p)
input double StopLoss        = 30;    // Stop Loss (p)
input bool   Reverse         = false; // Reverse Position
input double Lot             = 0.1;   // Lot
//---
input string slash="";       // * * * * * * * * * * * * * * * * * * *
sinput bool  InfoPanel       = true;  // On/Off Info Panel
sinput bool  SettingOnTheFly = false; // Setting "On The Fly"
//+------------------------------------------------------------------+
//| ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ                                            |
//+------------------------------------------------------------------+
int hdlSI=INVALID_HANDLE; // Хэндл сигнального индикатора
double lcheck=0;  // Для проверки значений параметров
bool isPos=false; // Наличие позиции
//--- КОПИЯ ВНЕШНИХ ПАРАМЕТРОВ
int    gPeriod_Ind = 0;
double gTakeProfit = 0.0;
double gStopLoss   = 0.0;
bool   gReverse    = false;
double gLot        = 0.0;
//+------------------------------------------------------------------+
//| ИНИЦИАЛИЗАЦИЯ ЭКСПЕРТА                                           |
//+------------------------------------------------------------------+
void OnInit()
  {
   if(NotTest()) { EventSetTimer(1); } // Включим таймер, если это не тестер
//---
   Init_arr_vparams(); // Инициализация массива значений параметров
   SetParameters(); // Установим параметры
   GetIndicatorsHandles(); // Получаем хендлы индикаторов
   NewBar(); // Инициализация нового бара
   SetInfoPanel(); // Информационная панель
  }
//+------------------------------------------------------------------+
//| ТИКИ ТЕКУЩЕГО СИМВОЛА                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
// Если бар не новый, выходим
   if(!NewBar()) { return; }
   else
     { TradingBlock(); }
  }
//+------------------------------------------------------------------+
//| ТАЙМЕР                                                           |
//+------------------------------------------------------------------+
void OnTimer()
  {
   SetParameters(); SetInfoPanel();
  }
//+------------------------------------------------------------------+
//| ДЕИНИЦИАЛИЗАЦИЯ ЭКСПЕРТА                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Получить код причины деинициализации
   if(NotTest()) {
     { Print(getUnitReasonText(reason)); }
//---
// При удалении с графика
   if(reason==REASON_REMOVE)
     {
      // Удалить все объекты, созданные экспертом
      DeleteAllExpertObjects();
      //---
      if(NotTest()) { EventKillTimer(); } // Отключим таймер
      IndicatorRelease(hdlSI); // Удалим хэндл индикатора
     }
  }

В главном файле я также оставил ещё некоторые функции:

  • Функция GetIndicatorsHandles – получает хэндл индикатора.
  • Функция NewBar – определяет событие наступления нового бара.
  • Функция SetParameters – устанавливает параметры в зависимости от установленного режима.
  • Функция iZeroMemory – обнуляет некоторые переменные и массивы.
Код этих функций можно посмотреть в приложенных к статье файлах. Здесь рассмотрим только функцию SetParameters (пояснительные комментарии в коде):
//+------------------------------------------------------------------+
//| УСТАНАВЛИВАЕТ ПАРАМЕТРЫ В ДВУХ РЕЖИМАХ                           |
//+------------------------------------------------------------------+
// Если эта переменная имеет значение false, то параметры из файла читаются из массива,
// в котором они сохраняются после первого чтения для быстрого доступа.
// Переменная обнуляется после изменения значения на панели.
bool flgRead=false;
double arrParamIP[]; // Массив, в котором сохраняются параметры из файла
//---
void SetParameters()
  {
// Если сейчас в тестере или
// в реал-тайме, но с отключенным режимом Настройки "на лету"
   if(!NotTest() || (NotTest() && !SettingOnTheFly))
     {
      // Обнулим переменную и массив параметров
      flgRead=false;
      ArrayResize(arrParamIP,0);
      //---
      // Проверим на корректность параметр Период Индикатора
      if(Period_Ind<=0)
        { lcheck=10; }
      else { lcheck=Period_Ind; }
      gPeriod_Ind=(int)lcheck;
      //---
      gStopLoss=StopLoss;
      gTakeProfit=TakeProfit;
      gReverse=Reverse;
      //---
      // Проверим на корректность параметр Объём (лот)
      if(Lot<=0)
        { lcheck=0.1; }
      else { lcheck=Lot; }
      gLot=lcheck;
     }
   else // Если включен параметр Настройка "на лету"
     {
      // Проверим, есть ли файл для записи/чтения параметров в/из файла
      string lpath="";
      //---
      // Если директория существует
      if((lpath=CheckCreateGetPath())!="")
        {
         // Запишем или прочитаем файл
         WriteReadParameters(lpath);
        }
     }
  }

Код функции SetParameters прост и понятен. Рассмотрим подробнее функцию WriteReadParameters. Всё довольно просто - сначала проверяется, есть ли файл с параметрами. Если файл есть, то с помощью функции GetValuesParamsFromFile читаем файл и заносим значения параметров в массив. Если же файла нет, то он создаётся, и в него записываются текущие внешние параметры.

Ниже представлен код, который выполняет вышеописанные действия с ещё более подробными комментариями:

//+------------------------------------------------------------------+
//| ЗАПИШЕМ ДАННЫЕ В ФАЙЛ                                            |
//+------------------------------------------------------------------+
void WriteReadParameters(string pth)
  {
   string nm_fl=pth+"ParametersOnTheFly.ini"; // Имя файла и путь файла
//---
// Получим хэндл файла для чтения
   int hFl=FileOpen(nm_fl,FILE_READ|FILE_ANSI);
//---
   if(hFl!=INVALID_HANDLE) // Если хэндл получен, то файл есть
     {
      // Получим параметры из файла
      if(!flgRead)
        {
         // Установим размер массива
         ArrayResize(arrParamIP,szArrIP);
         //---
         // Заполним массив значениями из файла
         flgRead=GetValuesParamsFromFile(hFl,arrParamIP);
        }
      //---
      // Если размер массива корректен, то ...
      if(ArraySize(arrParamIP)==szArrIP)
        {
         // ...установим параметры в переменные
         //---
         // Проверим на корректность параметр Период Индикатора
         if((int)arrParamIP[0]<=0) { lcheck=10; }
         else { lcheck=(int)arrParamIP[0]; }
         gPeriod_Ind=(int)lcheck;
         //---
         gTakeProfit=arrParamIP[1];
         gStopLoss=arrParamIP[2];
         gReverse=arrParamIP[3];
         //---
         // Проверим на корректность параметр Объём (лот)
         if(arrParamIP[4]<=0)
           { lcheck=0.1; }
         else { lcheck=arrParamIP[4]; }
         gLot=lcheck;
        }
     }
   else // Если файла нет
     {
      iZeroMemory(); // Обнулим переменные
      //---
      // При создании файла, запишем текущие параметры эксперта
      //---
      // Получим хэндл файла для записи
      int hFl2=FileOpen(nm_fl,FILE_WRITE|FILE_CSV|FILE_ANSI,"");
      //---
      if(hFl2!=INVALID_HANDLE) // Если хэндл получен
        {
         string sep="=";
         //---
         // Названия параметров и их значения берутся из массивов в файле ARRAYS.mqh
         for(int i=0; i<szArrIP; i++)
           { FileWrite(hFl2,arr_nmparams[i],sep,arr_vparams[i]); }
         //---
         FileClose(hFl2); // Закроем файл
         //---
         Print("Создан файл с параметрами эксперта "+NAME_EXPERT+".");
        }
     }
//---
   FileClose(hFl); // Закроем файл
  }

Функции WriteReadParameters и GetValuesParamsFromFile находятся в файле FILE_OPERATIONS.mqh.

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


3. Взаимодействие с пользовательской панелью

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

// Текущее значение на панели или
// введённое в поле ввода
string currVal="";
bool flgDialogWin=false; // Флаг существования панели
int
szArrList=0,// Размер массива списка вариантов
number=-1; // Номер параметра в списке на панели
string
nmMsgBx="",  // Имя диалогового окна
nmValObj=""; // Имя выбранного объекта
//---
// Массивы списка вариантов в диалоговом окне
string lenum[],lenmObj[];
//---
// Цвета элементов диалогового окна
color
clrBrdBtn=clrWhite,
clrBrdFonMsg=clrDimGray,clrFonMsg=C'15,15,15',
clrChoice=clrWhiteSmoke,clrHdrBtn=clrBlack,
clrFonHdrBtn=clrGainsboro,clrFonStr=C'22,39,38';

Далее следует главная функция, в которой обрабатываются события. В этом примере нам понадобится обрабатывать два:

  • Событие CHARTEVENT_OBJECT_CLICK – нажатие левой кнопкой мыши на графическом объекте.
  • Событие CHARTEVENT_OBJECT_EDIT – окончание редактирования текста в графическом объекте Edit.

С остальными событиями в языке MQL5 можно ознакомиться в Справке.

Вначале установим проверку для обработки событий только в реальном времени и если включена опция изменения параметров на лету (SettingOnTheFly). Обработку событий поместим в отдельные функции: ChartEvent_ObjectClick и ChartEvent_ObjectEndEdit.

//+------------------------------------------------------------------+
//| ПОЛЬЗОВАТЕЛЬСКИЕ СОБЫТИЯ                                         |
//+------------------------------------------------------------------+
void OnChartEvent(const int     id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
// Если реал-тайм и включена опция Настройка "на лету"
   if(NotTest() && SettingOnTheFly)
     {
      //+------------------------------------------------------------------+
      //| СОБЫТИЕ CHARTEVENT_OBJECT_CLICK                                  |
      //+------------------------------------------------------------------+
      if(ChartEvent_ObjectClick(id,lparam,dparam,sparam)) { return; }
      //---
      //+------------------------------------------------------------------+
      //| СОБЫТИЕ CHARTEVENT_OBJECT_ENDEDIT                                |
      //+------------------------------------------------------------------+
      if(ChartEvent_ObjectEndEdit(id,lparam,dparam,sparam)) { return; }
     }
//---
   return;
  }

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

Рис. 3. Диалоговое окно для изменения значения выбранного параметра

Рис. 3. Диалоговое окно для изменения значения выбранного параметра

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

Если нужно, чтобы диалоговое окно открывалось по центру графика, нужно получить размеры графика. Это можно выяснить, указав в функции ChartGetInteger свойства CHART_WIDTH_IN_PIXELS и CHART_HEIGHT_IN_PIXELS. Далее осуществляется переход в функцию DialogWindowInfoPanel. Со всеми свойствами графика можно ознакомиться в Справке.

Ниже представлен код вышеописанных действий:

//+------------------------------------------------------------------+
//| СОБЫТИЕ CHARTEVENT_OBJECT_CLICK                                  |
//+------------------------------------------------------------------+
bool ChartEvent_ObjectClick(int id,long lparam,double dparam,string sparam)
  {
   // Если было событие Нажатие на графическом объекте
   if(id==CHARTEVENT_OBJECT_CLICK) // id==1
     {
      Get_STV(); // Получим все данные по символу
      //---
      string clickedChartObject=sparam; // Имя нажатого объекта
      //---
      // Получим размеры графика
      width_chart=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,0);
      height_chart=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,0);
      //---
      DialogWindowInfoPanel(clickedChartObject);
     }
//---
   return(false);
  }

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

Если в начале функции DialogWindowInfoPanel оказывается, что диалоговое окно уже открыто, то программа будет проверять, был ли произведён клик по объекту в диалоговом окне. Например, в диалоговом окне при открытии будет выделена та строка в списке, значение которой сейчас на панели. Если нажать на другой вариант в списке, то программа перейдёт к функции SelectionOptionInDialogWindow, которая выделяет нажатый вариант в списке диалогового окна.

Если же произвести нажатие по уже выделенной строке в списке, то, если этот объект определён как редактируемый, появится поле ввода, нажав на которое можно ввести новое значение. За установку поля ввода отвечает функция SetEditObjInDialogWindow.

И, наконец, если было нажатие на кнопке Apply, то производится проверка, было ли изменено значение. Если да, то новое значение появляется на панели и записывается в файл.

Ниже можно ознакомиться с кодом основной функции диалогового окна:

//+------------------------------------------------------------------+
//| ДИАЛОГОВОЕ ОКНО ИНФОРМАЦИОННОЙ ПАНЕЛИ                            |
//+------------------------------------------------------------------+
void DialogWindowInfoPanel(string clickObj)
  {
// Если диалогового окна в текущий момент нет
   if(!flgDialogWin)
     {
      // Получим номер объекта в массиве
      // Выходим, если клик был не по параметрам на панели
      if((number=GetNumberClickedObjIP(clickObj))==-1) { return; }
      //---
      // Инициализация значений по умолчанию
      // и определение размера массива списка
      if(!InitArraysAndDefault()) { return; }
      //---
      // Установим диалоговое окно
      SetDialogWindow();
      //---
      flgDialogWin=true; // Отметим, что диалоговое окно открыто
      ChartRedraw();
     }
   else // Если диалоговое окно открыто
     {
      // Установим поле ввода для редактирования значения
      SetEditObjInDialogWindow(clickObj);
      //---
      // Если нажата одна из кнопок диалогового окна
      if(clickObj=="btnApply" || clickObj=="btnCancel")
        {
         // Если нажата кнопка Apply (Принять)
         if(clickObj=="btnApply")
           {
            // Сравним значения на панели и в списке
            // Если значение в списке отличается от того, что сейчас на панели (а значит и в файле),
            // ...то изменим значение на панели и перепишем файл
            if(currVal!=ObjectGetString(0,nmValObj,OBJPROP_TEXT))
              {
               // Обновим значение на панели
               ObjectSetString(0,nmValObj,OBJPROP_TEXT,currVal); ChartRedraw();
               //---
               // Прочитаем все данные на панели и запишем их в файл
               WriteNewData();
              }
           }
         //---
         DelDialogWindow(lenmObj); // Удалим окно сообщения
         iZeroMemory(); // Обнулим переменные
         //---
         // Обновим данные
         SetParameters();
         GetHandlesIndicators();
         SetInfoPanel();
         //---
         ChartRedraw();
        }
      else // Если это не Apply или Cancel
        {
         // Выделение варианта в списке диалогового окна
         SelectionOptionInDialogWindow(clickObj);
         //---
         ChartRedraw();
        }
     }
  }

Каждый раз после ввода нового значения в поле ввода генерируется событие CHARTEVENT_OBJECT_EDIT, и программа заходит в функцию ChartEvent_ObjectEndEdit. Если было изменено значение из диалогового окна, то запоминаем введённое значение, проверяем значение на корректность и присваиваем его объекту в списке. Подробнее можно посмотреть в коде ниже:

//+------------------------------------------------------------------+
//| СОБЫТИЕ CHARTEVENT_OBJECT_ENDEDIT                                |
//+------------------------------------------------------------------+
bool ChartEvent_ObjectEndEdit(int id,long lparam,double dparam,string sparam)
  {
   if(id==CHARTEVENT_OBJECT_ENDEDIT) // id==3
     {
      string editObject=sparam; // Имя отредактированного объекта
      //---
      // Если было изменено значение из поля ввода в диалоговом окне
      if(editObject=="editValIP")
        {
         // Получим введённое значение
         currVal=ObjectGetString(0,"editValIP",OBJPROP_TEXT);
         //---
         // (0) Period Indicator
         if(number==0)
           {
            // При ошибочном значении скорректируем его
            if(currVal=="0" || currVal=="" || SD(currVal)<=0) { currVal="1"; }
            //---
            // Установим введённое значение
            ObjectSetString(0,"enumMB0",OBJPROP_TEXT,currVal);
           }
         //---
         // (4) Lot
         if(number==4)
           {
            // При ошибочном значении сорректируем его
            if(currVal=="0" || currVal=="" || SD(currVal)<=0) { currVal=DS(SS.vol_min,2); }
            //---
            // Установим введённое значение
            ObjectSetString(0,"enumMB0",OBJPROP_TEXT,DS2(SD(currVal)));
           }
         //---
         // (1) Take Profit (p)
         // (2) Stop Loss (p)
         if(number==1 || number==2)
           {
            // При ошибочном значении скорректируем его
            if(currVal=="0" || currVal=="" || SD(currVal)<=0) { currVal="1"; }
            //---
            // Установим введённое значение
            ObjectSetString(0,"enumMB1",OBJPROP_TEXT,currVal);
           }
         //---         
         DelObjbyName("editValIP"); ChartRedraw();
        }
     }
//---
   return(false);
  }

На видео ниже продемонстрирована работа эксперта:



Заключение

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

Надеюсь, что эта статья поможет быстро разобраться на простых примерах со многими вопросами всем, кто начинает осваивать MQL5. В представленном примере я намеренно не поставил некоторые проверки в коде.

Например, если в тот момент, когда диалоговое окно открыто, изменить высоту/ширину графика, то положение диалогового окна не восстановится по центру. А если ещё после этого выбрать в списке другой вариант, то объект, который служит для выделения строки, будет заметно смещён. Пусть это будет домашним заданием. Практика в программировании тоже нужна. И чем её больше, тем лучше.

Успехов!

Прикрепленные файлы |
onthefly_ru.zip (28.65 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (49)
Andrey Khatimlianskii
Andrey Khatimlianskii | 23 ноя 2012 в 17:13
FAQ:
  хотелось бы сделать это так, что бы это мог сделать любой. 

А вот это уже в пол-куска не влезет. Да и не будет валяться бесплатно в базе.

Но сейчас задача другая. 

Denis Lazarev
Denis Lazarev | 23 ноя 2012 в 17:24
FAQ:

   В чем большой минус  EA Tree и ей подобных программ - это довольно сложный интерфейс, и необходимость (требование) от пользователя знаний хотя бы основ алгоритмики. Для того что бы начать ею пользоваться, ее надо предварительно изучить. а это время. Ну и опять же не каждый это сможет. То есть она рассчитана не  на трейдера, но на программиста. Когда мне год назад предложили написать подобный конструктор, я сразу откинул этот метод построения стратегии. Из за сложности его усвоения конечным потребителем в первую очередь.

 И откуда такой скептицизм по отношению к пятому языку ? По сравнению с четверкой в нем (как и в пятом терминале) есть все необходимые возможности для построения подобной программы. 

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

FAQ:

И откуда такой скептицизм по отношению к пятому языку ?

А где вы его увидели? Я говорю про то что EA Tree и ей подобные написаны на другом языке програмирования и как-то совместить их с программой mql5 будет крайне сложно

И извините если не прав, но помоему вы всячески пытаетесь повернуть диалог в сторону рекламы http://mykibo.com/index.php

Rustamzhan Salidzhanov
Rustamzhan Salidzhanov | 23 ноя 2012 в 18:11
lazarev-d-m:

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

А где вы его увидели? Я говорю про то что EA Tree и ей подобные написаны на другом языке програмирования и как-то совместить их с программой mql5 будет крайне сложно

И извините если не прав, но помоему вы всячески пытаетесь повернуть диалог в сторону рекламы http://mykibo.com/index.php

  Нет, я всячески пытаюсь завести диалог в сторону разработки действительно интуитивного и понятного интерфейса. 
Rustamzhan Salidzhanov
Rustamzhan Salidzhanov | 23 ноя 2012 в 18:12
komposter:

А вот это уже в пол-куска не влезет. Да и не будет валяться бесплатно в базе.

Но сейчас задача другая. 

  Ну она стоко и не стоила.
Denis Lazarev
Denis Lazarev | 23 ноя 2012 в 18:16
FAQ:
   Нет, я всячески пытаюсь завести диалог в сторону разработки действительно интуитивного и понятного интерфейса. 
В идеале было бы не плохо если бы тестер был интуитивно понятным, но для старта можно было бы сначала сдвинуть идею к началу реализации, и когда хоть что-то будет готово улучшать в сторону наглядности и "понятности"
Как протестировать торгового робота перед покупкой Как протестировать торгового робота перед покупкой

Покупка торгового робота в MQL5 Маркете имеет одно большое преимущество перед всеми другими подобными предложениями - вы можете устроить комплексную проверку предлагаемой автоматической системы прямо в терминале MetaTrader 5. Каждый советник перед покупкой можно и нужно тщательно прогнать во всех неблагоприятных режимах во встроенном тестере торговых стратегий, чтобы получить о нем максимально полное представление.

Интервью с Дмитрием Терентьевым (ATC 2012) Интервью с Дмитрием Терентьевым (ATC 2012)

Нужно ли быть программистом, чтобы писать торговых роботов? Должны ли вы провести годы в наблюдении за графиками цен, чтобы понять рынок и почувствовать его пульс? Эти вопросы мы затронули в интервью с Дмитрием Терентьевым (SAFF), чей торговый робот держится на первой странице Чемпионата с самого его начала.

Интервью с Хуаном Пабло Алонсо Эскобаром (ATC 2012) Интервью с Хуаном Пабло Алонсо Эскобаром (ATC 2012)

"Кто испытывает трудности с программированием и не смог принять участие в нынешнем Чемпионате, я могу сказать только одно - со временем все становится намного проще", - заявил Хуан Пабло Алонсо Эскобар (JPAlonso), герой нашего сегодняшнего интервью.

Как стать поставщиком сигналов для MetaTrader 4 и MetaTrader 5 Как стать поставщиком сигналов для MetaTrader 4 и MetaTrader 5

Хотите раздавать свои торговые сигналы и получать за это деньги? Зарегистрируйтесь на сайте MQL5.com в статусе продавца, укажите свой торговый счет, и вы сможете предложить трейдерам подписку на ваши сигналы.