Общее создание класса C_Trade для мета трейдера 4

 

Всем привет!

Недавно в теме вели горячую дискуссию о правильности того или иного кода, по скольку я продолжаю учиться и есть желание не только поделиться своими кодами и опытом но и (получить подзатыльник) получить опыт и примеры других.

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

Код не претендует на идеал по этому давайте сообща сделаем его луще!

class Trade
  {
private:
   MqlTick           tick;
public:

   string            symbol;
   int               type;
   int               error;
   double            lots;
   double            price;
   int               slippage;
   double            stoploss;
   double            takeprofit;
   string            comment;
   int               magic;
   datetime          expiration;
   color             arcolor;
   int               ticket;
   bool              rezult;
   int               digits;
   double            point;
   double            breakeven;
   double            breakstep;
   double            trailing;
   double            trailstep;

   bool              F_Send(Trade  &str);
                     Trade();
                    ~Trade();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Trade ::  Trade(){  }
Trade :: ~Trade(){  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Trade :: F_Send(Trade  &str)
  {
   ResetLastError();
   if(str.symbol==NULL || str.symbol=="")str.symbol=_Symbol;
   if(str.magic==NULL)str.magic=0;
   if(str.comment==NULL || str.comment=="")str.comment=StringConcatenate(WindowExpertName()," ",str.magic);

   int p=0;
   str.digits=(int)SymbolInfoInteger(str.symbol,SYMBOL_DIGITS);
   str.point =SymbolInfoDouble (str.symbol,SYMBOL_POINT);

   if(str.lots<SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN);
   if(str.lots>SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX);

   while(!IsTradeContextBusy() && p++<5)
     {
      if(!SymbolInfoTick(str.symbol,tick))
      Print("SymbolInfoTick() failed, error = ",GetLastError());
      if(str.type==OP_BUY ) str.price=NormalizeDouble(tick.ask,str.digits);
      if(str.type==OP_SELL) str.price=NormalizeDouble(tick.bid,str.digits);
      RefreshRates();
      str.ticket=OrderSend(
                           str.symbol,
                           str.type,
                           str.lots,
                           str.price,
                           str.slippage,
                           str.stoploss,
                           str.takeprofit,
                           str.comment,
                           str.magic,
                           str.expiration,
                           str.arcolor );
      if(str.ticket<0)
         Sleep(500);
      else
         break;
     }

   if(str.ticket>=0)
     {
      str.rezult=true;
      str.error=GetLastError();
      return true;
     }
   else
     {
      str.rezult=false;
      str.error=GetLastError();
      return false;
     }
   return false;
  }
//+------------------------------------------------------------------+

Вызов в советнике

   Order.magic=227;
   Order.type=OP_BUY;
   Order.lots=0.01;
   Order.slippage=30;
   Order.stoploss=0;
   Order.takeprofit=0;
   Order.comment="Привет";
   Order.arcolor=clrRed;
   
   if(Order.F_Send(Order)==true)
   Print("Open Type ",Order.type," Lot ",Order.lots," Slip ",Order.slippage," SL ",Order.stoploss," TP ",Order.takeprofit,"Comment ",Order.comment);
   else
   Print("Open Erorr N", Order.error ," Type ",Order.type," Lot ",Order.lots," Slip ",Order.slippage," SL ",Order.stoploss," TP ",Order.takeprofit,"Comment ",Order.comment);

Пинайте ......

 

Пару своих лепт:

1)

class CTrade : public CObject
  {
    //--- bla-bla-bla

  }


2) Потом, имхо, стоит придумать свою версию класса СSymbolInfo, чтобы избежать:

SymbolInfoDouble ()
SymbolInfoInteger()

 По аналогии с MQL5 придётся создавать свои классы СOrderInfo, CHistoryOrderInfo.

Видать, что у MQ не дошли руки до торговых классов Стандартной библиотеки...


3) Члены-данные называл бы с префикcа m_

