IP를 통해 Java에서 MT4로 주문 보내기 - 페이지 2

 
Mariop :

진실. 감사해요. 나는 그것을 기억하지 못했다. 실제로 거의 즉시 실행되는 명령이 필요하기 때문에 문제를 완전히 해결하지 못합니다(이 방법을 사용하면 매초만 확인할 수 있지만 적어도 모든 틱은 확인할 수 없음). 그러나 실제로 임시 솔루션을 쉽게 구축할 수 있습니다. 그것을 사용.

OnTimer가 시스템 클록에 맞춰 가장 빠른 속도를 가지지만, 즉 15ms마다, 저는 1ms 간격으로 루핑하는 것을 선호합니다(루프에서 Sleep(1) 사용).

 
Ovo :

OnTimer가 시스템 클록에 맞춰 가장 빠른 속도를 가지지만, 즉 15ms마다, 저는 1ms 간격으로 루핑하는 것을 선호합니다(루프에서 Sleep(1) 사용).

문제가 되지 않을까요? 내 말은, MT4에는 OnTick()을 실행하여 중지하고 반복하지 않고 몇 주 동안 실행(EA)한 후 오버플로되거나 크기가 초과되는 일종의 내부 버퍼를 방지하기 위해 실행해야 할 수 있는 내부 프로세스가 없습니다.

무지해서 물어보는건데 MT4가 그렇게 하도록 고안되지 않았다고 가정하면 문제가 될 수 있는지 모르겠습니다.

그래서 당신은 그것이 문제가 되지 않을 것이라고 생각합니까? (그렇다면 좋은 소식입니다.)


BTW: OnTimer() 가 1초 간격 미만으로 실행되도록 하려면 어떻게 합니까? :?

 

나는 비슷한 이유로 몇 년 전에 init()에서 시작된 루프에서 EA를 실행하곤 했습니다. 최소한의 지연으로 외부 데이터를 읽기 때문입니다. 부작용 없이 몇 주 동안 사용했습니다. Sleep(1)은 컴퓨팅 성능 에 미치는 영향을 매우 가볍게 만들기에 충분합니다.

타이머 설정은 밀리 단위를 허용합니다.

 
Ovo :

나는 비슷한 이유로 몇 년 전에 init()에서 시작된 루프에서 EA를 실행하곤 했습니다. 최소한의 지연으로 외부 데이터를 읽기 때문입니다. 부작용 없이 몇 주 동안 사용했습니다. Sleep(1)은 컴퓨팅 성능에 미치는 영향을 매우 가볍게 만들기에 충분합니다.

타이머 설정은 밀리 단위를 허용합니다.

특별한 소식입니다. 이미 확인 하셨다면 충돌을 두려워하지 않고 할 수 있습니다. 이 문제에 대한 경험을 공유해 주셔서 감사합니다. 문제 해결 =D
 
Mariop :

BTW: OnTimer()가 1초 간격 미만으로 실행되도록 하려면 어떻게 합니까? :?


EventSetMillisecondTimer

이 기능은 이 Expert Advisor 또는 표시기에 대해 1초 미만의 간격으로 타이머 이벤트가 생성되어야 함을 클라이언트 터미널에 나타냅니다.

bool EventSetMillisecondTimer (
    정수    밀리초        // 밀리초 수
);

매개변수

밀리초

【인】 타이머 이벤트의 빈도를 정의하는 밀리초 수입니다.

반환된 값

성공적으로 실행되면 true를 반환하고 그렇지 않으면 false를 반환합니다. 에러 코드를 받기 위해서는 GetLastError() 함수를 호출해야 합니다.

메모

이 기능은 고해상도 타이머가 필요한 경우를 위해 설계되었습니다 . 즉, 타이머 이벤트는 초당 한 번보다 더 자주 수신되어야 합니다. 몇 초 주기의 기존 타이머로 충분하다면 EventSetTimer() 를 사용하십시오.

일반적으로 이 함수는 OnInit() 함수 또는 클래스 생성자 에서 호출해야 합니다. 타이머에서 오는 이벤트를 처리하기 위해서는 Expert Advisor나 인디케이터에 OnTimer() 함수가 있어야 합니다.

