Send orders to MT4 from Java via IP - page 2

 
Mariop:

True. Thanks. I didn't remember that. Actually it doesn't solve the problem completely since I need orders to be executed almost immediately (and I think with this method I can only check it every second, but at least not every tick), but indeed I can easily build a temporary solution using it. 

Though the OnTimer has the fastest rate aligned with the system clock, i.e. every 15 ms, I would prefer looping in 1ms intervals (using the Sleep(1) in the loop).

 
Ovo:

Though the OnTimer has the fastest rate aligned with the system clock, i.e. every 15 ms, I would prefer looping in 1ms intervals (using the Sleep(1) in the loop).

 

 

Wouldn't that be a problem? I mean, there are not internal processes in MT4 that may need OnTick() to be executed to avoid some kind of internal buffers to end up overflowed or oversized after weeks of being running (the EA) without stopping and just looping?

I'm asking it from the ignorance, I have no idea whether it could be a problem, just assuming MT4 was not devised to do it.

So you think(/have tried) it will not be a problem? (If so, those are great news).


BTW: How do you get OnTimer() to be executed below 1 sec interval? :?

 

I used to run EAs in a loop started in init() some years ago, for similar reason - reading external data with minimum delay. It used to run weeks without any side effect. The Sleep(1) is satisfactory to make the computing power impact very light.

The timer settings accepts millis. 

 
Ovo:

I used to run EAs in a loop started in init() some years ago, for similar reason - reading external data with minimum delay. It used to run weeks without any side effect. The Sleep(1) is satisfactory to make the computing power impact very light.

The timer settings accepts millis. 

Extraordinary news. If you have already checked it, then I can do it without being afraid of it to crash. Thanks a lot for sharing your experience on this issue. Problem solved =D
 
Mariop:

BTW: How do you get OnTimer() to be executed below 1 sec interval? :?


EventSetMillisecondTimer

The function indicates to the client terminal that timer events should be generated at intervals less than one second for this Expert Advisor or indicator.

bool  EventSetMillisecondTimer(
   int  milliseconds      // number of milliseconds
   );

Parameters

milliseconds

[in]  Number of milliseconds defining the frequency of timer events.

Returned value

In case of successful execution, returns true, otherwise - false. To receive an error code, GetLastError() function should be called.

Note

This feature is designed for the cases when high-resolution timer is required. In other words, timer events should be received more frequently than once per second. If a conventional timer with the period of several seconds is enough for you, use EventSetTimer().

Usually, this function should be called from OnInit() function or in class constructor. To handle events coming from the timer, an Expert Advisor or an indicator should have OnTimer() function.

Each Expert Advisor and each indicator work with its own timer receiving events solely from this timer. During mql4 application shutdown, the timer is forcibly destroyed in case it has been created but has not been disabled by EventKillTimer() function.

Only one timer can be launched for each program. Each mql4 application and chart have their own queue of events where all newly arrived events are placed. If the queue already contains Timer event or this event is in the processing stage, then the new Timer event is not added to mql4 application queue.


 
GumRai:

EventSetMillisecondTimer

The function indicates to the clientterminal that timer eventsshould be generated at intervals less than one second for this Expert Advisor orindicator.

bool  EventSetMillisecondTimer(
   int  milliseconds      // number of milliseconds
   );

Parameters

milliseconds

[in]  Numberof milliseconds defining the frequency of timer events.

Returned value

In case of successfulexecution, returns true, otherwise - false. To receive an error code, GetLastError() function should be called.

Note

This feature is designedfor the cases when high-resolution timer isrequired. In other words, timer eventsshould be received more frequently than once per second. If a conventional timerwith the period of several seconds is enough for you, use EventSetTimer().

Usually, this functionshould be called from OnInit()function or in class constructor. To handle events coming from thetimer, an Expert Advisor or an indicator should have OnTimer() function.

Each Expert Advisor andeach indicator work with its own timer receiving events solely from this timer.During mql4 application shutdown, the timer is forcibly destroyed in case it hasbeen created but has not been disabled by EventKillTimer() function.

Only one timer can belaunched for each program. Each mql4 application and chart have their own queueof events where all newly arrived events are placed. If the queue alreadycontains Timer event or thisevent is in the processing stage, then the new Timer event is not added to mql4application queue.




Thanks for the detailed explanation; my fault; I read it too quickly online. (Links have interchanged docs.mql4.com domain with forum.mql4.com. Just in case anyone else check this thread...)


EDIT: I'm going to take advantage of a moderator being around: Do you know whether it exists any difference between executing OnTimer() every N millisecs and doing the same looping every N millisec as described on previous posts?

 

I don't see why all the fuss with "ms" timing. Unless this is some sort of "High Frequency News Scalper" on a very low latency broker connection, one second intervals on OnTimer() should be more than enough as a response time.

If you add all the delays and latency of the JAVA app execution, IPC (LAN & WAN) communication, Order management execution and Broker server latency, there is no real advantage in using "ms" timing for normal strategies.

If however, it is some sort of "High Frequency News Scalper", to be used on a VPS with a low latency connection to the broker, then you should NOT be messing about with JAVA and IPC at all, and should be coding the strategy directly in very compact MQL to get the lowest latency possible.

EDIT:

That fact that you are using a external app with a separate data feed (which is guaranteed to deviate in price, volume and timing with regards to the MT4 feed), shows that there is no way this would require such tight "ms" timing. A "one second" polling interval is more than adequate.

Remember also, that the OnTick() event can also check for incoming messages, so "one second" is only a limiting case when there are no incoming ticks. And if there are no incoming ticks, then there is also not enough activity (volatility and liquidity) to justify such a quick "ms" response anyway.

Don't complicate things! Remember the K.I.S.S. principal.

 
Mariop:

EDIT: I'm going to take advantage of a moderator being around: Do you know whether it exists any difference between executing OnTimer() every N millisecs and doing the same looping every N millisec as described on previous posts?

Just because I am a moderator, it doesn't mean that I am more knowledgable than others. In fact, the other posters in this thread obviously have more knowledge than I on the subject matter. I know nothing about Java.

I don't understand the point of using Sleep() in a timer event as it puts the EA on hold and this could mean missing a lot of OnTick() events. Of course, depending on the EA, OnTick events may be unimportant.

 
Ovo:

I used to run EAs in a loop started in init() some years ago, for similar reason - reading external data with minimum delay. It used to run weeks without any side effect. The Sleep(1) is satisfactory to make the computing power impact very light.

For a bit of fun... the following script accepts multiple concurrent TCP/IP connections, and writes incoming CR-delimited messages to the Experts log. For example, once the script is running you can connect via Telnet (to port 51234 by default), and each line of text which you type in will be printed.

 

#property strict 
#property show_inputs

// ---------------------------------------------------------------------
// User-configurable parameters
// ---------------------------------------------------------------------

input int PortNumber = 51234; // TCP/IP port number

// ---------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------

// Size of temporary buffer used to read from client sockets
#define SOCKET_READ_BUFFER_SIZE 10000

// ---------------------------------------------------------------------
// Forward definitions of classes
// ---------------------------------------------------------------------

// Wrapper around a connected client socket
class Connection;

// ---------------------------------------------------------------------
// Winsock structure definitions and DLL imports
// ---------------------------------------------------------------------

struct sockaddr_in {
   short af_family;
   short port;
   int addr;
   int dummy1;
   int dummy2;
};

struct timeval {
   int secs;
   int usecs;
};

struct fd_set {
   int count;
   int single_socket;
   int dummy[63];
};

#import "Ws2_32.dll"
   int socket(int, int, int);   
   int bind(int, sockaddr_in&, int);
   int htons(int);
   int listen(int, int);
   int accept(int, int, int);
   int closesocket(int);
   int select(int, fd_set&, int, int, timeval&);
   int recv(int, uchar&[], int, int);
   int WSAGetLastError();
#import   


// ---------------------------------------------------------------------
// Global variables
// ---------------------------------------------------------------------

// Handle of main listening server socket
int ServerSocket;

// List of currently connected clients
Connection * Clients[];



// ---------------------------------------------------------------------
// Entry point 
// ---------------------------------------------------------------------

void OnStart()
{
   if (!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED)) {Print("Requires \'Allow DLL imports\'");return;}

   // (Don't need to call WSAStartup because MT4 must have done this)

   // Create the main server socket
   ServerSocket = socket(2 /* AF_INET */, 1 /* SOCK_STREAM */, 6 /* IPPROTO_TCP */);
   if (ServerSocket == -1) {Print("ERROR " , WSAGetLastError() , " in socket creation");return;}
   
   // Bind the socket to the specified port number. In this example,
   // we only accept connections from localhost
   sockaddr_in service;
   service.af_family = 2 /* AF_INET */;
   service.addr = 0x100007F; // equivalent to inet_addr("127.0.0.1")
   service.port = (short)htons(PortNumber);
   if (bind(ServerSocket, service, 16 /* sizeof(service) */) == -1) {Print("ERROR " , WSAGetLastError() , " in socket bind");return;}

   // Put the socket into listening mode
   if (listen(ServerSocket, 0) == -1) {Print("ERROR " , WSAGetLastError() , " in socket listen");return;}
 

   // Listening loop, which continues until Remove Script is used
   timeval waitfor;
   waitfor.secs = 0;
   waitfor.usecs = 0;
   
   while (!IsStopped()) {
      // .........................................................
      // Do we have a new pending connection on the server socket?
      fd_set PollServerSocket;
      PollServerSocket.count = 1;
      PollServerSocket.single_socket = ServerSocket;

      int selres = select(0, PollServerSocket, 0, 0, waitfor);
      if (selres > 0) {
      
         Print("New incoming connection...");
         int NewClientSocket = accept(ServerSocket, 0, 0);
         if (NewClientSocket == -1) {
            Print("ERROR " , WSAGetLastError() , " in socket accept");

         } else {
            Print("...accepted");

            int ctarr = ArraySize(Clients);
            ArrayResize(Clients, ctarr + 1);
            Clients[ctarr] = new Connection(NewClientSocket);               
            Print("Got connection to client ", Clients[ctarr].GetID());
         }
      }
  
      // .........................................................
      // Process any incoming data from client connections
      // (including any which have just been accepted, above)
      int ctarr = ArraySize(Clients);
      for (int i = ctarr - 1; i >= 0; i--) {
         // Return value from ReadAnyPendingData() is true
         // if the socket still seems to be alive; false if 
         // the connection seems to have been closed, and should be discarded
         if (Clients[i].ReadAnyPendingData()) {
            // Socket still seems to be alive
            
         } else {
            // Socket appears to be dead. Delete, and remove from list
            Print("Lost connection to client ", Clients[i].GetID());
            
            delete Clients[i];
            for (int j = i + 1; j < ctarr; j++) {
               Clients[j - 1] = Clients[j];
            }
            ctarr--;
            ArrayResize(Clients, ctarr);           
         }
      }
      
      Sleep(10); // Sleep(1) appears to be a little too aggressive in this context
   }
}

