IP üzerinden Java'dan MT4'e sipariş gönder - sayfa 2

 
Mariop :

Doğru. Teşekkürler. Bunu hatırlamadım. Aslında bu sorunu tamamen çözmüyor çünkü emirlerin neredeyse anında yerine getirilmesine ihtiyacım var (ve sanırım bu yöntemle onu sadece saniyede bir kontrol edebiliyorum, ama en azından her tikte değil), ama gerçekten de kolayca geçici bir çözüm üretebiliyorum. onu kullanmak.

OnTimer, sistem saati ile uyumlu en hızlı hıza sahip olsa da, yani her 15 ms'de bir, 1 ms aralıklarla döngü yapmayı tercih ederim (döngüde Uyku(1)'i kullanarak).

 
Ovo :

OnTimer, sistem saati ile uyumlu en hızlı hıza sahip olsa da, yani her 15 ms'de bir, 1 ms aralıklarla döngü yapmayı tercih ederim (döngüde Uyku(1)'i kullanarak).

Bu bir sorun olmaz mıydı? Demek istediğim, MT4'te, bir tür dahili arabelleğin durmadan ve sadece döngüye girmeden haftalarca çalıştıktan sonra (EA) taşmasını veya aşırı boyutlandırılmasını önlemek için OnTick()'in yürütülmesi gerekebilecek dahili süreçler yok mu?

Cehaletten soruyorum, sorun olabilir mi bilmiyorum, sadece MT4'ün bunu yapmak için tasarlanmadığını varsayarsak.

Yani (/denediniz) bir sorun olmayacağını mı düşünüyorsunuz? (Eğer öyleyse, bunlar harika haberler).


BTW: OnTimer() 'ın 1 saniyelik aralığın altında yürütülmesini nasıl sağlarsınız? :?

 

EA'ları birkaç yıl önce init() içinde başlatılan bir döngüde çalıştırırdım, benzer bir nedenle - minimum gecikmeyle harici verileri okumak. Hiçbir yan etkisi olmadan haftalarca çalışırdı. Uyku(1), bilgi işlem gücü etkisinin çok hafif olması için tatmin edicidir.

Zamanlayıcı ayarları mili kabul eder.

 
Ovo :

EA'ları birkaç yıl önce init() içinde başlatılan bir döngüde çalıştırırdım, benzer bir nedenle - minimum gecikmeyle harici verileri okumak. Hiçbir yan etkisi olmadan haftalarca çalışırdı. Uyku(1), bilgi işlem gücü etkisinin çok hafif olması için tatmin edicidir.

Zamanlayıcı ayarları mili kabul eder.

Olağanüstü haberler. Zaten kontrol ettiyseniz, çökmesinden korkmadan yapabilirim. Bu konudaki deneyimlerinizi paylaştığınız için çok teşekkür ederiz. Sorun çözüldü =D
 
Mariop :

BTW: OnTimer()'ın 1 saniyelik aralığın altında yürütülmesini nasıl sağlarsınız? :?


EventSetMilisaniyeZamanlayıcı

İşlev, müşteri terminaline, bu Uzman Danışman veya gösterge için zamanlayıcı olaylarının bir saniyeden daha kısa aralıklarla oluşturulması gerektiğini belirtir.

bool EventSetMillisecondTimer (
    int    milisaniye        // milisaniye sayısı
);

parametreler

milisaniye

[içinde] Zamanlayıcı olaylarının sıklığını tanımlayan milisaniye sayısı.

döndürülen değer

Başarılı yürütme durumunda, true, aksi takdirde - false döndürür. Bir hata kodu almak için GetLastError() işlevi çağrılmalıdır.

Not

Bu özellik, yüksek çözünürlüklü zamanlayıcının gerekli olduğu durumlar için tasarlanmıştır . Başka bir deyişle, zamanlayıcı olayları saniyede bir defadan daha sık alınmalıdır. Birkaç saniyelik süreye sahip geleneksel bir zamanlayıcı sizin için yeterliyse, EventSetTimer() öğesini kullanın.

Genellikle, bu işlev OnInit() işlevinden veya sınıf yapıcısından çağrılmalıdır. Zamanlayıcıdan gelen olayları işlemek için bir Uzman Danışman veya gösterge OnTimer() işlevine sahip olmalıdır.

Her Uzman Danışman ve her gösterge, yalnızca bu zamanlayıcıdan olayları alan kendi zamanlayıcısıyla çalışır. mql4 uygulamasının kapatılması sırasında, oluşturulmuş ancak EventKillTimer() işlevi tarafından devre dışı bırakılmamışsa, zamanlayıcı zorla yok edilir.

Her program için yalnızca bir zamanlayıcı başlatılabilir. Her mql4 uygulamasının ve grafiğinin, yeni gelen tüm olayların yerleştirildiği kendi olay sırası vardır. Kuyruk zaten Zamanlayıcı olayı içeriyorsa veya bu olay işleme aşamasındaysa, yeni Zamanlayıcı olayı mql4 uygulama kuyruğuna eklenmez.


 
GumRai :

EventSetMilisaniyeZamanlayıcı

İşlev, bu Expert Advisor veya göstergesi için zamanlayıcı olaylarının bir saniyeden daha kısa aralıklarla oluşturulması gerektiğini müşteri terminaline bildirir.

bool EventSetMillisecondTimer (
    int    milisaniye        // milisaniye sayısı
);

parametreler

milisaniye

[içinde] Zamanlayıcı olaylarının sıklığını tanımlayan milisaniye sayısı.

döndürülen değer

Başarılı yürütme durumunda, true, aksi takdirde - false döndürür. Bir hata kodu almak için GetLastError() işlevi çağrılmalıdır.

Not

Bu özellik, yüksek çözünürlüklü zamanlayıcının gerekli olduğu durumlar için tasarlanmıştır . Başka bir deyişle, zamanlayıcı olayları saniyede bir defadan daha sık alınmalıdır. Birkaç saniyelik süreye sahip geleneksel bir zamanlayıcı sizin için yeterliyse, EventSetTimer () öğesini kullanın.

Genellikle, bu işlev OnInit() işlevinden veya sınıf yapıcısından çağrılmalıdır. Zamanlayıcıdan gelen olayları işlemek için bir Uzman Danışman veya gösterge OnTimer() işlevine sahip olmalıdır.

Her Expert Advisor ve her gösterge, yalnızca bu timer'dan olayları alan kendi timer'ı ile çalışır. mql4 uygulamasının kapanması sırasında, timer oluşturulmuş ancak EventKillTimer() işlevi tarafından devre dışı bırakılmamışsa, zorla yok edilir.

Her program için yalnızca bir zamanlayıcı başlatılabilir. Her mql4 uygulaması ve grafiği, yeni gelen tüm olayların yerleştirildiği kendi olay sıralarına sahiptir. Kuyruk zaten Zamanlayıcı olayı içeriyorsa veya bu olay işleme aşamasındaysa, yeni Zamanlayıcı olayı mql4application kuyruğuna eklenmez.




Detaylı açıklama için teşekkürler; benim hatam; İnternette çok hızlı okudum. (Bağlantılar docs.mql4.com alan adını forum.mql4.com ile değiştirmiştir. Başka birinin bu konuyu kontrol etmesi durumunda...)


DÜZENLEME: Etrafta olan bir moderatörün avantajından yararlanacağım: OnTimer()'ı her N milisaniyede yürütmek ile önceki gönderilerde açıklandığı gibi her N milisaniyede aynı döngüyü yapmak arasında herhangi bir fark olup olmadığını biliyor musunuz?

 

Neden "ms" zamanlaması ile ilgili tüm bu yaygarayı anlamıyorum. Bu, çok düşük gecikme süreli bir aracı bağlantısında bir tür "Yüksek Frekanslı Haber Ölçekleyici" olmadığı sürece, OnTimer() üzerindeki bir saniyelik aralıklar yanıt süresi olarak fazlasıyla yeterli olmalıdır.

JAVA uygulaması yürütme, IPC (LAN ve WAN) iletişimi, Sipariş yönetimi yürütme ve Aracı sunucu gecikmesinin tüm gecikmelerini ve gecikmesini eklerseniz, normal stratejiler için "ms" zamanlamasını kullanmanın gerçek bir avantajı yoktur.

Bununla birlikte, aracıya düşük gecikme süresi olan bir VPS'de kullanılacak bir tür "Yüksek Frekanslı Haber Ölçekleyici" ise, o zaman JAVA ve IPC ile hiç uğraşmamalısınız ve stratejiyi kodlamalısınız. mümkün olan en düşük gecikmeyi elde etmek için doğrudan çok kompakt MQL'de.

DÜZENLE:

Ayrı bir veri akışına sahip (MT4 akışına göre fiyat, hacim ve zamanlamada sapma olması garanti edilen) harici bir uygulama kullandığınız gerçeği, bunun böyle sıkı "ms" zamanlaması gerektirmemesinin hiçbir yolu olmadığını gösterir . "Bir saniye" yoklama aralığı fazlasıyla yeterli.

Ayrıca, OnTick() olayının gelen mesajları da kontrol edebileceğini unutmayın, bu nedenle "bir saniye", gelen işaretler olmadığında yalnızca sınırlayıcı bir durumdur. Ve gelen keneler yoksa, yine de bu kadar hızlı bir "ms" yanıtını haklı çıkarmak için yeterli aktivite (volatilite ve likidite) yoktur.

İşleri karmaşıklaştırma! KISS müdürünü hatırla.

 
Mariop :

DÜZENLEME: Etrafta olan bir moderatörün avantajından yararlanacağım: OnTimer()'ı her N milisaniyede yürütmek ile önceki gönderilerde açıklandığı gibi her N milisaniyede aynı döngüyü yapmak arasında herhangi bir fark olup olmadığını biliyor musunuz?

Moderatör olmam diğerlerinden daha bilgili olduğum anlamına gelmez. Aslında, bu başlıktaki diğer afişlerin konuyla ilgili benden daha fazla bilgisi olduğu açık. Java hakkında hiçbir şey bilmiyorum.

EA'yı beklemeye aldığı için bir zamanlayıcı olayında Sleep() kullanmanın amacını anlamıyorum ve bu birçok OnTick() olayının kaçırılması anlamına gelebilir. Tabii ki, EA'ya bağlı olarak OnTick olayları önemsiz olabilir.

 
Ovo :

EA'ları birkaç yıl önce init() içinde başlatılan bir döngüde çalıştırırdım, benzer bir nedenle - minimum gecikmeyle harici verileri okumak. Hiçbir yan etkisi olmadan haftalarca çalışırdı. Uyku(1), bilgi işlem gücü etkisinin çok hafif olması için tatmin edicidir.

Biraz eğlenmek için... aşağıdaki komut dosyası birden çok eşzamanlı TCP/IP bağlantısını kabul eder ve gelen CR ile sınırlandırılmış iletileri Uzmanlar günlüğüne yazar. Örneğin, komut dosyası çalışırken Telnet aracılığıyla (varsayılan olarak 51234 numaralı bağlantı noktasına) bağlanabilirsiniz ve yazdığınız her metin satırı yazdırılacaktır.

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

Biraz eğlenmek için... aşağıdaki komut dosyası birden çok eşzamanlı TCP/IP bağlantısını kabul eder ve gelen CR ile sınırlandırılmış iletileri Uzmanlar günlüğüne yazar.

... bariz olanı belirterek, yukarıdakileri bir komut dosyası yerine bir EA'da yapmak istiyorsanız, o zaman basitçe aşağıdaki gibi değiştirirsiniz:

  • Listen() çağrısına kadar tüm kodu OnStart() öğesinden EA'nın OnInit() öğesine taşıyın
  • OnInit()'in sonunda yüksek frekanslı bir zamanlayıcı ayarlayın, örneğin EventSetMillisecondTimer(10)
  • Kalan kodu OnStart()'tan OnTimer()'a taşıyın, dıştaki "while (!IsStopped()) {}" döngüsünü kaldırın
Bir not ekleyeceğim - bu, çok yeni MT4 yapılarında düzeltilmediği sürece - EventSetTimer() ve EventSetMillisecondTimer(), MT4 platformu zaten bir çizelgeye eklenmiş bir EA ile başlatılırken OnInit() içinde kullanılırsa başarısız olabilir. Tecrübelerime göre dönüş değerlerini kontrol etmek gerekiyor; yeniden dene; ve OnInit() içinde oluşturma girişimleri başarısız olursa, potansiyel olarak ilk OnTick() üzerinde zamanlayıcıyı kurmaya geri dönün.
Neden: