MT4のログファイルを監視してエラーがあったら通知したい

タイトルの通り、MT4のエラー内容を定期的にチェックして通知するシステムが欲しいなと前々から思ってました。
そこで今週から新しく「NotificationMT4Error」リポジトリを作成して開発をスタートさせました。(ちなみにまだ未完成)

概要

今回ターゲットにするのは、MT4のターミナルのエキスパートタブに表示されるエラー内容。 ここにはEAやインジケーターが出力した内容や、発注時のエラー情報が表示されます。
そしてこの出力内容は、データフォルダのMQL4 -> Logsフォルダの中に保存されています。
このログファイルの中身を読み込んで、エラーがあったら通知するインジケーターを作成します。

問題点

ログファイルを読み込む際に問題があります。
MQL4では基本的に、データフォルダのFilesフォルダ内のファイルしか操作ができません。
ログファイルはLogsフォルダの中にあるため、このままではファイルを移動させたり、中身を取得することができないのです。

解決方法

まず私はKernel32.dllのMoveFileEx関数を使用して、LogsフォルダからFilesフォルダへとログファイルを移せないか試しました。
しかしこの方法だと、過去のログファイルは移動可能でしたか、当日分のログファイルは移動できませんでした。
これはMT4がログを書き込むために、現在進行形でログファイルを開いていることが原因のようです。

そこで次に試したのがKernel32.dllのCopyFile関数です。
移動させるのではなく、Filesフォルダの中にコピーを作成しようとしました。
この方法は無事成功しました。
当日分のファイルも問題なくコピーすることが可能です。

まだ開発途中ですが、LogsフォルダからFilesフォルダへログファイルを移動して中身を読み込むサンプルです。

#import "Kernel32.dll"
   bool CopyFileW(string lpExistingFileName, // 既存のファイルの名前
                 string lpNewFileName,      // 新しいファイルの名前
                 bool   bFailIfExists);     // ファイルが存在する場合の動作
#import

void OnTimer()
{
   string data_path = TerminalInfoString(TERMINAL_DATA_PATH);
   string log_file = data_path + "\\MQL4\\Logs\\20171215.log";
   string destination = data_path + "\\MQL4\\Files\\NotificationMT4Error\\20171215.log";

   if(!CopyFileW(log_file, destination, false)) {
      return;
   }

   string rows[]; 
   string body = "";
   Read("NotificationMT4Error\\20171215.log", rows);

   for(int i = 0; i < ArraySize(rows); i++) {
      body = rows[i] + "\n" + body;
   }
   Comment(body);
}

void Read(const string path, string &rows[])
{
   int    str_size;
   int    handle = FileOpen(path, FILE_READ|FILE_CSV);
   int    count  = 0;

   if(handle == INVALID_HANDLE) return;

   while(!FileIsEnding(handle)) {
      str_size  = FileReadInteger(handle, INT_VALUE);
      ArrayResize(rows, count + 1);
      rows[count] = FileReadString(handle, str_size);
      count++;
   }

   if(handle != INVALID_HANDLE) FileClose(handle);
}

今後の作業

現在はコピーするファイル名がコードに書き込まれているので、日付から動的に生成できるよう改良が必要です。
ログファイルの中身を一行ずつ配列に格納して取得するところまではできているので、一行ずつチェックしてエラーがあれば通知する処理を追加します。

来週中には完成させる予定です。

arrow_upward