각 Expert Advisor와 각 표시기는 이 타이머에서만 이벤트를 수신하는 자체 타이머와 함께 작동합니다. mql4 애플리케이션 종료 중에 타이머가 생성되었지만 EventKillTimer() 함수에 의해 비활성화되지 않은 경우 타이머가 강제로 소멸됩니다.

각 프로그램에 대해 하나의 타이머만 시작할 수 있습니다. 각 mql4 애플리케이션 및 차트에는 새로 도착한 모든 이벤트가 배치되는 자체 이벤트 대기열이 있습니다. 대기열에 이미 Timer 이벤트가 포함되어 있거나 이 이벤트가 처리 단계에 있는 경우 새 Timer 이벤트는 mql4 애플리케이션 대기열에 추가되지 않습니다.


 
GumRai :

EventSetMillisecondTimer

이 기능은 타이머 이벤트가 이 Expert Advisor 또는 표시기에 대해 1초 미만의 간격으로 생성되어야 함을 클라이언트 터미널에 나타냅니다.

bool EventSetMillisecondTimer (
    정수    밀리초        // 밀리초 수
);

매개변수

밀리초

【인】 타이머 이벤트의 빈도를 정의하는 밀리초 수입니다.

반환된 값

성공적으로 실행되면 true를 반환하고 그렇지 않으면 false를 반환합니다. 에러 코드를 받기 위해서는 GetLastError() 함수를 호출해야 합니다.

메모

이 기능은 고해상도 타이머 가 필요한 경우에 설계되었습니다 . 즉, 타이머 이벤트는 초당 한 번보다 더 자주 수신되어야 합니다. 몇 초의 기간을 가진 기존 타이머로 충분하다면 EventSetTimer() 를 사용하십시오.

일반적으로 이 함수는 OnInit() 함수 또는 클래스 생성자 에서 호출해야 합니다. 타이머에서 오는 이벤트를 처리하기 위해서는 Expert Advisor나 인디케이터에 OnTimer() 함수가 있어야 합니다.

각 Expert Advisor와 각 표시기는 이 타이머에서만 이벤트를 수신하는 자체 타이머와 함께 작동합니다. mql4 애플리케이션 종료 중에 타이머가 생성되었지만 EventKillTimer() 함수에 의해 비활성화되지 않은 경우 타이머가 강제로 소멸됩니다.

각 프로그램에 대해 하나의 타이머만 시작할 수 있습니다. 각 mql4 애플리케이션 및 차트에는 새로 도착한 모든 이벤트가 배치되는 자체 이벤트 대기열이 있습니다. 대기열에 이미 Timer 이벤트가 포함되어 있거나 이 이벤트가 처리 단계에 있는 경우 새 Timer 이벤트가 mql4application 대기열에 추가되지 않습니다.




자세한 설명 감사합니다. 내 잘못; 온라인에서 너무 빨리 읽었습니다. (링크는 docs.mql4.com 도메인을 forum.mql4.com 과 교환했습니다. 다른 사람이 이 스레드를 확인할 경우를 대비하여...)


편집: 주위에 있는 중재자를 활용할 것입니다. 이전 게시물에서 설명한 대로 N 밀리초마다 OnTimer()를 실행하는 것과 N 밀리초마다 동일한 루프를 수행하는 것 사이에 차이점이 있는지 아십니까?

 

"ms" 타이밍으로 모든 소란을 피우는 이유를 모르겠습니다. 이것이 매우 낮은 대기 시간 중개자 연결에서 일종의 "고주파 뉴스 스캘퍼" 가 아닌 한, OnTimer() 의 1초 간격은 응답 시간으로 충분해야 합니다.

JAVA 앱 실행, IPC(LAN & WAN) 통신, 주문 관리 실행 및 브로커 서버 대기 시간의 모든 지연과 대기 시간을 추가하면 일반 전략에 "ms" 타이밍을 사용하는 데 실질적인 이점이 없습니다.

그러나 브로커에 대한 대기 시간이 짧은 VPS에서 사용되는 일종의 "High Frequency News Scalper" 인 경우 JAVA 및 IPC를 전혀 사용하지 않아야 하며 전략을 코딩해야 합니다. 가능한 가장 짧은 대기 시간을 얻기 위해 매우 컴팩트한 MQL에서 직접

편집하다:

별도의 데이터 피드와 함께 외부 앱을 사용하고 있다는 사실(MT4 피드와 관련하여 가격, 볼륨 및 타이밍에서 벗어나는 것이 보장됨)은 이렇게 빡빡한 "ms" 타이밍이 필요할 방법이 없음을 보여줍니다 . "1초" 폴링 간격이 적절합니다.

또한 OnTick() 이벤트는 들어오는 메시지를 확인할 수도 있으므로 "1초"는 들어오는 틱이 없을 때만 제한적인 경우입니다. 그리고 들어오는 틱이 없으면 어쨌든 그러한 빠른 "ms" 응답을 정당화하기에 충분한 활동(변동성 및 유동성)도 없습니다.

일을 복잡하게 만들지 마십시오! KISS 교장을 기억하십시오.

 
Mariop :

편집: 주위에 있는 중재자를 활용할 것입니다. 이전 게시물에서 설명한 대로 N 밀리초마다 OnTimer()를 실행하는 것과 N 밀리초마다 동일한 루프를 수행하는 것 사이에 차이점이 있는지 아십니까?

내가 중재자라고 해서 내가 다른 사람들보다 더 지식이 있다는 것을 의미하지는 않습니다. 사실, 이 스레드의 다른 포스터들은 분명히 그 주제에 대해 나보다 더 많은 지식을 가지고 있습니다. 나는 자바에 대해 아무것도 모른다.

타이머 이벤트에서 Sleep()을 사용 하는 요점을 이해하지 못합니다. EA가 보류되고 이는 OnTick() 이벤트가 많이 누락됨을 의미할 수 있기 때문입니다. 물론 EA에 따라 OnTick 이벤트는 중요하지 않을 수 있습니다.

 
Ovo :

나는 비슷한 이유로 몇 년 전에 init()에서 시작된 루프에서 EA를 실행하곤 했습니다. 최소한의 지연으로 외부 데이터를 읽기 때문입니다. 부작용 없이 몇 주 동안 사용했습니다. Sleep(1)은 컴퓨팅 성능에 미치는 영향을 매우 가볍게 만들기에 충분합니다.

약간의 재미를 위해... 다음 스크립트는 여러 동시 TCP/IP 연결을 허용하고 들어오는 CR로 구분된 메시지를 Experts 로그에 씁니다. 예를 들어 스크립트가 실행되면 Telnet을 통해(기본적으로 포트 51234로) 연결할 수 있으며 입력한 텍스트의 각 행이 인쇄됩니다.

 #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 :

약간의 재미를 위해... 다음 스크립트는 여러 동시 TCP/IP 연결을 허용하고 들어오는 CR로 구분된 메시지를 Experts 로그에 씁니다.

... 스크립트가 아닌 EA에서 위의 작업을 수행하려면 다음과 같이 변경하면 됩니다.

  • 모든 코드를 OnStart()에서 listen() 호출까지 포함하여 EA의 OnInit()로 이동합니다.
  • OnInit() 끝에 고주파 타이머를 설정합니다(예: EventSetMillisecondTimer(10)).
  • 나머지 코드를 OnStart()에서 OnTimer()로 이동하고 외부 "while (!IsStopped()) {}" 루프를 제거합니다.
최근 MT4 빌드에서 이 문제가 수정되지 않은 한 MT4 플랫폼이 이미 차트에 첨부된 EA로 시작될 때 OnInit()에서 사용하면 EventSetTimer() 및 EventSetMillisecondTimer()가 실패할 수 있다는 메모를 추가하겠습니다. 내 경험상 반환 값을 확인 하는 것이 필요합니다. 다시 해 보다; OnInit()에서 타이머를 생성하려는 시도가 실패한 경우 첫 번째 OnTick()에서 타이머를 설정하는 것으로 잠재적으로 폴백합니다.
사유: