JavaからIP経由でMT4へ注文を送信 - ページ 2

 
Mariop:

本当です。ありがとう。覚えてませんでした。私はほとんど即座に実行される注文を必要とするので、実際にはそれは問題を完全に解決するものではありません(そして、この方法では、私はそれを1秒ごとにチェックすることができると思いますが、少なくとも毎ティックではありません)、確かに私はそれを使って簡単に一時的なソリューションを構築することができます。

OnTimerはシステムクロックに合わせた最も速いレート、つまり15ms毎ですが、私は1ms間隔でループさせることを希望します(ループ内でSleep(1)を使用)。

 
Ovo:

OnTimerはシステムクロックに合わせた最も速いレート、つまり15ms毎ですが、私は1ms間隔でループさせることを希望します(ループ内でSleep(1)を使用します)。

それは問題ないでしょうか?つまり、MT4の内部処理で、何週間も(EAを)止めずにループさせているうちに、内部バッファがオーバーフローしたり、オーバーサイズになったりしないように、OnTick()を実行する必要があるようなものはないのでしょうか?

私は無知なので、それが問題になりうるかどうか全くわかりません。

ということは、問題ないとお考え(/試された)のでしょうか?(もしそうなら、それらは素晴らしいニュースです)。


ところで、OnTimer() を1秒以下の間隔で実行させるにはどうしたらいいのでしょうか?

 

数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への 影響を非常に軽くするために満足のいくものです。

タイマーの設定は、millisを受け取ります。

 
Ovo:

数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への影響を非常に軽くするために満足のいくものです。

タイマーの設定は、millisを受け取ります。

特別なニュースです。すでに確認 されているのであれば、クラッシュを恐れることなく実行できますね。この問題についてあなたの経験を共有していただき、ありがとうございます。問題は解決しました。
 
Mariop:

ところで、1秒間隔以下でOnTimer()を実行させるにはどうしたらいいのでしょうか? :?


イベントセットミリセコンドタイマー

この関数は、Expert AdvisorまたはIndicatorに対して、1秒未満の間隔でタイマー イベントを発生させることをクライアント端末に指示します。

boolEventSetMillisecondTimer(
intmilliseconds// ミリ秒の数
);

パラメータ

ミリ秒

[in] タイマーイベントの頻度を定義するミリ秒の数。

戻り値

実行に成功した場合、true を返し、そうでない場合は false を返します。エラーコードを 受け取るには、GetLastError() 関数を呼び出す必要があります。

注意事項

この機能は 高解像度のタイマーが必要 な場合のために設計されて います。つまり 1秒に1回以上の頻度でタイマーを受信 する必要があります。数秒の周期を持つ従来のタイマで十分な場合は、EventSetTimer() を使用する。

通常、この関数はOnInit() 関数やクラスのコンストラクタから 呼び出す必要があります。タイマーからのイベントを処理するために、Expert Advisor やインジケータはOnTimer() 関数を持っている必要があります。

各Expert Advisorと各インジケータは、このタイマーからのイベントのみを受信する独自のタイマーで動作します。 mql4アプリケーションのシャットダウン時に、タイマーが作成され、EventKillTimer() 関数によって無効化されていない場合、タイマーは強制的に破壊されます。

各プログラムに起動できるタイマは1つだけです。各mql4アプリケーションとチャートはそれぞれ独自のイベント・キューを持ち、そこに新しく到着したすべてのイベントが配置されます。もしキューにすでにTimer イベントが含まれていたり、このイベントが処理中である場合、新しいTimerイベントはmql4アプリケーションのキューに追加されません。


 
GumRai:

イベントセットミリセコンドタイマー

この関数は、Expert AdvisorまたはIndicatorに対して、1秒未満の間隔でタイマー イベントを生成することをクライアント端末に指示します。

boolEventSetMillisecondTimer(
intmilliseconds// ミリ秒の数
);

パラメータ

ミリ秒

[タイマー・イベントの頻度を定義するミリ秒の数。

返される値

成功した場合はtrueを、失敗した場合はfalseを返します。エラーコードを 受け取るには、GetLastError() 関数を呼び出す必要があります。

注意

この機能は 高解像度のタイマーが必要な 場合のために設計 されています。つまり 、1秒に1回以上の頻度でタイマーを受信 する必要があります。数秒の周期を持つ従来のタイマで十分な場合は、EventSetTimer() を使用する。

通常、この関数はOnInit() 関数かクラスのコンストラクタで 呼び出されます。タイマーからのイベントを処理するために、Expert AdvisorやIndicatorはOnTimer() 関数を持っている必要があります。

mql4アプリケーションのシャットダウン時に、タイマーが作成され、EventKillTimer() 関数によって無効化されていない場合、タイマーは強制的に破壊されます。

1つのプログラムに対して起動できるタイマーは1つだけです。各mql4アプリケーションとチャートは、それぞれ独自のイベントキューを持ち、そこに新しく到着したすべてのイベントが配置されます。もし、キューがすでにタイマー イベントを含んでいたり、このイベントが処理中であれば、新しいタイマーイベントはmql4applicationのキューには追加されません。




詳細な説明をありがとうございました。私のミスです。(リンクはdocs.mql4.comの ドメインをforum.mql4.comと 入れ替えました.このスレッドをチェックする人がいるかもしれないので、念のため...)


EDIT: モデレーターがいるのをいいことに。Nミリ秒ごとにOnTimer()を実行するのと、以前の投稿にあるようにNミリ秒ごとに同じループを実行するのとでは、何か違いがあるかご存知でしょうか?

 

なぜ、"ms "のタイミングで大騒ぎをするのかがわかりません。よほど低遅延の ブローカー接続で、ある種の「高頻度ニューススケーラー」でもない限り、OnTimer()の 1秒間隔は、応答時間として十分すぎるほどであるべきです。

JAVAアプリの実行、IPC(LANとWAN)通信、オーダー管理の実行、ブローカーサーバーの遅延をすべて加味すると、通常のストラテジーで「ms」タイミングを使うメリットはないでしょう。

しかし、もしそれが「高頻度ニューススキャルパー」の ようなもので、ブローカーへの低遅延接続のVPSで使用するのであれば、JAVAやIPCを一切いじらず、非常にコンパクトなMQLで直接戦略をコーディングして、できるだけ低遅延にすべきなのです。

編集部

MT4とは別のデータフィード(価格、数量、タイミングが異なることが保証されている)を持つ外部アプリを使用しているということは、このような厳しい「ミリ秒」タイミングが必要であるはずがないことを示しています 1秒」のポーリング間隔が十分すぎるほどです。

OnTick() イベントは受信メッセージもチェックできるため、「1秒」は受信ティックがない場合にのみ限定されることも覚えておいてください。また、ティックの受信がない場合、そのような素早い「ms」応答を正当化できるほどの活動(ボラティリティと流動性)はありません。

物事を複雑にしないでください。K.I.S.S.の原則を忘れないでください。

 
Mariop:

EDIT: モデレーターがいるので便乗します。Nミリ秒ごとにOnTimer()を実行することと、以前の投稿にあるようにNミリ秒ごとに同じループを実行することの間に違いが存在するかどうか知っていますか?

私はモデレーターだからといって、他の人より知識があるというわけではありません。実際、このスレッドの他の投稿者は、明らかにこのテーマについて私よりも多くの知識を持っています。私はJavaについて何も知りません。

タイマイベントでSleep() を使用するとEAが停止してしまい、OnTick()イベントを大量に逃してしまうので、意味がわかりません。もちろん、EAによっては、OnTickイベントは重要でない場合もあります。

 
Ovo:

数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への影響を非常に軽くするために満足のいくものです。

ちょっと面白いのは、次のスクリプトが複数のTCP/IP接続を同時に受け付け、受信したCR区切りのメッセージをExpertsログに書き込むことです。例えば、このスクリプトを実行すると、Telnet(デフォルトではポート51234)で接続し、入力したテキストが1行ずつ出力されます。

#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ビルドで修正されていない限り、EventSetTimer()とEventSetMillisecondTimer()は、MT4プラットフォームがすでにチャートにEAを装着して起動しているときにOnInit()で使用すると失敗することがあるということを追記しておきます。私の経験では、OnInit()でタイマーを作成しようとしたが失敗した場合、戻り値をチェック し、再試行し、最初のOnTick()でタイマーを設定するようフォールバックすることが必要である。
理由: