AM2
Андрей

 
Уровень 35

  Торгую в компаниях:


Группа "Программирование на MQL"

Рейтинг 280



Создание торговой панели с использованием классов стандартной библиотеки МТ4

Не так давно я впервые создал и поделился с вами способом создания торговой панели на основе графических объектов. Топик назывался "Панель управления на MQL4 это просто!"

Сейчас я хочу предложить более трудозатратный но намного более интересный способ написания торговой панели. В основу легла статья СОЗДАЕМ ПОМОЩНИКА В РУЧНОЙ ТОРГОВЛЕ. Я немного переделал этот урок для терминала МТ4.

На нашей панели будет 3 кнопки, метка и поле для редактирования и выглядеть она будет следующим образом:



Первым делом создадим следующую заготовку на базе класса CAppDialog.

//+------------------------------------------------------------------+
//|                                                      Panelka.mq4 |
//|                                              Copyright 2016, AM2 |
//|                                      http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, AM2"
#property link      "http://www.forexsystems.biz"
#property version   "1.00"
#property strict

#include <Controls\Dialog.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTradePanel : public CAppDialog
  {
public:
                     CTradePanel(void){};
                    ~CTradePanel(void){};
  };

CTradePanel TradePanel;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   // Create Trade Panel
// Create Trade Panel
   TradePanel.Create(ChartID(),"Panelka",0,20,20,150,200);
   // Run Trade Panel
   TradePanel.Run();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+


Выглядеть она будет так:



Чтобы нанести на панель необходимые нам элементы, создадим объекты соответствующих классов.

Добавляем необходимые включаемые файлы и создаем функцию Creat() для класса CTradePanel:


#include <Controls\Dialog.mqh>
#include <Controls\Label.mqh>
#include <Controls\Button.mqh>


Для каждого объекта на панели в классе CTradePanel объявляем переменные соответствующего типа, и там же объявляем процедуру Creat(..), в которой и расставим все элементы по своим местам. Обратите внимание: объявление переменных и другие действия внутри класса CTradePanel мы объявляем в блоке «private». Функции же, доступные для вызова из-за пределов класса, такие как Creat(...), объявляются в блоке «public».

class CTradePanel : public CAppDialog
  {
private:

   CLabel            Lots_label;                      // Display label " Lots"
   CEdit             Lots;                            // Display volume of next order
   CButton           SELL,BUY;                        // Sell and Buy Buttons
   CButton           CloseAll;                        // Close buttons

public:
                     CTradePanel(void){};
                    ~CTradePanel(void){};
   virtual bool      Create(const long chart,const string name,const int subwin=0,const int x1=20,const int y1=20,const int x2=320,const int y2=420);

  };



Создадим функции для отбражения наших элементов на панели:

Класс CLabel мы будем использовать для отображения информационного текста на нашей панели.


bool CTradePanel::CreateLabel(const long chart,const int subwindow,CLabel &object,const string text,const uint x,const uint y,label_align align)
  {
// All objects must have separate name
   string name=m_name+"Label"+(string)ObjectsTotal(chart,-1,OBJ_LABEL);
//--- Call Create function
   if(!object.Create(chart,name,subwindow,x,y,0,0))
     {
      return false;
     }
//--- Adjust text
   if(!object.Text(text))
     {
      return false;
     }
//--- Align text to Dialog box's grid
   ObjectSetInteger(chart,object.Name(),OBJPROP_ANCHOR,(align==left ? ANCHOR_LEFT_UPPER <img src='http://opentraders.ru/templates/skin/g6h/images/smilies/005.gif' alt=' ( '> align==right ? ANCHOR_RIGHT_UPPER : ANCHOR_UPPER)));
//--- Add object to controls
   if(!Add(object))
     {
      return false;
     }
   return true;
  }


Класс CButton предназначен для создания кнопок прямоугольной формы с надписью. Это наши стандартные кнопки открытия и закрытия ордеров.


bool CTradePanel::CreateButton(const long chart,const int subwindow,CButton &object,const string text,const uint x,const uint y,const uint x_size,const uint y_size)
  {
// All objects must have separate name
   string name=m_name+"Button"+(string)ObjectsTotal(chart,-1,OBJ_BUTTON);
//--- Call Create function
   if(!object.Create(chart,name,subwindow,x,y,x+x_size,y+y_size))
     {
      return false;
     }
//--- Adjust text
   if(!object.Text(text))
     {
      return false;
     }
//--- set button flag to unlock
   object.Locking(false);
//--- set button flag to unpressed
   if(!object.Pressed(false))
     {
      return false;
     }
//--- Add object to controls
   if(!Add(object))
     {
      return false;
     }
   return true;
  }


