MQL5の共通関数・変換関数を完全網羅。Print・Alert・Sleep・型変換・GetLastError・WebRequestなど、EA開発で使うすべての汎用関数をコード付きで解説します。デバッグログ、パフォーマンス計測、メール/プッシュ通知、Web API連携まで、実践的なパターンを豊富に紹介。MQL4との違いも併記しています。
共通関数・変換関数の基礎知識
共通関数はEA開発の基盤となる機能群です。ログ出力、エラー処理、型変換、外部通信など、あらゆるEAで使用する不可欠な関数が含まれています。
MQL4とMQL5の共通関数の違い
| 項目 | MQL4 | MQL5 |
|---|---|---|
| 対応 | 対応(同じ) | |
| PrintFormat | 対応(ビルド600+) | 対応(printf相当) |
| Alert | 対応 | 対応(同じ) |
| Comment | 対応 | 対応(同じ) |
| MessageBox | 対応 | 対応 |
| SendNotification | 対応(ビルド600+) | 対応 |
| WebRequest | 対応(制限あり) | 対応(2つのオーバーロード) |
| GetMicrosecondCount | 対応 | 対応(高精度タイマー) |
| EnumToString | 対応 | 対応 |
| DebugBreak | 対応 | 対応 |
| ExpertRemove | 対応 | 対応 |
Print / PrintFormat — ログ出力
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);
}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();
}共通関数・変換関数 一覧リファレンス
| 関数 | 機能 | MQL4 | MQL5 |
|---|---|---|---|
| ログ出力 | 対応 | 対応 | |
| PrintFormat | 書式付きログ出力 | 対応(600+) | 対応 |
| Alert | アラートダイアログ | 対応 | 対応 |
| Comment | チャートコメント | 対応 | 対応 |
| MessageBox | メッセージボックス | 対応 | 対応 |
| Sleep | 処理の一時停止 | 対応 | 対応 |
| ExpertRemove | EAの自己停止 | 対応 | 対応 |
| GetLastError | エラーコード取得 | 対応 | 対応 |
| ResetLastError | エラーリセット | 対応 | 対応 |
| GetTickCount | ミリ秒カウンタ | 対応 | 対応 |
| GetMicrosecondCount | マイクロ秒カウンタ | 対応 | 対応 |
| DoubleToString | double→文字列 | DoubleToStr | 対応 |
| IntegerToString | 整数→文字列 | 対応 | 対応 |
| StringToDouble | 文字列→double | StrToDouble | 対応 |
| StringToInteger | 文字列→整数 | StrToInteger | 対応 |
| EnumToString | 列挙値→文字列 | 対応 | 対応 |
| ColorToString | 色→文字列 | 対応 | 対応 |
| StringToColor | 文字列→色 | 対応 | 対応 |
| SendNotification | プッシュ通知 | 対応(600+) | 対応 |
| SendMail | メール送信 | 対応 | 対応 |
| WebRequest | HTTP通信 | 対応(制限あり) | 対応 |
| DebugBreak | デバッガー停止 | 対応 | 対応 |
| IsStopped | 停止要求確認 | 対応 | 対応 |
| UninitializeReason | 終了理由取得 | 対応 | 対応 |
| TerminalClose | ターミナル終了 | 対応 | 対応 |
- PrintFormatで統一されたフォーマットのログを出力し、デバッグ効率を向上
- GetLastError+ResetLastErrorのペアでエラーを確実にキャッチ
- GetMicrosecondCountでマイクロ秒精度のパフォーマンス計測が可能
- WebRequestで外部API連携(URL許可リストの設定を忘れずに)
- SendNotificationでスマホにリアルタイム取引通知を送信
プロが開発したEAをお探しの方は → シストレ.COM EA一覧





