Push, pull and when not to hammer your broker

 

I can't imagine people not asking this question before, but I couldn't find the answer on this forum. I recently started programming in MQL4, after having experience in other languages.

From the documentation I gather that your broker pushes price information to the terminal buffer. When the start() function is called, that price data is copied to a buffer specifically for that start() function. But what happens if the RefreshRates() function is called? Does that copy the new price information from the terminal buffer to the function buffer, or does it send a request to the broker for the new price information (pull)?

And does the same principle apply to order information? Is the order history also stored in the terminal buffer? Or does your EA send a request to the broker everytime you use order attributes?

The reason for asking is that I don't want to hammer my broker with unnecessary requests and pissing him off in the process. It's bad enough I might have to update a stoploss on every tick.

 
no, this won't send requests to the broker. It will only update the automatic variables like Bid and Ask and buffers, etc. with the new data that *might* have been pushed by the broker in the meantime.
 

Thanks for the info :-)

 

The way I understand it:

The broker broadcast the ticks. Ticks can be lost in Cyberspace. The Tick-Count is the same as the Volume-Count. Hence, you can miss the if( Volume[0]==1 ).

The start() is called when your platform receives this broadcast. The price information is then stored in what's called pre-defined variables and not-Buffers. I cannot call the Ask[7] for example.

RefreshRates() requests the information from the broker and updates the Pre-Defined variables. This seem to me the case because you can run Scripts and even EAs which does not Return from the Start function and gets stuck in a Endless While Loop. This type of script Sleeps for about 5-Second wakes up and has to RefershRates().

Pissing the broker-off would depend upon A) the broker and B) how often you're hammering their servers. I've read cases on this forum where a broker would disable someone for too-much-request but theses are usually smaller brokers who may-not have the hardware to support the traffic.

Example of Time-Series which have Buffers. And Pre-Defined Variables.... Here.

Added***. 7Bit has more experience and I missed his response while I was writing this.

 

I still have to get used to the fact that "buffer" in MQL means something different than the general use of the word "buffer". You're right that price information is stored in pre-defined variables and that they aren't buffers.


But what about functions like OrderSelect and OrderComment? Does the terminal have some kind of "buffer" where order information is stored, or does each function send a request to the broker?

 
burgie:

But what about functions like OrderSelect and OrderComment? Does the terminal have some kind of "buffer" where order information is stored, or does each function send a request to the broker?

The terminal is displaying stuff about your current orders regardless of whether or not an EA is there. Likewise the terminal has an OrderHistory display regardless of EA activity, so there should be no need to "ask your broker". In some cases the terminal can reject an Order without even sending it to the broker due to its own checking routines.

The journal should tell you if anything goes to the broker. I don't think OrderSelect is sent to the broker.

 

burgie:

But what about functions like OrderSelect and OrderComment? Does the terminal have some kind of "buffer" where order information is stored, or does each function send a request to the broker?

No, also these functions only return what is already stored somewhere in MetaTrader's memory. I am not entirely sure whether you need to RefreshRates() for all the order-related info too without trying it now (but my guess is: yes), so it would not hurt to call RefreshRates() whenever you are trying the same thing another time within the same execution of start(), for example after a Sleep(). For example:

while (!success){
  RefreshRates();
  stop = Ask + something;
  ticket = OrderSend(OP_SELL, ..., Bid, stop, ...);
  success = (ticket > 0);
  if (!success){
    Sleep(100);
  }
}
The only thing that is hammering the broker here would be the OrderSend() because this must by definition do something with the broker immediately. The same is true for OrderClose(), OrderModify() etc., but I have never seen the other functions that only query information produce any network traffic, they only seem to retrieve what was last pushed by the broker. RefreshRates() here will only make the Bid and Ask have the new values (they never update on their own during one execution of start without your knowledge [to avoid a whole nasty class of bugs from the realm of thread-unsafety to enter the world of programming n00bs who are already challenged by single threaded programs], they will be frozen at the beginning of start() and stay locked unless you explicitly allow them to be updated).
 
7bit:

I am not entirely sure whether you need to RefreshRates() for all the order-related info too without trying it now (but my guess is: yes), so it would not hurt to call RefreshRates() whenever you are trying the same thing another time within the same execution of start(), for example after a Sleep().

The documentation (book) is explicit about what RefreshRates does.

https://book.mql4.com/variables/predefined

 

I know some of us now use OrderClosePrice rather than Bid/Ask since it doesn't care about the order type. In an experiment to test 7 bit's ideas (above) I wrote a little test script.

//----------------------------------------------------------------------+
int deinit(){
   Comment("");
}
//----------------------------------------------------------------------+
int start(){
   // Run in a DEMO account
   int ticker = 100;
   
   int ticket= OrderSend(Symbol(),OP_BUY,0.1,Ask,10,0,0);
   if( ticket< 0 ){
      Comment("failed to buy");
      return(0);
   }
   
   if( !OrderSelect(ticket,SELECT_BY_TICKET) ){
      Comment("failed to select ticket");
      return(0);
   }

   while(ticker>0){           // ticket remains selected indefinitely
      while( !RefreshRates() )
         Sleep(50);

      // If you do not re-OrderSelect after a new quote OrderClosePrice is not valid
      //OrderSelect(ticket,SELECT_BY_TICKET);
      string str="";
      if( MathAbs(Bid - OrderClosePrice()) > Point/2.0 )
         str = "\n** OrderClose value = FAIL **";
         
      Comment(ticker + "\n" + DoubleToStr(Bid,Digits)+ "\n" + DoubleToStr(OrderClosePrice(),Digits)+ str);
      ticker--;
   }

   if( !OrderClose(ticket, OrderLots(), OrderClosePrice(), 10) )
      Comment("**CLOSE TRADE MANUALLY**");
      
   return(0);
}

It turns out that OrderClosePrice is a copy of data and does not update on its own or on a RefreshRates. You have to explicitly do another OrderSelect (by test).

 

I tried a similar test with an EA.

// Run in a DEMO account
int ticket=  -1;
int ticker = -1;

//----------------------------------------------------------------------+
int init(){

   ticket= OrderSend(Symbol(),OP_BUY,0.1,Ask,10,0,0);

   if( ticket< 0 ){
      Comment("failed to buy");
      ticker = -1;   // effectively an abort flag
      Sleep(1000);
      return(0);
   }

   if( !OrderSelect(ticket,SELECT_BY_TICKET) ){ // this is only valid for 1 tick as it is copies current values
      Comment("failed to select ticket");
      ticker = -1;   // effectively an abort flag
      Sleep(1000);
      return(0);
   }
   
   ticker = 100;
}
//----------------------------------------------------------------------+
int deinit(){
   Comment("");
}
//----------------------------------------------------------------------+
int start(){
   if( ticker <= 0 ){
      if( ticket > 0 ){
         if( OrderClose(ticket, OrderLots(), Bid, 10) )
            ticket = -1;
      }
      return( 0 );
   }

   // If you do not re-OrderSelect after a new tick OrderClosePrice (and any other changes) are not valid
   //OrderSelect(ticket,SELECT_BY_TICKET);
   string str="";
   if( MathAbs(Bid - OrderClosePrice()) > Point/2.0 )
      str = "\n** OrderClose value = FAIL **";
      
   Comment(ticker + "\n" + DoubleToStr(Bid,Digits)+ "\n" + DoubleToStr(OrderClosePrice(),Digits)+ str);
   
   ticker--;
      
   return(0);
}

I would conclude that any information "selected" by an OrderSelect is a copy of all the relevant data and that if anything changes the only way you will know is if you do another OrderSelect. RefreshRates and new ticks do not help.

 

My uncle pointed towards this little trick:

datetime CatchTime = Time[0];
Alert( "CatchTime=" + CatchTime );
Sleep( 75 * 1000 );

CatchTime = Time[0];
Alert( "CatchTime=" + CatchTime );
Sleep( 75 * 1000 );

It seems that more than just price data is "buffered". Pretty much everything is a snapshot it seems. The starting time of the current bar is not updated, when a new bar is formed while the start function is running. Which is quite handy of course :-)

Thank you all for all the information provided!

Reason: