#property strict#property show_inputs
// ---------------------------------------------------------------------// User-configurable parameters// ---------------------------------------------------------------------inputint 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 socketclass 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 socketint ServerSocket;
// List of currently connected clients
Connection * Clients[];
// ---------------------------------------------------------------------// Entry point // ---------------------------------------------------------------------voidOnStart()
{
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 modeif (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 discardedif (Clients[i].ReadAnyPendingData()) {
// Socket still seems to be alive
} else {
// Socket appears to be dead. Delete, and remove from listPrint("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// ---------------------------------------------------------------------voidOnDeinit(constint 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 handleint mSocket;
// Temporary buffer used to handle incoming datauchar 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() {returnIntegerToString(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 socketint 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 connectionstring 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 logPrint("#" , 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");
}
returntrue;
} else {
// recv() failed. Assume socket is deadreturnfalse;
}
} elseif (selres == -1) {
// Assume socket is deadreturnfalse;
} else {
// No pending datareturntrue;
}
}
本当です。ありがとう。覚えてませんでした。私はほとんど即座に実行される注文を必要とするので、実際にはそれは問題を完全に解決するものではありません(そして、この方法では、私はそれを1秒ごとにチェックすることができると思いますが、少なくとも毎ティックではありません)、確かに私はそれを使って簡単に一時的なソリューションを構築することができます。
OnTimerはシステムクロックに合わせた最も速いレート、つまり15ms毎ですが、私は1ms間隔でループさせることを希望します(ループ内でSleep(1)を使用)。
OnTimerはシステムクロックに合わせた最も速いレート、つまり15ms毎ですが、私は1ms間隔でループさせることを希望します(ループ内でSleep(1)を使用します)。
それは問題ないでしょうか?つまり、MT4の内部処理で、何週間も(EAを)止めずにループさせているうちに、内部バッファがオーバーフローしたり、オーバーサイズになったりしないように、OnTick()を実行する必要があるようなものはないのでしょうか?
私は無知なので、それが問題になりうるかどうか全くわかりません。
ということは、問題ないとお考え(/試された)のでしょうか?(もしそうなら、それらは素晴らしいニュースです)。
ところで、OnTimer() を1秒以下の間隔で実行させるにはどうしたらいいのでしょうか?
数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への 影響を非常に軽くするために満足のいくものです。
タイマーの設定は、millisを受け取ります。
数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への影響を非常に軽くするために満足のいくものです。
タイマーの設定は、millisを受け取ります。
ところで、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アプリケーションのキューに追加されません。
イベントセットミリセコンドタイマー
この関数は、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で直接戦略をコーディングして、できるだけ低遅延にすべきなのです。
編集部
EDIT: モデレーターがいるので便乗します。Nミリ秒ごとにOnTimer()を実行することと、以前の投稿にあるようにNミリ秒ごとに同じループを実行することの間に違いが存在するかどうか知っていますか?
私はモデレーターだからといって、他の人より知識があるというわけではありません。実際、このスレッドの他の投稿者は、明らかにこのテーマについて私よりも多くの知識を持っています。私はJavaについて何も知りません。
タイマイベントでSleep() を使用するとEAが停止してしまい、OnTick()イベントを大量に逃してしまうので、意味がわかりません。もちろん、EAによっては、OnTickイベントは重要でない場合もあります。
数年前までは、init()で始まるループでEAを動かしていました。その時は副作用もなく何週間も実行できたものです。Sleep(1)は、計算機への影響を非常に軽くするために満足のいくものです。
ちょっと面白いのは、次のスクリプトが複数のTCP/IP接続を同時に受け付け、受信したCR区切りのメッセージをExpertsログに書き込むことです。例えば、このスクリプトを実行すると、Telnet(デフォルトではポート51234)で接続し、入力したテキストが1行ずつ出力されます。
ちょっと面白いのは、次のスクリプトが複数の同時 TCP/IP 接続を受け入れ、受信した CR 区切りのメッセージを Experts ログに書き込むことです。
もし、上記のことをスクリプトではなくEAで行いたいのであれば、以下のように変更すればよいでしょう。