Класс CEdit предназначен для создания объектов ввода данных.


bool CTradePanel::CreateEdit(const long chart,const int subwindow,CEdit &object,const string text,const uint x,const uint y,const uint x_size,const uint y_size)
  {
// All objects must have separate name
   string name=m_name+"Edit"+(string)ObjectsTotal(chart,-1,OBJ_EDIT);
//--- Call Create function
   if(!object.Create(chart,name,subwindow,x,y,x+x_size,y+y_size))
     {
      return false;
     }
//--- Adjust text
   if(!object.Text(text))
     {
      return false;
     }
//--- Align text in Edit box
   if(!object.TextAlign(ALIGN_CENTER))
     {
      return false;
     }
//--- set Read only flag to false
   if(!object.ReadOnly(false))
     {
      return false;
     }
//--- Add object to controls
   if(!Add(object))
     {
      return false;
     }
   return true;
  }


Объявим эти функции в блоке «private» нашего класса.


private:

   //--- Create Label object
   bool              CreateLabel(const long chart,const int subwindow,CLabel &object,const string text,const uint x,const uint y,label_align align);
   //--- Create Button
   bool              CreateButton(const long chart,const int subwindow,CButton &object,const string text,const uint x,const uint y,const uint x_size,const uint y_size);
   //--- Create Edit object
   bool              CreateEdit(const long chart,const int subwindow,CEdit &object,const string text,const uint x,const uint y,const uint x_size,const uint y_size);
   //--- Create BMP Button
   bool              CreateBmpButton(const long chart,const int subwindow,CBmpButton &object,const uint x,const uint y,string BmpON,string BmpOFF,bool lock);


Теперь напишем функцию, которая создаст все элементы на панели:


bool CTradePanel::Create(const long chart,const string name,const int subwin=0,const int x1=20,const int y1=20,const int x2=320,const int y2=420)
  {
// At first call create function of parents class
   CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2);

// Calculate coordinates and size of BID object

// Create object
   CreateLabel(chart,subwin,Lots_label,"LOT",55,5,0);
   CreateEdit(chart,subwin,Lots,"0.1",33,35,60,20);
   CreateButton(chart,subwin,BUY,"BUY",33,65,60,20);
   CreateButton(chart,subwin,SELL,"SELL",33,95,60,20);
   CreateButton(chart,subwin,CloseAll,"CLOSE",33,125,60,20);

   return(true);
  }


События от нажатия кнопок обрабатываются функцией OnChartEvent.


//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   TradePanel.OnEvent(id, lparam, dparam, sparam);
  }


Пропишем ее в родительском классе:


public:

   virtual bool      OnEvent(const int id,const long &lparam, const double &dparam, const string &sparam);


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


//+------------------------------------------------------------------+
//| Event Handling                                                   |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CTradePanel)
ON_EVENT(ON_END_EDIT,Lots,LotsEndEdit)
ON_EVENT(ON_CLICK,BUY,BuyClick)
ON_EVENT(ON_CLICK,SELL,SellClick)
ON_EVENT(ON_CLICK,CloseAll,CloseClick)
EVENT_MAP_END(CAppDialog)


Соответственно, все функции обработки событий мы должны объявить в блоке «private» нашего класса


private:

   //--- On Event functions
   void              LotsEndEdit(void);               // Edit Lot size

   //--- variables of current values
   double            cur_lot;                         // Lot of next order

   void              BuyClick();                      // Click BUY button
   void              SellClick();                     // Click SELL button
   void              CloseClick();                    // Click CLOSE button   



Сами фцнкции обработкки событий будут выглядеть так:


//+------------------------------------------------------------------+
//|  Click BUY button                                                |
//+------------------------------------------------------------------+
void CTradePanel::BuyClick(void)
  {
   PutOrder(0,Ask);
  }
//+------------------------------------------------------------------+
//|  Click SELL button                                               |
//+------------------------------------------------------------------+
void CTradePanel::SellClick(void)
  {
   PutOrder(1,Bid);
  }
//+------------------------------------------------------------------+
//|  Click CLOSE button                                              |
//+------------------------------------------------------------------+
void CTradePanel::CloseClick(void)
  {
   CloseAll();
  }


Для торговых операций воспользуемся заготовленными заранее функциями:


//+------------------------------------------------------------------+
//| Установка ордера                                                 |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
  {
   int r=0;
   color clr=Green;
   double sl=0,tp=0;

   if(type==1 || type==3 || type==5)
     {
      clr=Red;
      if(StopLoss>0)   sl=NormalizeDouble(price+StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
     }

   if(type==0 || type==2 || type==4)
     {
      clr=Blue;
      if(StopLoss>0)   sl=NormalizeDouble(price-StopLoss*Point,Digits);
      if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
     }

   r=OrderSend(NULL,type,Lot,NormalizeDouble(price,Digits),Slip,sl,tp,"",Magic,0,clr);
   return;
  }
//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера                                  |
//+------------------------------------------------------------------+
void CloseAll(int ot=-1)
  {
   bool cl;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderType()==0 && (ot==0 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
              }
            if(OrderType()==1 && (ot==1 || ot==-1))
              {
               RefreshRates();
               cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
              }
           }
        }
     }
  }


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


//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   TradePanel.Destroy(reason);
   return;
  }


Эту функцию мы должны объявить в блоке public нашего класса:


public:
.............
   virtual void      Destroy(const int reason);


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

//+------------------------------------------------------------------+
//| Application deinitialization function                            |
//+------------------------------------------------------------------+
void CTradePanel:<img src='http://opentraders.ru/templates/skin/g6h/images/smilies/003.gif' alt=' :D '> estroy(const int reason)
  {
   CAppDialog:<img src='http://opentraders.ru/templates/skin/g6h/images/smilies/003.gif' alt=' :D '> estroy(reason);
   return;
  }


И наконец пропишем входные переменные для советника:


extern double Lot        = 0.1;      // лот
extern int StopLoss      = 500;      // лось
extern int TakeProfit    = 500;      // язь
extern int Slip          = 30;       // реквот
extern int Magic         = 0;        // магик


На этом все и сейчас посмотрит результат работы нашей панели.
Нажимает кнопку бай:



Жмем клоуз, закрылись:



Более подробный урок можете посмотреть по ссылке выше. Если у кого есть какие то вопросы спрашивайте :D 
Скачать советник: www.opentraders.ru/downloads/1209/
  • +6
  • Просмотров: 25819
  • 14 июня 2016, 19:02
  • AM2
Понравилcя материал? Не забудьте поставить плюс и поделиться в социальной сети!

Вступите в группу "Программирование на MQL", чтобы следить за обновлениями
ПРИСОЕДИНИТЬСЯ К ГРУППЕ
присоединиться
  Предыдущая запись в группе
Индикатор "Спидометр"
Следующая запись в группе  
Индикатор опционных уровней для MT4 и МТ5
08 июня 2016
12 июля 2016

Брокер для ваших роботов, 15 лет на рынке

Комментарии (24)

+
0
А чего с такой ехидцей?
Если у кого есть какие то вопросы спрашивайте :D 

:D 
avatar

  27  Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..

  • 14 июня 2016, 19:29
+
0
У меня 7 часов ушло чтобы разобраться хоть немного, я думаю не у всех терпения хватит.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 14 июня 2016, 19:31
+
0
Мне другое не понятно. Классы они на то и классы, чтобы быть в отдельных разных файлах. Ты создал класс CTradePanel со своими функциями. Зачем ты это всё поместил внутрь эксперта? Это не логично. Внутри эксперта логичны только функции.
Каждый класс со своими функциями отдельным файлом. К ним только обращаться и расширять их, может быть изменять, но не залезая к ним внутрь. (в этом их и суть)
avatar

  27  Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..

  • 14 июня 2016, 19:40
+
0
Я давно хотел сделать такую штуку. Нашел такой вариант реализации, если у тебя есть другой, с удовольствием рассмотрю.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 14 июня 2016, 21:04
+
0
Я про то, что класс с его функциями вынести в отдельный файл. (ладно, будет настроение, статью напишу)
avatar

  27  Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..

  • 14 июня 2016, 22:49
+
0
avatar

  1  ZeleBoba Сообщений: 7

  • 19 декабря 2016, 11:42
+
0
Имею вопросы:)  Зачем кнопки SELL, BUY И CLOSE:D 
avatar

  19  Kashtan Сообщений: 739 - Игорь

  • 14 июня 2016, 23:19
+
+1
Опять бухой пришел?*haha*  Что тут не понятного?*wall* 
avatar

  7  Vitalik5675 Сообщений: 282

  • 14 июня 2016, 23:30
+
0
Андрей, чистила в очередной раз терминал от лишних индикаторов и советников и наткнулась на образец SimplePanel:

Там три файла:

Вот так выглядит:
avatar

  27  Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..

  • 16 июня 2016, 00:16
+
0
На этой основе тоже можно сделать, только я PanelDialog.mqh файл не нашел нашлось только Panel.mqh
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 16 июня 2016, 07:41
+
0
может у тебя он просто по-другому называется? у меня у двух брокеров — PanelDialog
А индикатор панель такую же строит?
avatar

  27  Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..

  • 17 июня 2016, 02:11
+
0
PanelDialog.mqh находится в папке Indicators=>Examples=>SimplePanel

Если это конечно актуально спустя столько лет.

Или может это вовсе не то.
avatar

  20  alex30774 Сообщений: 778

  • 17 сентября 2022, 18:24
+
0
Панелька такая же.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 17 июня 2016, 07:49
+
0
Подскажите, если сможете как исправить.
Дело в том, что когда я добавляю другие кнопки в панель, то они не перемещаются вместе с панелью а висят на одном месте, тоже самое при закрытии панели
А еще не работает переключение лотности, когда другой лот вбиваю, открывается всегда одним и тем же.
Ах да еще вопрос хотел, еще одну панель такую же рядом, с другим набором кнопок, но они чего то конфликтуют, хотя не должны.
И на масое главное, какая функция отвечает за перетаскивание панели по графику?
Наверное надо код приложить и скрин я чуть поздне добавлю.
Редактирован: 13 ноября 2016, 16:30
avatar

  16  cerber04 Сообщений: 409

  • 13 ноября 2016, 16:15
+
0
Я все делал на лету, разбирался и переписывал с первоисточника. Ссылка в самом начале. Здесь только основа, лот с поля редактирования не считывается.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 13 ноября 2016, 17:16
+
0
Напиши в столе заказов что нужно сделать, посмотрю завтра.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 13 ноября 2016, 17:40
+
0
Cпасибо, неплохо для ликбеза. Осваиваю потихоньку классы.
Ваш вариант работает на реальных графиках, но на тестере события не срабатывают. ((
Почему?
avatar

  1  ZeleBoba Сообщений: 7

  • 19 декабря 2016, 11:44
+
0
Как добавить к панельке доп. шаблон кнопки
и подключить к ней нужный скрипт из папки ...\MQL4\Scripts?
Так, чтобы скрипт срабатывал при нажатии на эту кнопку.
avatar

  11  preasto Сообщений: 445

  • 19 декабря 2016, 12:23
+
0
Все подробности по ссылке в начале статьи.
avatar

  35  AM2 Автор Сообщений: 16445 - Андрей

  • 20 декабря 2016, 03:38
+
0
Андрей, подскажите пожалуйста сам код, для подключения к любой кнопке,
чтобы при нажатии на неё запускался указанный отдельный(внешний) скрипт из папки ...\MQL4\Scripts.
(а не заданный(внесённый как функция) из кода самой панельки).
Редактирован: 29 декабря 2016, 15:30
avatar

  11  preasto Сообщений: 445

  • 29 декабря 2016, 15:29
+
0
Скомпилировал панельку в MT4. Столкнулся с такой проблемой — при переключении таймфреймов панелька рассыпается. Нормально проходит только первое переключение. Может кто подскажет, как это побороть?
MT4 Build 1090.

avatar

  0  lova Сообщений: 1

  • 31 июля 2017, 13:59
+
0
Ха! Есть такое)))
Только что испытал)))
Вот как надо:

Вот как при переключении таймфреймов:


Всё работает, всё нормально, но при переключении ТФ реально рассыпается)))

Короче, беда с этой библиотекой, при перходе из ТФ в ТФ множит объекты как из пулемёта, в чём можно убедиться, посмотрев кол-во объектов на графике.
Увы, вот самый приемлемый вариант, через указатель:
CTradePanel *TradePanel;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  TradePanel = new CTradePanel();

   if(!TradePanel.Create(ChartID(),"Put_LIne",0,20,20,150,200))
     return(INIT_FAILED);

   if(!TradePanel.Run())
     return(INIT_FAILED);

   return(INIT_SUCCEEDED); 
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  if(UninitializeReason()!=REASON_CHARTCHANGE)
  {
  delete(TradePanel);
   TradePanel.Destroy(reason);
   }
  
  }

При таком раскладе объекты множатся друг под другом, не в рассыпную, а на изначально заданных координатах.
Редактирован: 17 июля 2019, 19:15
avatar

  24  ShamanHand Сообщений: 1092 - Наношу добро, причиняю пользу.

  • 17 июля 2019, 11:45
+
0
Похоже, лучше всё же делать без дурных библиотек, а через простое создание объектов.
Кода меньше, всё понятней.
avatar

  24  ShamanHand Сообщений: 1092 - Наношу добро, причиняю пользу.

  • 17 июля 2019, 19:23
+
0
А можно сделать кнопки бай и сел цветными, а в настройках — выбор цвета для каждой кнопки?
avatar

  4  qorqis Сообщений: 20

  • 17 декабря 2024, 15:50

Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий