Discussion of article "Library for easy and quick development of MetaTrader programs (part XXVI): Working with pending trading requests - first implementation (opening positions)"

 

New article Library for easy and quick development of MetaTrader programs (part XXVI): Working with pending trading requests - first implementation (opening positions) has been published:

In this article, we are going to store some data in the value of the orders and positions magic number and start the implementation of pending requests. To check the concept, let's create the first test pending request for opening market positions when receiving a server error requiring waiting and sending a repeated request.

Compile and launch the EA. Turn off the Internet and wait till the following image appears in the lower right corner of the terminal:



After disabling the Internet and clicking Sell, the trade server returns the error and the following entries are displayed in the journal:

2019.11.26 15:34:48.661 CTrading::OpenPosition<uint,uint>: Invalid request:
2019.11.26 15:34:48.661 No connection with the trade server
2019.11.26 15:34:48.661 Correction of trade request parameters ...
2019.11.26 15:34:48.661 Trading attempt #1. Error: No connection with the trade server

After receiving the error, the library creates a pending request with the parameters set during the unsuccessful attempt to open a short position.
The pending request also features the number of attempts and the waiting time of 20 seconds.

Then enable the Internet to restore the connection to the trade server:


As soon as the connection is restored, the library starts handling a pending request sending it to the server. As a result, we have an open position with journal entries:

2019.11.26 15:35:00.853 CTrading::OpenPosition<double,double>: Invalid request:
2019.11.26 15:35:00.853 Trading is prohibited for the current account
2019.11.26 15:35:00.853 Correction of trade request parameters ...
2019.11.26 15:35:00.853 Trading operation aborted
2019.11.26 15:35:01.192 CTrading::OpenPosition<double,double>: Invalid request:
2019.11.26 15:35:01.192 Trading is prohibited for the current account
2019.11.26 15:35:01.192 Correction of trade request parameters ...
2019.11.26 15:35:01.192 Trading operation aborted
2019.11.26 15:35:01.942 - Position is open: 2019.11.26 10:35:01.660 -
2019.11.26 15:35:01.942 EURUSD Opened 0.10 Sell #486405595 [0.10 Market-order Sell #486405595] at price 1.10126, sl 1.10285, tp 1.09985, Magic number 17629307 (123), G1: 13
2019.11.26 15:35:01.942 OnDoEasyEvent: Position is open

As we can see, after restoring the connection to the trade server, trading for the current account was enabled with a delay.
But the pending request did the trick anyway
...

Also, we can see the real magic number 17629307 in the journal followed by the magic number defined in the EA settings in brackets (123) plus another entry G1: 13 informing that the first group ID is equal to 13, while the second group ID is absent — its value turned out to be equal to zero, therefore there was no second entry with the G2: XX second group ID.

Author: Artyom Trishkin

 
Hello! I downloaded the latest version of the library and Expert Part_26, put the visual mode on the tester and market orders are opened, but all pending orders are not.

orders are opened, but all pending orders are not.

Exchange symbols, broker Otkritie, version 5.00 build 2190.

 
Alexander:
Hello! I downloaded the latest version of the library and Expert Part_26, put the visual mode and market mode on the tester.

orders are opened, but all pending orders are not.

Exchange symbols, broker Otkritie, version 5.00 build 2190.

Forum on trading, automated trading systems and testing trading strategies

Discussion of the article "Library for easy and fast creation of programmes for MetaTrader (Part XXV): Handling errors returned by the trading server"

Artyom Trishkin, 2019.11.28 09:39

In this version of the library, as well as in the next one, I missed checking order fill types and order expiry types. There will be corrections in the next (27) article.

For now, I can suggest to explicitly specify the expiry type when sending a trade request. For example, to place a Sell Limit pending order, you need to add it in the test Expert Advisor:

//--- If the BUTT_SELL_LIMIT button is pressed: Set SellLimit
else if(button==EnumToString(BUTT_SELL_LIMIT))
  {
   //--- Set SellLimit order
   engine.PlaceSellLimit(lot,Symbol(),distance_pending,stoploss,takeprofit,magic,TextByLanguage("Pending SellLimit","Pending order SellLimit"),0,ORDER_TIME_DAY);
  }

And do the same in all lines that contain the call of methods for setting pending orders.


 
Yes, thank you, that's how it works.
 
//--- Data location in the magic numberber int value
      //-----------------------------------------------------------
      //  bit   32|31       24|23       16|15        8|7         0|
      //-----------------------------------------------------------
      //  byte    |     3     |     2     |     1     |     0     |
      //-----------------------------------------------------------
      //  data    |   uchar   |   uchar   |         ushort        |
      //-----------------------------------------------------------
      //  descr   |pend req id| id2 | id1 |          magic        |
      //-----------------------------------------------------------      
//--- Return (1) the specified magic numberber, the ID of (2) the first group, (3) second group, (4) pending request from the magic numberber value
   ushort            GetMagicID(void)                                const { return ushort(this.Magic() & 0xFFFF);                                 }
   uchar             GetGroupID1(void)                               const { return uchar(this.Magic()>>16) & 0x0F;                                }
   uchar             GetGroupID2(void)                               const { return uchar((this.Magic()>>16) & 0xF0)>>4;                           }
   uchar             GetPendReqID(void)                              const { return uchar(this.Magic()>>24) & 0xFF;                                }

There exists a convenient function for extracting bits from a number.

//--- extract cnt bits at the kth bit position
   uint              _getBits(const uint number,uint pos,uint cnt=1) const { return (number >> pos) & ((1 << cnt) - 1);                            }
      
   ushort            GetMagicID(void)                                const { return ushort(_getBits(this.Magic(),0,16));                           }
   uchar             GetGroupID1(void)                               const { return uchar(_getBits(this.Magic(),16,4));                            }
   uchar             GetGroupID2(void)                               const { return uchar(_getBits(this.Magic(),20,4));                            }
   uchar             GetPendReqID(void)                              const { return uchar(_getBits(this.Magic(),24,8));                            }
 
amrali:

There exists a convenient function for extracting bits from a number.

Thanks
 
Is there an implementation in the library to open an immediate market execution?
 
iabbott:
Is there an implementation in the library to open an immediate market execution?
Yes
 

Could you tell me, please, where exactly, in what method, do you decode the encoded magic in the pending request?

After an error when opening a position(insufficient funds) and then triggering a pending request, I have a position created with a completely different magic (apparently, the one encoded).

Where do you decode it? I want a native majik, not a new one.

 
void CTradingControl::OnPReqByErrCodeHandler()

This is where you're supposed to call the method that returns the original magick. And what method is that? GetMagicID()?

 
//+------------------------------------------------------------------+
//| Returns the order's profit in pips|
//+------------------------------------------------------------------+
int COrder::ProfitInPoints(void) const
  {
   MqlTick tick={0};
   string symbol=this.Symbol();
   if(!::SymbolInfoTick(symbol,tick))
      return 0;
   ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)this.TypeOrder();
   double point=::SymbolInfoDouble(symbol,SYMBOL_POINT);
   if(type==ORDER_TYPE_CLOSE_BY || point==0) return 0;
   if(this.Status()==ORDER_STATUS_HISTORY_ORDER)
      return int(type==ORDER_TYPE_BUY ? (this.PriceClose()-this.PriceOpen())/point : type==ORDER_TYPE_SELL ? (this.PriceOpen()-this.PriceClose())/point : 0);
   else if(this.Status()==ORDER_STATUS_MARKET_POSITION)
     {
      if(type==ORDER_TYPE_BUY)
         return int((tick.bid-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL)
         return int((this.PriceOpen()-tick.ask)/point);
     }
   else if(this.Status()==ORDER_STATUS_MARKET_PENDING)
     {
      if(type==ORDER_TYPE_BUY_LIMIT || type==ORDER_TYPE_BUY_STOP || type==ORDER_TYPE_BUY_STOP_LIMIT)
         return (int)fabs((tick.bid-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL_LIMIT || type==ORDER_TYPE_SELL_STOP || type==ORDER_TYPE_SELL_STOP_LIMIT)
         return (int)fabs((this.PriceOpen()-tick.ask)/point);
     }
   return 0;
  }

Why is there no calculation here for ORDER_STATUS_DEAL type ?

In general, it is not clear how to get the profit in points of a closed trade or position...
And it is always 0:

deal_profit_pts=(int)deal.GetProperty(ORDER_PROP_PROFIT_PT)