MQL5 共通関数・変換関数 完全ガイド|Print・Alert・Sleep・型変換・エラー取得

MQL5の共通関数・変換関数を完全網羅。Print・Alert・Sleep・型変換・GetLastError・WebRequestなど、EA開発で使うすべての汎用関数をコード付きで解説します。デバッグログ、パフォーマンス計測、メール/プッシュ通知、Web API連携まで、実践的なパターンを豊富に紹介。MQL4との違いも併記しています。

目次

共通関数・変換関数の基礎知識

共通関数はEA開発の基盤となる機能群です。ログ出力、エラー処理、型変換、外部通信など、あらゆるEAで使用する不可欠な関数が含まれています。

MQL4とMQL5の共通関数の違い

項目MQL4MQL5
Print対応対応(同じ)
PrintFormat対応(ビルド600+)対応(printf相当)
Alert対応対応(同じ)
Comment対応対応(同じ)
MessageBox対応対応
SendNotification対応(ビルド600+)対応
WebRequest対応(制限あり)対応(2つのオーバーロード)
GetMicrosecondCount対応対応(高精度タイマー)
EnumToString対応対応
DebugBreak対応対応
ExpertRemove対応対応

EA開発で最も頻繁に使用する関数です。エキスパートタブ(ログ)にメッセージを出力します。

void Print(
   ...  // 任意の数の引数(自動的に文字列に変換される)
);

void PrintFormat(
   string  format_string,  // 書式文字列(printf形式)
   ...                     // 引数
);
// PrintFormat()はStringFormat()の結果をPrint()するのと同等

// 基本的なPrint
Print("Hello MQL5");
Print("Bid=", SymbolInfoDouble(_Symbol, SYMBOL_BID));
Print("複数の値: ", 123, " ", 45.67, " ", true, " ", TimeCurrent());

// PrintFormatで書式付き出力
PrintFormat("Symbol=%s Bid=%.5f Ask=%.5f Spread=%d",
            _Symbol,
            SymbolInfoDouble(_Symbol, SYMBOL_BID),
            SymbolInfoDouble(_Symbol, SYMBOL_ASK),
            (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));

// 書式指定子の一覧
// %s  = 文字列
// %d  = 整数(10進数)
// %u  = 符号なし整数
// %f  = 浮動小数点
// %.Nf = 小数点以下N桁
// %e  = 指数表記
// %I64d = long型整数
// %I64u = ulong型整数
// %%  = %文字そのもの
// パターン1: 取引ログ
void LogTrade(string action, ulong ticket, double price, double lot)
  {
   PrintFormat("[TRADE] %s Ticket=%I64u Symbol=%s Price=%.5f Lot=%.2f",
               action, ticket, _Symbol, price, lot);
  }

// パターン2: エラーログ
void LogError(string context, int errorCode)
  {
   PrintFormat("[ERROR] %s: code=%d (%s)",
               context, errorCode,
               errorCode == 0 ? "No error" : IntegerToString(errorCode));
  }

// パターン3: デバッグログ(条件付き)
input bool DebugMode = false;

void LogDebug(string message)
  {
   if(DebugMode)
      PrintFormat("[DEBUG] %s | %s", TimeToString(TimeCurrent(), TIME_SECONDS), message);
  }

// パターン4: 構造体の出力
void LogPosition(ulong ticket)
  {
   if(!PositionSelectByTicket(ticket)) return;

   PrintFormat("=== Position #%I64u ===", ticket);
   PrintFormat("  Symbol:  %s", PositionGetString(POSITION_SYMBOL));
   PrintFormat("  Type:    %s", PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? "Buy" : "Sell");
   PrintFormat("  Volume:  %.2f", PositionGetDouble(POSITION_VOLUME));
   PrintFormat("  Open:    %.5f", PositionGetDouble(POSITION_PRICE_OPEN));
   PrintFormat("  Current: %.5f", PositionGetDouble(POSITION_PRICE_CURRENT));
   PrintFormat("  SL:      %.5f", PositionGetDouble(POSITION_SL));
   PrintFormat("  TP:      %.5f", PositionGetDouble(POSITION_TP));
   PrintFormat("  Profit:  %.2f", PositionGetDouble(POSITION_PROFIT));
   PrintFormat("  Swap:    %.2f", PositionGetDouble(POSITION_SWAP));
  }

OnTick()内で毎ティックPrint()を呼ぶと、ログファイルが急速に肥大化し、パフォーマンスにも影響します。本番運用では重要なイベント時のみログを出力するようにしてください。デバッグ用のログはinput bool DebugModeで切り替え可能にするのがベストプラクティスです。

Alert — アラートダイアログ

void Alert(
   ...  // 任意の数の引数
);

// 音声付きダイアログで通知(ユーザーに即座に気付かせたい場合)
Alert("重要: ", _Symbol, " でストップロスに到達しました");
Alert("注文約定: Buy ", 0.1, " lots @ ", 1.12345);

// Alert連打を防止するパターン
datetime lastAlertTime = 0;
void SafeAlert(string message, int cooldownSeconds = 300)
  {
   if(TimeCurrent() - lastAlertTime < cooldownSeconds) return;
   lastAlertTime = TimeCurrent();
   Alert(message);
  }

Alert()はアラートウィンドウを表示し、音を鳴らします。バックテスト中は動作しません(無視されます)。頻繁に呼ぶとユーザーの操作を妨げるため、重要なイベント(取引成立・大きな損失等)のみに使用してください。

Comment — チャートコメント表示

void Comment(
   ...  // 任意の数の引数
);

// チャート左上にリアルタイム情報を表示
void OnTick()
  {
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);

   Comment(
      "=== MyEA v2.0 ===\n",
      "Symbol: ", _Symbol, "\n",
      "Bid: ", DoubleToString(bid, _Digits), "\n",
      "Ask: ", DoubleToString(ask, _Digits), "\n",
      "Spread: ", spread, " pt\n",
      "Time: ", TimeToString(TimeCurrent(), TIME_SECONDS)
   );
  }

// コメントをクリア
void OnDeinit(const int reason)
  {
   Comment("");  // 空文字列でクリア
  }

MessageBox — メッセージボックス

int MessageBox(
   string  text,             // 本文
   string  caption = NULL,   // タイトル
   int     flags = 0         // フラグ(ボタンの種類)
);
// 戻り値: IDYES, IDNO, IDOK, IDCANCEL, IDABORT, IDRETRY, IDIGNORE

// フラグ例
// MB_OK           - OKボタンのみ
// MB_OKCANCEL     - OK/キャンセル
// MB_YESNO        - はい/いいえ
// MB_YESNOCANCEL  - はい/いいえ/キャンセル
// MB_ICONWARNING  - 警告アイコン
// MB_ICONERROR    - エラーアイコン
// MB_ICONQUESTION - 質問アイコン

// 確認ダイアログ
int result = MessageBox("全ポジションを決済しますか?",
                        "確認", MB_YESNO | MB_ICONQUESTION);
if(result == IDYES)
  {
   Print("ユーザーが決済を承認しました");
   // 全決済処理...
  }

// 警告ダイアログ
MessageBox("証拠金が不足しています。ロットサイズを減らしてください。",
           "警告", MB_OK | MB_ICONWARNING);
重要

MessageBox()はユーザーが応答するまでEAの処理をブロックします。OnTick()内で使用すると、ダイアログが表示されている間ティックの処理が停止します。緊急の確認以外ではOnTimer()やOnChartEvent()内で使用してください。バックテスト中は動作しません。

Sleep — 処理の一時停止

void Sleep(
   int  milliseconds  // 停止時間(ミリ秒)
);

// 注文リトライパターン
bool PlaceOrderWithRetry(int retries = 3)
  {
   for(int i = 0; i < retries; i++)
     {
      // ... 注文処理 ...
      MqlTradeResult result;
      MqlTradeRequest request;
      // ... request設定 ...

      if(OrderSend(request, result))
        {
         if(result.retcode == TRADE_RETCODE_DONE)
            return true;
        }

      int error = GetLastError();
      PrintFormat("注文リトライ %d/%d: error=%d", i + 1, retries, error);

      // リクオート等の一時的エラーの場合はリトライ
      if(result.retcode == TRADE_RETCODE_REQUOTE || result.retcode == TRADE_RETCODE_TIMEOUT)
         Sleep(500);  // 500ms待機
      else
         break;  // 永続的エラーは即座に中止
     }
   return false;
  }

// CopyBuffer待機パターン
bool WaitForIndicator(int handle, int bufferNum, int count, double &buffer[])
  {
   ArraySetAsSeries(buffer, true);
   for(int i = 0; i < 10; i++)  // 最大10回リトライ
     {
      if(CopyBuffer(handle, bufferNum, 0, count, buffer) >= count)
         return true;
      Sleep(100);  // 100ms待機
     }
   return false;
  }

Sleep()はEAの処理を完全に停止します。OnTick()内で長時間のSleepを使うと、ティックを取りこぼします。スクリプトでは自由に使えますが、EA/インジケーターでは短時間(100〜500ms)に限定してください。バックテスト中のSleep()は無視されます。

ExpertRemove — EAの自己停止

void ExpertRemove();
// EAをチャートから削除する(OnDeinitが呼ばれる)

// 使用例: 致命的エラー時にEAを停止
void OnTick()
  {
   // 口座残高チェック
   if(AccountInfoDouble(ACCOUNT_BALANCE) < 1000)
     {
      Alert("口座残高が最低額を下回りました。EAを停止します。");
      ExpertRemove();
      return;  // ExpertRemove後も現在のOnTick()は最後まで実行される
     }

   // 最大ドローダウンチェック
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double drawdownPct = (balance - equity) / balance * 100;

   if(drawdownPct > 20)  // 20%超のドローダウン
     {
      Alert("ドローダウンが20%を超えました。EAを停止します。");
      ExpertRemove();
     }
  }

GetLastError / ResetLastError — エラー処理

int GetLastError();       // 最後のエラーコードを取得
void ResetLastError();    // エラーコードをリセット

// 基本的なエラーチェック
void OnTick()
  {
   ResetLastError();  // 事前にリセット

   double buffer[];
   ArraySetAsSeries(buffer, true);
   int copied = CopyBuffer(maHandle, 0, 0, 10, buffer);

   if(copied < 10)
     {
      int err = GetLastError();
      PrintFormat("CopyBuffer失敗: copied=%d error=%d", copied, err);
      return;
     }
  }

// エラーコードを人間が読める文字列に変換
string ErrorDescription(int errorCode)
  {
   switch(errorCode)
     {
      case 0:     return "No error";
      case 4001:  return "Unexpected internal error";
      case 4002:  return "Wrong internal parameter";
      case 4003:  return "Invalid parameter when calling function";
      case 4004:  return "Not enough memory";
      case 4007:  return "Not enough memory for array resize";
      case 4051:  return "Invalid function parameter value";
      case 4052:  return "Internal string error";
      case 4053:  return "Array error";
      case 4101:  return "Wrong chart ID";
      case 4103:  return "Cannot open chart";
      case 4104:  return "Chart not responding";
      case 4201:  return "Cannot open file";
      case 4202:  return "Wrong file name";
      case 4203:  return "Too many files opened";
      case 10004: return "Requote";
      case 10006: return "Request rejected";
      case 10007: return "Request canceled by trader";
      case 10008: return "Order placed";
      case 10009: return "Request completed";
      case 10010: return "Only part of request completed";
      case 10013: return "Invalid request";
      case 10014: return "Invalid volume";
      case 10015: return "Invalid price";
      case 10016: return "Invalid stops";
      case 10018: return "Market closed";
      case 10019: return "Not enough money";
      case 10021: return "No price changes";
      case 10025: return "Too many requests";
      default:    return StringFormat("Unknown error (%d)", errorCode);
     }
  }

GetTickCount / GetMicrosecondCount — パフォーマンス計測

uint GetTickCount();          // ミリ秒単位のカウンタ(約49日で一周)
ulong GetMicrosecondCount();  // マイクロ秒単位のカウンタ(高精度)

// ミリ秒精度の処理時間計測
void MeasurePerformance()
  {
   uint start = GetTickCount();

   // 計測したい処理
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   CopyRates(_Symbol, PERIOD_M1, 0, 10000, rates);

   uint elapsed = GetTickCount() - start;
   PrintFormat("処理時間: %u ms", elapsed);
  }

// マイクロ秒精度の計測(高精度)
void PreciseMeasure()
  {
   ulong start = GetMicrosecondCount();

   // 計測したい処理
   for(int i = 0; i < 1000; i++)
     {
      double val = MathSqrt(MathPow(i, 2.5));
     }

   ulong elapsed = GetMicrosecondCount() - start;
   PrintFormat("処理時間: %I64u μs (%.3f ms)", elapsed, elapsed / 1000.0);
  }

// OnTick()の処理時間モニタリング
void OnTick()
  {
   ulong tickStart = GetMicrosecondCount();

   // ... EA処理 ...

   ulong tickTime = GetMicrosecondCount() - tickStart;
   if(tickTime > 10000)  // 10ms超の場合は警告
      PrintFormat("OnTick()が遅い: %I64u μs (%.1f ms)", tickTime, tickTime / 1000.0);
  }

GetMicrosecondCount()はMQL5のみの機能で、マイクロ秒(1/1,000,000秒)精度の計測が可能です。パフォーマンスチューニングやボトルネック特定に非常に有用です。GetTickCount()はMQL4でも使用可能です。

型変換関数

// double → string
string DoubleToString(double value, int digits = 8);
DoubleToString(1.23456, 3);      // "1.235"
DoubleToString(150.0, _Digits);  // "150.000"

// int/long → string
string IntegerToString(long number, int str_len = 0, ushort fill_char = ' ');
IntegerToString(42);              // "42"
IntegerToString(42, 5, '0');      // "00042"(ゼロ埋め)

// string → double
double StringToDouble(string value);
StringToDouble("1.23456");        // 1.23456
StringToDouble("abc");            // 0.0(変換失敗)

// string → int/long
long StringToInteger(string value);
StringToInteger("12345");          // 12345
StringToInteger("0xFF");           // 0(公式ドキュメントに16進対応の記載なし)

// char → string
string CharToString(uchar char_code);
CharToString(65);                  // "A"

// short → string
string ShortToString(ushort symbol_code);
ShortToString(0x30A2);            // "ア"(カタカナ)

// color → string / string → color
string ColorToString(color value, bool color_name = false);
ColorToString(clrRed);             // "255,0,0"
ColorToString(clrRed, true);       // "Red"

color StringToColor(string value);
StringToColor("255,0,0");          // clrRed
StringToColor("Red");              // clrRed

// enum → string(MQL5のみ)
// EnumToStringは任意の列挙型を受け付けます
template
string EnumToString(T value);
EnumToString(PERIOD_H1);           // "PERIOD_H1"
EnumToString(POSITION_TYPE_BUY);   // "POSITION_TYPE_BUY"
// 価格の表示用フォーマット
string FormatPrice(double price)
  {
   return DoubleToString(price, _Digits);
  }

// pips表示(小数点1桁)
string FormatPips(double points)
  {
   double pips = points / (_Digits == 3 || _Digits == 5 ? 10 : 1);
   return DoubleToString(pips, 1) + " pips";
  }

// 金額表示(通貨記号付き)
string FormatMoney(double amount)
  {
   string currency = AccountInfoString(ACCOUNT_CURRENCY);
   if(currency == "JPY")
      return IntegerToString((long)MathRound(amount)) + "円";
   else
      return DoubleToString(amount, 2) + " " + currency;
  }

// 時間のカスタム表示
string FormatDuration(int seconds)
  {
   int hours = seconds / 3600;
   int mins  = (seconds % 3600) / 60;
   int secs  = seconds % 60;

   if(hours > 0)
      return StringFormat("%dh %02dm %02ds", hours, mins, secs);
   else if(mins > 0)
      return StringFormat("%dm %02ds", mins, secs);
   else
      return StringFormat("%ds", secs);
  }

UninitializeReason / IsStopped — EA状態の確認

int UninitializeReason();  // EA終了の理由コードを取得
bool IsStopped();          // EAが停止要求を受けているか

// OnDeinitでの終了理由の取得
void OnDeinit(const int reason)
  {
   string reasonStr;
   switch(reason)
     {
      case REASON_PROGRAM:     reasonStr = "ExpertRemove()呼び出し"; break;
      case REASON_REMOVE:      reasonStr = "チャートからEAを削除"; break;
      case REASON_RECOMPILE:   reasonStr = "再コンパイル"; break;
      case REASON_CHARTCHANGE: reasonStr = "シンボルまたは時間足の変更"; break;
      case REASON_CHARTCLOSE:  reasonStr = "チャートの終了"; break;
      case REASON_PARAMETERS:  reasonStr = "パラメータの変更"; break;
      case REASON_ACCOUNT:     reasonStr = "口座の変更"; break;
      case REASON_TEMPLATE:    reasonStr = "テンプレートの適用"; break;
      case REASON_INITFAILED:  reasonStr = "OnInit()の失敗"; break;
      case REASON_CLOSE:       reasonStr = "ターミナルの終了"; break;
      default:                 reasonStr = "不明"; break;
     }
   PrintFormat("EA終了: reason=%d (%s)", reason, reasonStr);
  }

// 長い処理中の停止チェック
void LongProcess()
  {
   for(int i = 0; i < 100000; i++)
     {
      if(IsStopped())
        {
         Print("停止要求を受信。処理を中断します。");
         return;
        }
      // ... 重い処理 ...
     }
  }

SendNotification / SendMail / SendFTP — 外部通知

// プッシュ通知(スマホのMT5アプリに送信)
bool SendNotification(
   string  text  // 通知テキスト(最大255文字)
);

// メール送信
bool SendMail(
   string  subject,  // 件名
   string  body      // 本文
);

// FTPアップロード
bool SendFTP(
   string  filename,        // ファイル名
   string  ftp_path = NULL  // FTPパス
);

// 取引通知の送信
void NotifyTrade(string action, double price, double lot, double profit = 0)
  {
   // プッシュ通知
   string msg = StringFormat("[%s] %s %s %.2f lots @ %.5f",
                             TimeToString(TimeCurrent(), TIME_MINUTES),
                             action, _Symbol, lot, price);
   if(profit != 0)
      msg += StringFormat(" P/L=%.2f", profit);

   if(!SendNotification(msg))
      PrintFormat("プッシュ通知失敗: %d", GetLastError());

   // メール通知
   string subject = StringFormat("EA Trade: %s %s", action, _Symbol);
   string body = StringFormat(
      "EA Trading Alert\n"
      "================\n"
      "Action: %s\n"
      "Symbol: %s\n"
      "Lot: %.2f\n"
      "Price: %.5f\n"
      "Time: %s\n",
      action, _Symbol, lot, price,
      TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS));

   if(profit != 0)
      body += StringFormat("Profit: %.2f\n", profit);

   SendMail(subject, body);
  }
重要

SendNotification()を使うには、MT5モバイルアプリでMetaQuotes IDを取得し、ターミナルの設定で登録する必要があります。SendMail()はターミナルの「メール」タブでSMTP設定が必要です。バックテスト中はいずれも動作しません。

WebRequest — Web API連携

外部のWeb APIと通信する関数です。EA開発では、外部シグナルの取得、Webhook通知、データのアップロードなどに使用します。

// オーバーロード1: ヘッダーを文字列で指定
int WebRequest(
   const string  method,       // "GET" or "POST"
   const string  url,          // URL
   const string  headers,      // リクエストヘッダー
   int           timeout,      // タイムアウト(ミリ秒)
   const char    &data[],      // 送信データ
   char          &result[],    // 応答データ
   string        &result_headers  // 応答ヘッダー
);

// オーバーロード2: Cookie対応
int WebRequest(
   const string  method,
   const string  url,
   const string  cookie,
   const string  referer,
   int           timeout,
   const char    &data[],
   char          &result[],
   string        &result_headers
);
// 戻り値: HTTPステータスコード(200=成功、-1=エラー)
// パターン1: Webhook通知(Discord/Slack等)
bool SendWebhook(string webhookUrl, string message)
  {
   string headers = "Content-Type: application/json\r\n";
   string json = "{\"content\":\"" + message + "\"}";

   uchar data[];
   StringToCharArray(json, data, 0, WHOLE_ARRAY, CP_UTF8);
   // 末尾のNULL文字を除去
   ArrayResize(data, ArraySize(data) - 1);

   uchar result[];
   string resultHeaders;

   ResetLastError();
   int httpCode = WebRequest("POST", webhookUrl, headers, 5000, data, result, resultHeaders);

   if(httpCode == -1)
     {
      PrintFormat("WebRequest失敗: error=%d", GetLastError());
      Print("URLがターミナルの許可リストに追加されているか確認してください");
      return false;
     }

   PrintFormat("Webhook送信: HTTP %d", httpCode);
   return (httpCode >= 200 && httpCode < 300);
  }

// パターン2: REST API からデータ取得
string HttpGet(string url, int timeout = 5000)
  {
   uchar data[];
   uchar result[];
   string resultHeaders;

   int httpCode = WebRequest("GET", url, "", timeout, data, result, resultHeaders);

   if(httpCode == -1)
     {
      PrintFormat("HTTP GET失敗: %d", GetLastError());
      return "";
     }

   return CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
  }

// パターン3: 取引結果をAPIに送信
void ReportTradeToAPI(string apiUrl, string apiKey,
                      string action, double price, double lot, double profit)
  {
   string headers = "Content-Type: application/json\r\n"
                  + "Authorization: Bearer " + apiKey + "\r\n";

   string json = StringFormat(
      "{\"action\":\"%s\",\"symbol\":\"%s\",\"price\":%.5f,"
      "\"lot\":%.2f,\"profit\":%.2f,\"time\":\"%s\"}",
      action, _Symbol, price, lot, profit,
      TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS));

   uchar data[];
   StringToCharArray(json, data, 0, WHOLE_ARRAY, CP_UTF8);
   ArrayResize(data, ArraySize(data) - 1);

   uchar result[];
   string resultHeaders;

   int httpCode = WebRequest("POST", apiUrl, headers, 10000, data, result, resultHeaders);
   PrintFormat("API Report: HTTP %d", httpCode);
  }
重要

WebRequest()を使用するには、ターミナルの「ツール→オプション→エキスパートアドバイザ」で対象URLを許可リストに追加する必要があります。セキュリティ上の理由から、リストにないURLへのアクセスは全てブロックされます。また、OnTick()内でのWebRequestはティック処理をブロックするため、OnTimer()での非同期的な使用が推奨です。

DebugBreak — デバッグブレークポイント

void DebugBreak();
// MetaEditorのデバッガー使用時にブレークポイントを設定
// デバッガーが接続されていない場合は無視される

// 条件付きブレークポイント
void OnTick()
  {
   double rsi[];
   ArraySetAsSeries(rsi, true);
   if(CopyBuffer(rsiHandle, 0, 0, 1, rsi) < 1) return;

   // RSIが極端な値の時にデバッガーで停止
   if(rsi[0] > 90 || rsi[0] < 10)
      DebugBreak();  // デバッガーで変数を確認可能
  }

TerminalClose — ターミナルの終了

bool TerminalClose(int ret_code);  // ターミナルを終了させる

// 緊急停止(マージンコール対策等)
void EmergencyShutdown()
  {
   // まず全ポジションを決済
   // ... 決済処理 ...

   Alert("緊急停止: ターミナルを終了します");
   TerminalClose(0);  // 終了コード0で正常終了
  }

実践パターン:EA開発での活用

パターン1:包括的なログシステム

enum ENUM_LOG_LEVEL { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };

input ENUM_LOG_LEVEL  InpLogLevel  = LOG_INFO;
input bool            InpLogToFile = true;
input bool            InpNotify    = true;

class CLogger
  {
private:
   ENUM_LOG_LEVEL    m_level;
   bool              m_toFile;
   bool              m_notify;
   int               m_fileHandle;
   string            m_eaName;

   string LevelStr(ENUM_LOG_LEVEL level)
     {
      switch(level)
        {
         case LOG_TRACE: return "TRACE";
         case LOG_DEBUG: return "DEBUG";
         case LOG_INFO:  return "INFO ";
         case LOG_WARN:  return "WARN ";
         case LOG_ERROR: return "ERROR";
         case LOG_FATAL: return "FATAL";
         default:        return "?????";
        }
     }

public:
                     CLogger(string eaName, ENUM_LOG_LEVEL level,
                             bool toFile, bool notify)
                     : m_eaName(eaName), m_level(level),
                       m_toFile(toFile), m_notify(notify), m_fileHandle(INVALID_HANDLE)
     {
      if(m_toFile)
        {
         MqlDateTime dt;
         TimeCurrent(dt);
         string filename = StringFormat("%s_%04d%02d%02d.log",
                                        m_eaName, dt.year, dt.mon, dt.day);
         m_fileHandle = FileOpen(filename,
                                 FILE_WRITE | FILE_READ | FILE_TXT |
                                 FILE_SHARE_READ | FILE_ANSI);
         if(m_fileHandle != INVALID_HANDLE)
            FileSeek(m_fileHandle, 0, SEEK_END);
        }
     }

                    ~CLogger()
     {
      if(m_fileHandle != INVALID_HANDLE)
         FileClose(m_fileHandle);
     }

   void              Log(ENUM_LOG_LEVEL level, string message)
     {
      if(level < m_level) return;

      string line = StringFormat("[%s] [%s] [%s] %s",
                                 TimeToString(TimeCurrent(), TIME_SECONDS),
                                 LevelStr(level), _Symbol, message);

      Print(line);

      if(m_toFile && m_fileHandle != INVALID_HANDLE)
        {
         FileWriteString(m_fileHandle, line + "\n");
         if(level >= LOG_WARN) FileFlush(m_fileHandle);
        }

      if(m_notify && level >= LOG_ERROR)
         SendNotification(line);
     }

   void Trace(string msg) { Log(LOG_TRACE, msg); }
   void Debug(string msg) { Log(LOG_DEBUG, msg); }
   void Info(string msg)  { Log(LOG_INFO, msg); }
   void Warn(string msg)  { Log(LOG_WARN, msg); }
   void Error(string msg) { Log(LOG_ERROR, msg); }
   void Fatal(string msg) { Log(LOG_FATAL, msg); Alert(msg); }
  };

// 使用例
CLogger *logger;

int OnInit()
  {
   logger = new CLogger("MyEA_v2", InpLogLevel, InpLogToFile, InpNotify);
   logger.Info("EA started on " + _Symbol);
   return INIT_SUCCEEDED;
  }

void OnTick()
  {
   logger.Debug(StringFormat("Bid=%.5f Spread=%d",
                SymbolInfoDouble(_Symbol, SYMBOL_BID),
                (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)));
  }

void OnDeinit(const int reason)
  {
   logger.Info(StringFormat("EA stopped: reason=%d", reason));
   delete logger;
  }

パターン2:パフォーマンスプロファイラー

class CProfiler
  {
private:
   string            m_names[];
   ulong             m_starts[];
   ulong             m_totals[];
   int               m_counts[];
   int               m_size;

   int FindOrCreate(string name)
     {
      for(int i = 0; i < m_size; i++)
         if(m_names[i] == name) return i;

      m_size++;
      ArrayResize(m_names, m_size);
      ArrayResize(m_starts, m_size);
      ArrayResize(m_totals, m_size);
      ArrayResize(m_counts, m_size);
      m_names[m_size-1] = name;
      m_totals[m_size-1] = 0;
      m_counts[m_size-1] = 0;
      return m_size - 1;
     }

public:
                     CProfiler() : m_size(0) {}

   void              Start(string name)
     {
      int idx = FindOrCreate(name);
      m_starts[idx] = GetMicrosecondCount();
     }

   void              Stop(string name)
     {
      int idx = FindOrCreate(name);
      m_totals[idx] += GetMicrosecondCount() - m_starts[idx];
      m_counts[idx]++;
     }

   void              Report()
     {
      Print("=== Performance Report ===");
      for(int i = 0; i < m_size; i++)
        {
         double avgUs = m_counts[i] > 0 ? (double)m_totals[i] / m_counts[i] : 0;
         PrintFormat("  %-20s: total=%.1f ms  avg=%.1f us  calls=%d",
                     m_names[i], m_totals[i] / 1000.0, avgUs, m_counts[i]);
        }
     }
  };

CProfiler profiler;

void OnTick()
  {
   profiler.Start("OnTick_Total");

   profiler.Start("CopyBuffer");
   double ma[];
   ArraySetAsSeries(ma, true);
   CopyBuffer(maHandle, 0, 0, 100, ma);
   profiler.Stop("CopyBuffer");

   profiler.Start("Logic");
   // ... ロジック処理 ...
   profiler.Stop("Logic");

   profiler.Stop("OnTick_Total");
  }

void OnDeinit(const int reason)
  {
   profiler.Report();
  }

共通関数・変換関数 一覧リファレンス

関数機能MQL4MQL5
Printログ出力対応対応
PrintFormat書式付きログ出力対応(600+)対応
Alertアラートダイアログ対応対応
Commentチャートコメント対応対応
MessageBoxメッセージボックス対応対応
Sleep処理の一時停止対応対応
ExpertRemoveEAの自己停止対応対応
GetLastErrorエラーコード取得対応対応
ResetLastErrorエラーリセット対応対応
GetTickCountミリ秒カウンタ対応対応
GetMicrosecondCountマイクロ秒カウンタ対応対応
DoubleToStringdouble→文字列DoubleToStr対応
IntegerToString整数→文字列対応対応
StringToDouble文字列→doubleStrToDouble対応
StringToInteger文字列→整数StrToInteger対応
EnumToString列挙値→文字列対応対応
ColorToString色→文字列対応対応
StringToColor文字列→色対応対応
SendNotificationプッシュ通知対応(600+)対応
SendMailメール送信対応対応
WebRequestHTTP通信対応(制限あり)対応
DebugBreakデバッガー停止対応対応
IsStopped停止要求確認対応対応
UninitializeReason終了理由取得対応対応
TerminalCloseターミナル終了対応対応
  • PrintFormatで統一されたフォーマットのログを出力し、デバッグ効率を向上
  • GetLastError+ResetLastErrorのペアでエラーを確実にキャッチ
  • GetMicrosecondCountでマイクロ秒精度のパフォーマンス計測が可能
  • WebRequestで外部API連携(URL許可リストの設定を忘れずに)
  • SendNotificationでスマホにリアルタイム取引通知を送信

プロが開発したEAをお探しの方は → シストレ.COM EA一覧

シストレ.COMで実績のあるEAが使い放題!/
無料会員登録はこちら
FX自動売買でEAを探すなら
シストレ.COM
実績あるEAが無料
厳格な審査を乗り越えた実績のあるEAが無料で使えます!
自由な口座選び
有料版を購入し柔軟な口座選びが可能!
フォワードテスト公開
全EAのフォワードテスト結果を公開中!
FX初心者も安心
初心者の方も安心して取引を始められます。
多様なEA選択肢
様々な種別のEAをご用意!自分の手法にあった取引が可能です。
信頼のFX会社と提携
人気のFX会社と提携中!様々なFX会社から選べます。
1分で登録完了!EA探すならシストレ.COM!/
無料会員登録はこちら
【FX自動売買】システムトレード完全ガイド|Forex Guide

この記事が気に入ったら
フォローしてね!

お役立ち情報をシェアする
  • URLをコピーしました!
目次