How to run a python script from an MQL4 EA-process ( MetaTrader4 Terminal )?

xion picture xion · Sep 8, 2017 · Viewed 7.5k times · Source

I have a simple test.py script that I would like to run from an MQL4 EA.

How can I implement this?

I have tried using ShellExecute() but that will not work in my case as I am running MetaTrader4 Terminal on a linux machine and thus cannot call windows based ShellExecute() ( even with a wine ).

Answer

user3666197 picture user3666197 · Sep 8, 2017

Option 0: use of a wine-promise to have a full DLL-abstraction

The wine project, if configured properly, ought provide a full DLL-abstraction, so that a legitimate ShellExecute() ought provide a way to launch a wine-enveloped MetaTrader4 Terminal a launch of such intended process.


Option 1: use a distributed processing { ZeroMQ | nanomsg }

Given this option feasible since ZeroMQ v2.11, the python was always ready to communicate with MQL4 and start/stop any service provisioning on-{MQL4|*}-demand. This would be my preferred way, as the workflow is not isolated to just "fire-and-forget" missile-control.

Using this architecture many years for AI/ML-predictor Predictive Engine, Remote Keyboards, off-site centralised smart-logging, process-health/performance-telemetry services integration ( not only with MQL4-code execution-units ) and remaining happy all the years for having chosen this advanced distributed architecture way.


Nota Bene: It is fair to note, that somewhere around an MQL4 Build 850 / 900 MetaTrader4 Terminal code-execution engine revision has created a few dozens headbang issues for DLL-wrapper / original ZeroMQ v2.11 wrapper, but some moderate amount of efforts made the New-MQL4.56789 change of string, which stopped to be string anymore ( being surprisingly a re-dressed struct ), but in most high-performance processing interactions are bit-packed, so no heart-breaks ought appear from this.


Python side:

def main():
    # setup ZeroMQ infrastructure and map all resources
    import  zmq
    ...
    pass; mainloopSTAY = True
    #     mainloop(): -----------------------------
    while mainloopSTAY:
       try:
           # ----------------------- event-handling:
           pass;   
       except:
           # ------------------------- EXC-handling: { continue }
           pass;
       finally:
           # dismantle ZeroMQ infrastructure and release all resources
           pass;   print( "INF: main().finally: EXIT" )
           # { break | if mainloopSTAY }
    #----------------------------------------------
    pass;          print( "INF: main().pre-return SECTION" )

if __name__ == '__main__':
    main()   #  EXECUTED only if this module-file was called to run from a command-line ( Ref. SECTION: import for def: )

MQL4 side:

#include   <mql4zmq_for_Terminal_4.00_Build.840.mqh>        // STILL BUG/ERROR on zmq_poll() while missing zmq_poll_struct_t

         string   aTemp = ">>> ";                           // globally visible ...
         int      aZmqCONTEXT,                              // globally visible ...
                  aZmqSOCKET;                               // globally visible ... so as to be able to auto-deinit in { EA -s | #Indicators } .deinit() on panic termination(s)

//+------------------------------------------------------------------+
//|      msMOD_deinit( int       aZmqSOCKET  = EMPTY )               |
//+------------------------------------------------------------------+
void     msMOD_deinit( const int aZmqSOCKET  = EMPTY ) {
         if (                    aZmqSOCKET != EMPTY ) {
               zmq_setsockopt(   aZmqSOCKET, ZMQ_LINGER, 0 );
               zmq_close(        aZmqSOCKET );
               }
         zmq_term(               aZmqCONTEXT );
         return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void  OnDeinit( const int anAutoDeinitREASON ){ // auto-generated ONLY for { EA-s , #Indicator-s }
      msMOD_deinit( aZmqSOCKET );
   }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void  OnStart()
{                                      aZmqCONTEXT = zmq_init(1);                            // .init into globally visible int
                                 if (  aZmqCONTEXT < 0 ){   
                                                            msMOD_deinit();                  // GRACEFUL CLEANUP
                                                            return;                          // DEBUG: RET()
                                 }
                                 int   aZmqPAIR = zmq_socket( aZmqCONTEXT, ZMQ_PAIR );       // .sock PAIR
                                 if (  aZmqPAIR < 0 ){
                                                            msMOD_deinit( aZmqPAIR );        // GRACEFUL CLEANUP
                                                            return;                          // DEBUG: RET()
                                 }
                                 int   aZmqBindPAIR = zmq_bind(   aZmqPAIR,
                                                                  "tcp://A.B.C.D:PORT"  // i5-eth0-IP:#####
                                                                  );                     
                                 if (  aZmqBindPAIR < 0 ){
                                                            msMOD_deinit( aZmqPAIR );        // GRACEFUL CLEANUP
                                                            return;                          // DEBUG: RET()
                                 }
       ...
       int RC = mql4zmq_msg_init_data( aSendMsgOBJ, aSendMsgBuffUCHAR, aSendMsgBUFF_SIZE * 4 );
       zmq_send( aZmqPAIR,             aSendMsgOBJ );
       ...
}