Описание членов-переменных хде?

 
denkir:

Пару своих лепт:

1)


2) Потом, имхо, стоит придумать свою версию класса СSymbolInfo, чтобы избежать:

 По аналогии с MQL5 придётся создавать свои классы СOrderInfo, CHistoryOrderInfo.

Видать у MQ не дошли руки до торговых классов Стандартной библиотеки...


3) Члены-данные называл бы с префикcа m_

Описание членов-переменных хде?

1 не понятно зачем тулить CObject

2 что значит описание , можно больше инфы ?

 
VOLDEMAR:

1 не понятно зачем тулить CObject

ООП. Чтим, ну или не чтим традиции языка :-)

2 что значит описание , можно больше инфы ?

Что означает член-данные. Хотя многое понятно, но всё же...

 
class Trade
  {
private:
   MqlTick           tick; //ЗАЧЕМ ЭТОТ ТИК ЕСЛИ ЕГО ДОСТАТОЧНО ОБЪЯВИТЬ В МЕТОДЕ?
public: //УБРАТЬ ПОЛЯ В ЗОНУ PRIVATE
//ЗАЧЕМ ВСЕ ЭТИ ПОЛЯ, ЕСЛИ ОНИ НЕ ИСПОЛЬЗУЮТСЯ В МЕТОДАХ?
   string            symbol;
   int               type;
   int               error;
   double            lots;
   double            price;
   int               slippage;
   double            stoploss;
   double            takeprofit;
   string            comment;
   int               magic;
   datetime          expiration;
   color             arcolor;
   int               ticket;
   bool              rezult;
   int               digits;
   double            point;
   double            breakeven;
   double            breakstep;
   double            trailing;
   double            trailstep;

   bool              F_Send(Trade  &str);//ПЕРЕИМЕНОВАТЬ. НАПРИМЕР НА ORDERSEND
                     Trade(); //ЗАЧЕМ ПИСАТЬ ПУСТЫЕ КОНСТРУКТОР И ДИСТРУКТОР?
                    ~Trade(); //УДАЛИТЬ.
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Trade ::  Trade(){  }
Trade :: ~Trade(){  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Trade :: F_Send(Trade  &str)
  {
   ResetLastError();
   if(str.symbol==NULL || str.symbol=="")str.symbol=_Symbol;
   if(str.magic==NULL)str.magic=0;
   if(str.comment==NULL || str.comment=="")str.comment=StringConcatenate(WindowExpertName()," ",str.magic);

   int p=0;
   str.digits=(int)SymbolInfoInteger(str.symbol,SYMBOL_DIGITS);
   str.point =SymbolInfoDouble (str.symbol,SYMBOL_POINT);

   if(str.lots<SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN);
   if(str.lots>SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX);

   while(!IsTradeContextBusy() && p++<5)//НАСКОЛЬКО ПОМНЮ, ContextBusy НЕ АКТУАЛЕН В ПОСЛЕДНИХ ВЕРСИЯХ MQL4
     {
      if(!SymbolInfoTick(str.symbol,tick))
      Print("SymbolInfoTick() failed, error = ",GetLastError());
      if(str.type==OP_BUY ) str.price=NormalizeDouble(tick.ask,str.digits); //НОРМАЛИЗАЦИЯ НУЖНА В НЕЗАВИСИМОСТИ ОТ ТИПА ОРДЕРА.
      if(str.type==OP_SELL) str.price=NormalizeDouble(tick.bid,str.digits);
      RefreshRates();//ВЫЗВАТЬ ДО ПОЛУЧЕНИЯ if(!SymbolInfoTick(str.symbol,tick))
      str.ticket=OrderSend(
                           str.symbol,
                           str.type,
                           str.lots,
                           str.price,
                           str.slippage,
                           str.stoploss,
                           str.takeprofit,
                           str.comment,
                           str.magic,
                           str.expiration,
                           str.arcolor );
      if(str.ticket<0)
         Sleep(500);
      else
         break;
     }

   if(str.ticket>=0)
     {
      str.rezult=true;
      str.error=GetLastError();
      return true;
     }
   else
     {
      str.rezult=false;
      str.error=GetLastError();
      return false;
     }
   return false;
  }
//+------------------------------------------------------------------+
 

После этого

if(!SymbolInfoTick(str.symbol,tick))
      Print("SymbolInfoTick() failed, error = ",GetLastError());

Нужно наверное или return или continue. Иначе зачем эта проверка?

 

VOLDEMAR:

Код не претендует на идеал по этому давайте сообща сделаем его луще!

Чтобы что-то улучшать, нужно понять, какая идея заложена в класс? Разработка класса и проектирование... вот чем нужно сначала заняться...

Или Вы хотите сделать аналог CTrade в MQL5?

 

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

+

цены SL и TP тоже было бы неплохо нормализовать.


+ Добавить проверку на разрешение советнику торговать и автоторговлю в терминале. Если эти проверки не сделаны раньше.

+ Проверку на TerminalConnected на случай если вызов идет не из OnTick() а например из OnTimer().

+ Проверка уровней SL & TP на соответствие ограничениям брокера и положению относительно текущей цены.

+ Проверить/Нормализовать запрашиваемый объем позиции (в соотв с VOLUME_STEP)

+ Проверить достаточность маржи

 

Вот накатал

bool Trade :: SendOrder(Trade  &str)
  {
   ResetLastError();
//--------------- Проверка на разрешение советнику торговать --------------//
   int p=0,c=0;string txt=NULL;
   bool Lan=(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian");
// Разрешение на торговлю кнопка в терминале   
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      c++;
      if(Lan)txt=(string)c+"-Отключена кнопка Авто-Торговля    ";
      else txt=(string)c+"-Disable button Auto-Trading    ";
     }
// Свойства терминала     
   if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
     {
      c++;
      if(Lan)txt=txt+(string)c+"-В настройках терминала включите \"Разрешить автоматическую торговлю\", запустите советник в термнале";
      else txt=txt+(string)c+"-In the terminal settings include \"Allow automated trading \", run counselor in termnale";
     }
// Наличие связи с стервером брокера  
   if(!IsConnected())
     {
      c++;
      if(Lan)txt=txt+(string)c+"-Отсутсвует связь с интернетом / сервером брокера";
      else txt=txt+(string)c+"-Not available Internet connection / server broker";
     }
// алерт с инструкциями
   if(txt!=NULL)
     {
      Alert(txt);
      return false;
     }
//-------------------------------------------------------------------------//
//----------------------------- Неучтенка ---------------------------------//
   if(str.symbol==NULL || str.symbol=="")str.symbol=_Symbol;
   if(str.magic==NULL)str.magic=0;
   if(str.comment==NULL || str.comment=="")str.comment=StringConcatenate(WindowExpertName()," ",str.magic);
   str.digits=(int)SymbolInfoInteger(str.symbol,SYMBOL_DIGITS);
   str.point =SymbolInfoDouble (str.symbol,SYMBOL_POINT);
   m_fl=NormalizeDouble(SymbolInfoInteger(str.symbol,SYMBOL_TRADE_FREEZE_LEVEL)*str.point,str.digits);
//-------------------------------------------------------------------------//
//------------------ Проверка и нормализация лота--------------------------//
   if(str.lots<SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MIN);
   if(str.lots>SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX))str.lots =SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_MAX);
   if(MarketInfo(str.symbol,MODE_MARGINREQUIRED)*str.lots>AccountEquity())  //  ПО НОВОМУ НЕ НАШОЛ
     {
      str.comment="Not enough money to open a position";
      str.error=GetLastError();
      return false;
     }
   if(SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_STEP)==0.001) str.lots=NormalizeDouble(str.lots,3);
   if(SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_STEP)==0.01) str.lots=NormalizeDouble(str.lots,2);
   if(SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_STEP)==0.1) str.lots=NormalizeDouble(str.lots,1);
   if(SymbolInfoDouble (str.symbol,SYMBOL_VOLUME_STEP)==1) str.lots=NormalizeDouble(str.lots,0);
//-------------------------------------------------------------------------//
//------------------ запускаем цикл на 5 попыток --------------------------//
   while(!IsTradeContextBusy() && p++<5)
     {
      RefreshRates();
      // Обновим данные на каждой интерации
      if(!SymbolInfoTick(str.symbol,tick))
        {
         Print("SymbolInfoTick() failed, error = ",GetLastError());
         str.error=GetLastError();
         return false;
        }
      if(str.type==OP_BUY)
        {
         if(str.takeprofit>0)
           {
            str.takeprofit=NormalizeDouble(tick.ask+str.takeprofit*str.point,str.digits);
            if((str.takeprofit-m_fl)<=tick.ask)
              {
               str.comment="Error open buy TP freeze level";
               str.error=GetLastError();
               return false;
              }
           }
         if(str.stoploss>0)
           {
            str.stoploss=NormalizeDouble(tick.ask-str.stoploss  *str.point,str.digits);
            if((str.stoploss+m_fl)>=tick.ask)
              {
               str.comment="Error open buy SL freeze level";
               str.error=GetLastError();
               return false;
              }
           }
         str.price=NormalizeDouble(tick.ask,str.digits);
        }
      if(str.type==OP_SELL)
        {
         if(str.takeprofit>0)
           {
            str.takeprofit=NormalizeDouble(tick.bid-str.takeprofit*str.point,str.digits);
            if((str.takeprofit+m_fl)<=tick.bid)
              {
               str.comment="Error open sell TP freeze level";
               str.error=GetLastError();
               return false;
              }
           }
         if(str.stoploss>0)
           {
            str.stoploss=NormalizeDouble(tick.bid+str.stoploss  *str.point,str.digits);
            if((str.stoploss-m_fl)<=tick.bid)
              {
               str.comment="Error open sell SL freeze level";
               str.error=GetLastError();
               return false;
              }
           }
         str.price=NormalizeDouble(tick.bid,str.digits);
        }

      str.ticket=OrderSend(
                           str.symbol,
                           str.type,
                           str.lots,
                           str.price,
                           str.slippage,
                           str.stoploss,
                           str.takeprofit,
                           str.comment,
                           str.magic,
                           str.expiration,
                           str.arcolor );
      if(str.ticket<0)
         Sleep(500);
      else
         break;
     }

   if(str.ticket>=0)
     {
      str.rezult=true;
      str.Get_price=str.price;
      str.error=GetLastError();
      return true;
     }
   else
     {
      str.rezult=false;
      str.error=GetLastError();
      return false;
     }
   return false;
  }
 
   str.digits
   str.point

Думаю можно перенести в private

 

Нафига в параметры засовывать чужой объект (ну или свой)?

bool Trade :: SendOrder(Trade  &str)

Имхо, лучше создать для всех торговых параметров структуру что-то типа:

//+------------------------------------------------------------------+
//| Структура базовых торговых элементов                             |
//+------------------------------------------------------------------+
struct STradeElements
  {
   double            lot;             // лот
   uint              stop_loss;       // стоплосс,пп
   uint              take_profit;     // профит,пп
   uint              trailing_stop;   // трал,пп
   uint              slippage;        // проскальзывание,пп
   uint              pause;           // торговая пауза,мс
   uint              attempts;        // торговых попыток
   string            symbol;          // инструмент
  }

и её потом принимать:

bool Trade :: SendOrder(const STradeElements &_tradeStr)

А лучше сделать перегрузку методов.

Для своих торговых параметров так:

bool Trade :: SendOrder(void)

Тогда до этого нужно будет параметры проинициализировать...