Limit Pair To 1 Open Order

 

This code works in back testing and most of the time forward testing but every now and then an extra trade will still be placed on the currency pair despite the check in the code below that SHOULD be preventing this. Trades do have different magic number but I do NOT reference them here as I only want 1 trade per pair so I was assuming the orders symbol check would achieve this (limit one order on the pair), am I missing something?

void IfOrderDoesNotExistBuy()
{
    bool exists = false;
    for (int i=OrdersTotal()-1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
        if (OrderSymbol() == Symbol())
        {
            exists = true;
        }
    }
    else
    {
        Print("OrderSelect() error - ", ErrorDescription(GetLastError()));
    }
    
    if (exists == false)
    {
        BuyOrderType();
        
    }
}
 
if(openorder!=1)opentradecommand;
 
gangsta1:

This code works in back testing and most of the time forward testing but every now and then an extra trade will still be placed on the currency pair despite the check in the code below that SHOULD be preventing this. Trades do have different magic number but I do NOT reference them here as I only want 1 trade per pair so I was assuming the orders symbol check would achieve this (limit one order on the pair), am I missing something?

Are you running several EA on the same pair ?
 

No, just the one EA with several different entry criteria, all checking for an open order on the pair using the code above. Another solution I had was:

void LimitOpenOrdersBuy()
{
    int count = 0;
    for (int i=OrdersTotal()-1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
        if (OrderSymbol() == Symbol())
        {
            count++;
        }
    }
    else
    {
        Print("OrderSend() error - ", ErrorDescription(GetLastError()));
    }
    if (count < OpenOrdersLimit)
    {
            BuyOrderType();
    }
}
 
It can be that in case there is a kind of reconnection(?) OrdersTotal() will give you 0 is not yet set correctly - just my guess.
 
gangsta1: check in the code below that SHOULD be preventing this.  am I missing something?

It should work, except you have a race condition. EA1 checks total finds it zero, EA2 checks total finds it zero. Both EAs open an order.

You need a mutex around the check and open.

Not compiled, not tested.
input string         GV_Mutex                   = "Mutex";
//+------------------------------------------------------------------+
//| Trade context semaphore.                                         |
//+------------------------------------------------------------------+
class Mutex{
 Public:
   void                 Mutex()                     : mName(GV_Mutex),
                                                      mLocked(false){   Lock();}
   void                 Mutex(const string& aName)  : mName(aName),
                                                      mLocked(false){   Lock();}
   void                ~Mutex(){                                     Release();}
   void                 Lock(void){
      if(mLocked) return
      int      startWaitingTime  = 0;
      if(!GlobalVariableTemp(mName){                     // Attempt to create
      && _LastError != ERR_GLOBAL_VARIABLES_PROCESSING)  DisableTrading(
         StringFormat("Mutex: GVSet('%s') Failed: %i",s, _LastError) ); return;}
      while(true){
         if(!IsTradeContextBusy()
         && GlobalVariableSetOnCondition(mName, 0, 1) ){
            if(startWaitingTime != 0){
               Comment(WindowExpertName(),": ", VERSION);   WindowRedraw();
               SetNeedToRefresh();  // I slept
            }
            RefreshIf();   // RefreshRates if slept or previous OrderSend/Modify
            SetNeedToRefresh();     // Assume will do a OrderSend/Modify/Close.
            mLocked = true;
            return;
         }
         if(IsStopped() ){
            Alert("Mutex: The expert was terminated by the user!");  return;  }
         if(startWaitingTime == 0)
            startWaitingTime  = GetTickCount(); // Remember start time.
         else{
            int   delay = GetTickCount() - startWaitingTime;
   #define MUTEX_TIMEOUT_MSEC    60000 // Trade context busy maximum delay
            if(delay > MUTEX_TIMEOUT_MSEC){              // Abort.
               DisableTrading(StringFormat("Wait time (%i sec) exceeded!",
                              MUTEX_TIMEOUT_MSEC / 1000) ); return;
            }
            Comment(WindowExpertName(), ": ",
            "Wait until another expert finishes trading... ", delay / 1000.);
            WindowRedraw();
         }
         Sleep(1000);
      }  // while
      //NOT REACHED
   }  // Lock
   void                 Release(void){
      if(mLocked){
         if(!GlobalVariableSet(mName, 0) )
            Alert("Mutex: GlobalVariableSet('%s',!LOCK): Error #",
                  mName, _LastError);
         mLocked=false;
      }
   }
   void                 IsLocked(void)             const{return mLocked;    }
 Private:
   string               mName;
   bool                 mLocked;
}; // Mutex
void            DisableTrading(string msg){
        string tradingDisabled = msg+" Trading disabled.";
        CloseAllOrders();               Alert(tradingDisabled);         Comment(tradingDisabled);
        ExpertRemove();
}
////////////////////////////////////
{
  Mutex m;
  IfOrderDoesNotExistBuy();
}
Not compiled, not tested.
 
Thank you although from my experience I understand that a MUTEX is required if the trades are open at the EXACT same time. I had a trade today on a pair that already had an open trade from a few days ago despite using the Limit Open Orders code in my second post. It is very frustrating as to me that code is clearly checking the symbol pair for an existing trade and should therefore NOT allow another trade to be open. The only thing I can think of is that I need to include a condition to check order magic number also.
 
gooly:
It can be that in case there is a kind of reconnection(?) OrdersTotal() will give you 0 is not yet set correctly - just my guess.
Thanks Gooly. Do you mean that if mt4 disconnects and reconnects that the orders total can be reset? I would have thought that when the EA goes through the limit open orders check again it would still find an open order.
 
gangsta1: Thank you although from my experience I understand that a MUTEX is required if the trades are open at the EXACT same time.
There is no EXACT over a network. Both EAs will start at the EXACT same time because a new tick was received. Both server requests will be sent milliseconds apart. It can take tens of seconds to open an order on the server (minutes during news.)  The reply and update to total will be seconds later when the tickets are returned.
gangsta1:  Do you mean that if mt4 disconnects and reconnects that the orders total can be reset?
I doubt that. What ever it has locally is still there and would eventually be updated on reconnect. Network timeout (a disconnect) takes a minute before the terminal  even knows.
 

I guess (!) that if you hear disconnect and reconnect (in case you have enabled theses sound events) mt4 knows about it.

And I know that if in case the terminal (re-) loads its server information it takes a while despite OnTick() starts and might create wrong results - that why I return as long e.g. OrdersHistoryTotal() is still 0:

...
void OnTick(){
   ...
   if (!isInit) {
      if ( OrdersHistoryTotal()==0 ) return;
      isInit = true;
   }
   ...

But as I don't know anything about mt4's server it's only guessing than knowing :(


Another problem is that I don't know much about what is changed and not changed in case you just recompile your EA!

The 'extern-' ('input-') variables stay the same even though you might have changed them in the EA-mq4 files, but what about the static, global variables, and ...

 
Thank you all very much for taking the time to reply and help out. I did in fact recompile my EA after the initial trade on the pair was opened so I believe that may have been what allowed another trade to be opened on that pair. Or, I may be wrong. I will follow trading closely and see if this occurs again (more than 1 order per pair) and then attempt to implement the suggestions made.