// ---------------------------------------------------------------------
// Termination (could do this at the end of OnStart() instead.
// It's just a little clearer to do it here
// ---------------------------------------------------------------------

void OnDeinit(const int reason)
{
   closesocket(ServerSocket);
   
   for (int i = 0; i < ArraySize(Clients); i++) {
      delete Clients[i];
   }
}


// ---------------------------------------------------------------------
// Simple wrapper around each connected client socket
// ---------------------------------------------------------------------

class Connection {
private:
   // Client socket handle
   int mSocket;

   // Temporary buffer used to handle incoming data
   uchar mTempBuffer[SOCKET_READ_BUFFER_SIZE];
   
   // Stored-up data, waiting for a \r character 
   string mPendingData;
   
public:
   Connection(int ClientSocket) {mSocket = ClientSocket; mPendingData = "";}
   ~Connection() {closesocket(mSocket);}
   string GetID() {return IntegerToString(mSocket);}
   
   bool ReadAnyPendingData();
};

// Called repeatedly on a timer from OnStart(), to check whether any
// data is available on this client connection. Returns true if the 
// client still seems to be connected (*not* if there's new data); 
// returns false if the connection seems to be dead. 
bool Connection::ReadAnyPendingData()
{
   // Check the client socket for data-readability
   timeval waitfor;
   waitfor.secs = 0;
   waitfor.usecs = 0;

   fd_set PollClientSocket;
   PollClientSocket.count = 1;
   PollClientSocket.single_socket = mSocket;

   int selres = select(0, PollClientSocket, 0, 0, waitfor);
   if (selres > 0) {
      
      // Winsock says that there is data waiting to be read on this socket
      int res = recv(mSocket, mTempBuffer, SOCKET_READ_BUFFER_SIZE, 0);
      if (res > 0) {
         // Convert the buffer to a string, and add it to any pending
         // data which we already have on this connection
         string strIncoming = CharArrayToString(mTempBuffer, 0, res);
         mPendingData += strIncoming;
         
         // Do we have a complete message (or more than one) ending in \r?
         int idxTerm = StringFind(mPendingData, "\r");
         while (idxTerm >= 0) {
            if (idxTerm > 0) {
               string strMsg = StringSubstr(mPendingData, 0, idxTerm);         
               
               // Print the \r-terminated message in the log
               Print("#" , GetID() , ": " , strMsg);
            }               
         
            // Keep looping until we have extracted all the \r delimited 
            // messages, and leave any residue in the pending data 
            mPendingData = StringSubstr(mPendingData, idxTerm + 1);
            idxTerm = StringFind(mPendingData, "\r");
         }
         
         return true;
         
      } else {
         // recv() failed. Assume socket is dead
         return false;
      }
   
   } else if (selres == -1) {
      // Assume socket is dead
      return false;
      
   } else {
      // No pending data
      return true;
   }
}
 
jjc:

For a bit of fun... the following script accepts multiple concurrent TCP/IP connections, and writes incoming CR-delimited messages to the Experts log.  

... stating the obvious, if you wanted to do the above in an EA rather than a script, then you'd simply change it as follows:

  • Move all the code from OnStart(), up to and including the call to listen(), into the EA's OnInit()
  • Set up a high-frequency timer at the end of OnInit(), e.g. EventSetMillisecondTimer(10)
  • Move the remaining code from OnStart() into OnTimer(), removing the outer "while (!IsStopped()) {}" loop
I'll add a note that - unless this has been fixed in very recent MT4 builds - EventSetTimer() and EventSetMillisecondTimer() can fail if used in OnInit() when the MT4 platform is starting up with an EA already attached to a chart. In my experience it's necessary to check the return values; retry; and potentially fall back to setting up the timer on the first OnTick() if attempts to create it in OnInit() have been unsuccessful. 
Reason: