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

MQL5共通関数はPrint・Alert・Sleep・型変換・WebRequestなどEA開発の基盤となる関数群だ。ログ出力からエラー処理・外部通知まで、コード付きで全関数を網羅する。

MQL5 共通関数 リファレンスカード
目次

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

共通関数は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," ptn","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 Alertn""================n""Action: %sn""Symbol: %sn""Lot: %.2fn""Price: %.5fn""Time: %sn",
      action, _Symbol, lot, price,
      TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS));

   if(profit != 0)
      body += StringFormat("Profit: %.2fn", 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/jsonrn";
   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/jsonrn"
                  +"Authorization: Bearer" + apiKey +"rn";

   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一覧

まとめ

MQL5の共通関数はEA開発の基盤です。Print/PrintFormatでログを整備し、GetLastError+ResetLastErrorのペアでエラーを確実に処理しましょう。型変換はDoubleToString/StringToDoubleで統一するのが保守しやすい。WebRequestやSendNotificationを使えば外部連携も実装できます。MQL4からの移行は関数名がほぼ共通なので、書式の違いに注意しながら進めてください。

MQL5共通関数 よくある質問

MQL5の共通関数にはどんなものがありますか?

Print()でログ出力、Alert()でダイアログ通知、Comment()でチャート表示、Sleep()で待機が基本です。MQL4との違いとしてPrintFormat()が追加され、書式指定が容易になりました。GetLastError()/ResetLastError()のペアでエラー処理も強化されています。

MQL5の型変換関数はどう使いますか?

数値→文字列はDoubleToString()/IntegerToString()、文字列→数値はStringToDouble()/StringToInteger()を使います。MQL4のDoubleToStr()に相当します。NormalizeDouble()も健在で、小数点以下の桁数を揃えるのに必須です。キャスト(int)/(double)も使えます。

GetLastError()はどう使えばいいですか?

取引関数など失敗する可能性がある処理の直後に呼び出します。ResetLastError()で事前にリセットしてから処理し、失敗時にGetLastError()でエラーコードを取得するのが正しいパターンです。エラーコードはErrorDescription()で文字列に変換できます。

MQL4とMQL5の共通関数の主な違いは?

関数名の大半は共通です。MQL5ではPrintFormat()の追加、GetMicrosecondCount()による高精度タイマー、WebRequestのオーバーロード追加が目立つ変更点です。MQL4のDoubleToStr()はDoubleToString()に統合されています。

デバッグに便利なMQL5関数は?

PrintFormat()で構造化ログ、Comment()でチャートにリアルタイム表示、DebugBreak()でデバッガ停止が役立ちます。__FUNCTION__や__LINE__マクロと組み合わせるとエラー発生箇所を素早く特定できます。GetMicrosecondCount()でパフォーマンス計測も可能です。

WebRequestはどう設定すれば使えますか?

MT5のツール→オプション→エキスパートアドバイザーで「WebRequestを許可するURLリスト」に接続先URLを追加する必要があります。追加しないとERR_FUNCTION_NOT_ALLOWED(4014)が返ります。HTTP/HTTPSどちらも対応しており、POSTリクエストも送信できます。

MQL5リファレンス 関連記事

シストレ.COM編集部|200種類以上のEAをフォワード計測する運営3年の検証メディア。MetaTrader (MT4/MT5) を実運用してきた編集部が監修・執筆しています。

⚠ リスクに関する注意事項

本記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。FX取引はレバレッジ取引の特性上、預託した証拠金以上の損失が生じる可能性があります。取引の際は、ご自身の判断と責任において行ってください。詳しくは特定商取引法に基づく表記をご確認ください。

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

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

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

この記事を書いた人

シストレ.COM編集部は、FX自動売買(EA)とテクニカル分析を専門とするインターネットメディア「シストレ.COM」の編集チームです。200本以上のEAのフォワードテスト結果を公開し、実際の運用データに基づいた客観的な情報を発信しています。記事の執筆・監修はMetaTrader(MT4/MT5)での実運用経験を持つスタッフが担当。

目次