My EA does a double entry - page 7

To add comments, please log in or register
Dua Yong Rew
5747
Dua Yong Rew  

if I use sleep, I will lose ticks?

what will be the consequences? can share with me?

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
Alain Verleyen
40780
Alain Verleyen  
doshur:

if I use sleep, I will lose ticks?

what will be the consequences? can share with me?

It depends of your strategy. As this issue about "double trades" can only occur when your trading code is executed on each tick, you probably have a strategy which depends on tick. So it's up to you to evaluate what can be the consequence if you loss the ticks that arrives during your delay (sleep).

Dua Yong Rew
5747
Dua Yong Rew  
angevoyageur:

It depends of your strategy. As this issue about "double trades" can only occur when your trading code is executed on each tick, you probably have a strategy which depends on tick. So it's up to you to evaluate what can be the consequence if you loss the ticks that arrives during your delay (sleep).

So if I sleep for 800

means I lose ticks for the next 800ms? After I enter my trade, my EA does nothing, only sits there till TP or SL or wait for time to exit.

So my strategy is ok if I use sleep?

does calling refreshrates() get back the ticks? 

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
Rogerio Figurelli
Moderator
59010
Rogerio Figurelli  
doshur:

So if I sleep for 800

means I lose ticks for the next 800ms? After I enter my trade, my EA does nothing, only sits there till TP or SL or wait for time to exit.

So my strategy is ok if I use sleep?

does calling refreshrates() get back the ticks? 

doshur, ticks you loose, you loose, there is no wayback machine. 

Regarding documentation at https://www.mql5.com/en/docs/common/sleep the function suspends execution of the current Expert Advisor or script within a specified interval.

So, even OnTimer events will be suspended, probably because the EA uses just one thread.

So, use a fixed Sleep is not a definitive solution, is just "numerology", i.e., a workaround if the delay is lower than your value.

And this why I propose a loop testing PositionSelect after open the trade, to double check the PositionOpen execution and return as a better workaround than just Sleep(), and that also comprove the cause of the problem (according angevoyageur tests).

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
Dua Yong Rew
5747
Dua Yong Rew  

This is what I'm using now. Where should I code the workaround provided by figurelli in a more elegant way

 

//
         {
            Price = SymbolInfoDouble(Symbol(), SYMBOL_ASK);

            if(m_Trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, LotSize, Price, 0, 0))
            {
               Sleep(800);

               if(m_Trade.ResultRetcode() == 10009)
               {
                  Print("Position opened in ", Symbol());

                  return;
               }
               else
               {
                  Print("Error opening position in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
               }
            }
            else
            {
               Print("Error with PositionOpen in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
            }
         }
Rodrigo Malacarne
Moderator
8115
Rodrigo Malacarne  
doshur:

This is what I'm using now. Where should I code the workaround provided by figurelli in a more elegant way

 

Hello doshur, I was also having problems with double entries in one of my EA's. Actually, these problems were ocurring only when I was trading highly liquid assets. Even after setting orders to be sent in asynchronous mode, the EA was "apparently" waiting too long for a server response to update PositionsTotal()... meanwhile, other incoming ticks were triggering the conditions to send a second order... in the Portuguese forum I posted a workaround, which I would like to share here.

The idea is simple:

//--- global variables
CTrade trade;
bool position_opened=false;

//--- inside OnTick()
if( conditions to open && position_opened==false )
  {
   //--- set the global variable to true to avoid duplicate orders
   position_opened=true;
   trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment");
  }

 The only problem with this code is the case where the order is not accepted by the server, so you need to "reset" the global variable... You could use this:

MqlTradeResult mresult;

//--- 
if(mresult.retcode==10009 || mresult.retcode==10008)
  {Print("Success!");}
else 
  {
   Print("Error = ",GetLastError());
   ResetLastError();
   //--- Sets the global variable to false
   position_opened=false;
   return;
  }

 So, in the case the first order sent returns an error, the global variable will be set to false so the EA could send another order. However, I have to say that I tested this code only in stocks and futures, but not in forex market... :-(

Dua Yong Rew
5747
Dua Yong Rew  
Malacarne:

Hello doshur, I was also having problems with double entries in one of my EA's. Actually, these problems were ocurring only when I was trading highly liquid assets. Even after setting orders to be sent in asynchronous mode, the EA was "apparently" waiting too long for a server response to update PositionsTotal()... meanwhile, other incoming ticks were triggering the conditions to send a second order... in the Portuguese forum I posted a workaround, which I would like to share here.

The idea is simple:

 The only problem with this code is the case where the order is not accepted by the server, so you need to "reset" the global variable... You could use this:

 So, in the case the first order sent returns an error, the global variable will be set to false so the EA could send another order. However, I have to say that I tested this code only in stocks and futures, but not in forex market... :-(

This seems viable. Let's see if figurelli and angevoyageur has any comments on this workaround...
Rogerio Figurelli
Moderator
59010
Rogerio Figurelli  
doshur:
This seems viable. Let's see if figurelli and angevoyageur has any comments on this workaround...

This solution proposed by Malacarne (with some adjustments I will propose) is great, since for me is not a workaround (as Malacarne modestly refers), but one elegant and right way to address this question.

In my opinion, the original problem of double entry is not a MT5 bug, but a coding bug, since the help states:

"Successful completion of the PositionOpen(...) method does not always mean successful execution of the trade operation. It's necessary to check the result of trade request (trade server return code) using ResultRetcode() and value, returned by ResultDeal()."

So, I suggest some little changes to be more resilient to any market condition:

1) Test PostionOpen() return too, as the original code, for instance:

if (trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")) position_opened=true;

2) A more complete treatment of ResultRetcode(), since you can have other relevant postion opened, like 10010 - TRADE_RETCODE_DONE_PARTIAL - Only part of the request was completed. Also, 10008 - TRADE_RETCODE_PLACED - Order placed is not Success for me, just 10009 - TRADE_RETCODE_DONE - Request completed, and this are asynchronous messages, so the second part of Malacarne code could consider this and/or deal ticket, after deal is executed, too.

Anyway, looks like for me that we are on the right way and final cut now.

Alain Verleyen
40780
Alain Verleyen  
Malacarne:

Hello doshur, I was also having problems with double entries in one of my EA's. Actually, these problems were ocurring only when I was trading highly liquid assets. Even after setting orders to be sent in asynchronous mode, the EA was "apparently" waiting too long for a server response to update PositionsTotal()... meanwhile, other incoming ticks were triggering the conditions to send a second order... in the Portuguese forum I posted a workaround, which I would like to share here.

The idea is simple:

 The only problem with this code is the case where the order is not accepted by the server, so you need to "reset" the global variable... You could use this:

 So, in the case the first order sent returns an error, the global variable will be set to false so the EA could send another order. However, I have to say that I tested this code only in stocks and futures, but not in forex market... :-(

It's a valid approach, however you have to reset your global variable position_opened to false when your position is closed. Where are you doing that ?

About your implementation, some details :

  1. There is no need to set position_opened to true and then to false if there is an error.
  2. You are using an object of the CTrade class, so no need to use a new MqlTradeResult structure.
  3. As figurelli noted in his post, you have to check the returned value of PositionOpen.
  4. The name of the class is CTrade, not Ctrade. mql5 is case sensitive.
  5. position_opened is a bool, not need to compare it to false. If you do it, you have to use '==' and not '='.

So, here is the modified code (Compiled but not tested) :

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//--- global variables
CTrade trade;
bool position_opened=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool conditions_to_open;
   ENUM_ORDER_TYPE order_type;
   double lot;
   double price,sl,tp;

//---...set variables

//--- inside OnTick()
   if(conditions_to_open && !position_opened) //-- Or position_opened==false
     {
      if(trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")
         && 
         (trade.ResultRetcode()==10009 || trade.ResultRetcode()==10008)) //-- Or others condition according to your needs
        {
         //--- set the global variable to true to avoid duplicate orders
         position_opened=true;
         Print("Success!");
        }
      else
        {
         Print("Error = ",GetLastError(), "trade error = ", trade.ResultRetcode());
         //--- Sets the global variable to false
         // position_opened=false;                                         //-- Not needed as position_opened is already false
         return;
        }

     }
//--- 
  }
//+------------------------------------------------------------------+
Alain Verleyen
40780
Alain Verleyen  
figurelli:

...

In my opinion, the original problem of double entry is not a MT5 bug, but a coding bug, since the help states:

"Successful completion of the PositionOpen(...) method does not always mean successful execution of the trade operation. It's necessary to check the result of trade request (trade server return code) using ResultRetcode() and value, returned by ResultDeal()."

I don't think it's related to the issue of this topic. The issue we get is in case of a request was filled successfully and a position is opened. But this position is opened on the trade server, the problem we encountered is when there is a delay more important as usual and the MT5 terminal is notified of this new position AFTER a new tick is already processed.

It's not a bug, as it's designed this way. BUT in my opinion it's a poor designed for a platform who allow explicitly synchronous and asynchronous trading requests. We are talking here about an request which is supposed to be synchronous, but in fact it's not really synchronous as when you get the reply from the server for the request (trade.ResultRetCode in the code above) we still have to wait for the MT5 platform to be informed and updated about the trading results. (I understood all of that with this thread).

So, I suggest some little changes to be more resilient to any market condition:

1) Test PostionOpen() return too, as the original code, for instance:

2) A more complete treatment of ResultRetcode(), since you can have other relevant postion opened, like 10010 - TRADE_RETCODE_DONE_PARTIAL - Only part of the request was completed. Also, 10008 - TRADE_RETCODE_PLACED - Order placed is not Success for me, just 10009 - TRADE_RETCODE_DONE - Request completed, and this are asynchronous messages, so the second part of Malacarne code could consider this and/or deal ticket, after deal is executed, too.

Anyway, looks like for me that we are on the right way and final cut now.

Of course, you are absolutely right that one have to check the returned value of PositionOpen AND the returned code of the trade result. However the ResultRetCode is synchronous, it's the updated of the MT5 database about position (deal and order) who is asynchronous. The test I made with your proposition demonstrated this, as I use of course a code who checked the returned value of the trade request.
To add comments, please log in or register