MQL4のエラーコードを体系的にまとめました。GetLastError()・ResetLastError()によるエラー検出、取引エラー(ERR_NO_ERROR〜ERR_TRADE_ERROR)、サーバーエラー(ERR_SERVER_BUSY〜ERR_NO_CONNECTION)、ランタイムエラー、カスタムエラーの全コード一覧、コンパイルエラーの対処法、リトライ付きエラーハンドリングパターンまで、MT4 EA開発に必要なエラー処理のすべてをコード付きで解説します。
MQL4とMQL5のエラー処理の違い
| 機能 | MQL4 | MQL5 |
|---|---|---|
| エラー取得 | GetLastError() | GetLastError() |
| エラーリセット | ResetLastError() | ResetLastError() |
| 取引エラー | ERR_〇〇系定数 | TRADE_RETCODE_〇〇系定数 |
| エラーコード体系 | 0〜数千の連番 | カテゴリ別(4000番台、10000番台等) |
| 取引結果 | OrderSendの戻り値(-1=失敗) | MqlTradeResult.retcode |
MQL4のエラーハンドリングはEAの安定稼働に直結する最重要機能です。エラーを無視するとポジションの二重発注、SL/TP未設定のまま放置、証拠金不足での連続失敗など、深刻な問題が発生します。すべてのOrderSend/OrderClose/OrderModifyの後には必ずエラーチェックを入れましょう。
MQL4のエラーハンドリングはEAの安定稼働に直結する最重要機能です。エラーを無視するとポジションの二重発注、SL/TP未設定のまま放置、証拠金不足での連続失敗など、深刻な問題が発生します。すべてのOrderSend/OrderClose/OrderModifyの後には必ずエラーチェックを入れましょう。
GetLastError / ResetLastError
int GetLastError();
// 最後に発生したエラーコードを返す。呼び出し後もエラーは保持される
void ResetLastError();
// エラーコードを0(ERR_NO_ERROR)にリセットするvoid SafeOrderSend()
{
ResetLastError(); // エラーをクリア
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0,
"Test", 12345, 0, clrBlue);
if(ticket < 0)
{
int err = GetLastError();
Print("注文失敗: エラーコード=", err, " (", ErrorDescription(err), ")");
}
else
{
Print("注文成功: ticket=", ticket);
}
}取引エラーコード
| コード | 定数 | 説明 | 対処法 |
|---|---|---|---|
| 0 | ERR_NO_ERROR | エラーなし | — |
| 1 | ERR_NO_RESULT | エラーなしだが結果も不明 | OrderModifyで値が同じ場合に発生。無視可 |
| 2 | ERR_COMMON_ERROR | 一般エラー | パラメータを確認 |
| 3 | ERR_INVALID_TRADE_PARAMETERS | 無効な取引パラメータ | ロット/価格/SL/TPを確認 |
| 4 | ERR_SERVER_BUSY | サーバービジー | 数秒待ってリトライ |
| 5 | ERR_OLD_VERSION | MT4バージョンが古い | MT4をアップデート |
| 6 | ERR_NO_CONNECTION | サーバーに接続できない | 接続を確認してリトライ |
| 7 | ERR_NOT_ENOUGH_RIGHTS | 権限不足 | 口座の権限を確認 |
| 8 | ERR_TOO_FREQUENT_REQUESTS | リクエスト過多 | リクエスト間隔を空ける |
| 9 | ERR_MALFUNCTIONAL_TRADE | 取引操作が不正 | パラメータを確認 |
| 64 | ERR_ACCOUNT_DISABLED | 口座が無効 | ブローカーに連絡 |
| 65 | ERR_INVALID_ACCOUNT | 無効な口座番号 | 口座番号を確認 |
| 128 | ERR_TRADE_TIMEOUT | 取引タイムアウト | 数秒待ってリトライ |
| 129 | ERR_INVALID_PRICE | 無効な価格 | RefreshRates()して再取得 |
| 130 | ERR_INVALID_STOPS | 無効なSL/TP | MODE_STOPLEVELを確認 |
| 131 | ERR_INVALID_TRADE_VOLUME | 無効なロット数 | MINLOT/MAXLOT/LOTSTEPを確認 |
| 132 | ERR_MARKET_CLOSED | 市場が閉じている | 取引時間を確認 |
| 133 | ERR_TRADE_DISABLED | 取引が無効 | 自動売買を有効にする |
| 134 | ERR_NOT_ENOUGH_MONEY | 証拠金不足 | ロットを減らすか入金 |
| 135 | ERR_PRICE_CHANGED | 価格が変更された | RefreshRates()してリトライ |
| 136 | ERR_OFF_QUOTES | オフクオート | 数秒待ってリトライ |
| 137 | ERR_BROKER_BUSY | ブローカービジー | 数秒待ってリトライ |
| 138 | ERR_REQUOTE | リクオート | RefreshRates()してリトライ |
| 139 | ERR_ORDER_LOCKED | 注文がロックされている | しばらく待つ |
| 140 | ERR_LONG_POSITIONS_ONLY_ALLOWED | 買いのみ許可 | 口座設定を確認 |
| 141 | ERR_TOO_MANY_REQUESTS | リクエスト過多 | リクエスト間隔を空ける |
| 145 | ERR_TRADE_MODIFY_DENIED | 変更拒否(価格が近すぎる) | フリーズレベルを確認 |
| 146 | ERR_TRADE_CONTEXT_BUSY | 取引コンテキストがビジー | IsTradeContextBusy()でチェック |
| 147 | ERR_TRADE_EXPIRATION_DENIED | 有効期限が拒否された | expirationを0にする |
| 148 | ERR_TRADE_TOO_MANY_ORDERS | 注文数上限 | 既存注文を整理 |
ランタイムエラーコード
| コード | 定数 | 説明 |
|---|---|---|
| 4000 | ERR_NO_MQLERROR | MQLエラーなし |
| 4001 | ERR_WRONG_FUNCTION_POINTER | 不正な関数ポインタ |
| 4002 | ERR_ARRAY_INDEX_OUT_OF_RANGE | 配列インデックス範囲外 |
| 4003 | ERR_NO_MEMORY_FOR_CALL_STACK | コールスタックメモリ不足 |
| 4004 | ERR_RECURSIVE_STACK_OVERFLOW | 再帰スタックオーバーフロー |
| 4005 | ERR_NOT_ENOUGH_STACK_FOR_PARAM | スタック不足 |
| 4006 | ERR_NO_MEMORY_FOR_PARAM_STRING | 文字列パラメータのメモリ不足 |
| 4007 | ERR_NO_MEMORY_FOR_TEMP_STRING | 一時文字列のメモリ不足 |
| 4008 | ERR_NOT_INITIALIZED_STRING | 未初期化文字列 |
| 4009 | ERR_NOT_INITIALIZED_ARRAYSTRING | 未初期化文字列配列 |
| 4010 | ERR_NO_MEMORY_FOR_ARRAYSTRING | 文字列配列のメモリ不足 |
| 4011 | ERR_TOO_LONG_STRING | 文字列が長すぎる |
| 4012 | ERR_REMAINDER_FROM_ZERO_DIVIDE | ゼロ除算の余り |
| 4013 | ERR_ZERO_DIVIDE | ゼロ除算 |
| 4014 | ERR_UNKNOWN_COMMAND | 不明なコマンド |
| 4015 | ERR_WRONG_JUMP | 不正なジャンプ |
| 4016 | ERR_NOT_INITIALIZED_ARRAY | 未初期化配列 |
| 4017 | ERR_DLL_CALLS_NOT_ALLOWED | DLL呼び出し不許可 |
| 4018 | ERR_CANNOT_LOAD_LIBRARY | ライブラリロード失敗 |
| 4019 | ERR_CANNOT_CALL_FUNCTION | 関数呼び出し失敗 |
| 4020 | ERR_EXTERNAL_CALLS_NOT_ALLOWED | 外部呼び出し不許可 |
| 4050 | ERR_INVALID_FUNCTION_PARAMSCNT | 関数パラメータ数が不正 |
| 4051 | ERR_INVALID_FUNCTION_PARAMVALUE | 関数パラメータ値が不正 |
| 4055 | ERR_CUSTOM_INDICATOR_ERROR | カスタムインジケーターエラー |
| 4062 | ERR_STRING_PARAMETER_EXPECTED | 文字列パラメータが必要 |
| 4063 | ERR_INTEGER_PARAMETER_EXPECTED | 整数パラメータが必要 |
| 4064 | ERR_DOUBLE_PARAMETER_EXPECTED | 浮動小数点パラメータが必要 |
| 4066 | ERR_ARRAY_AS_PARAMETER_EXPECTED | 配列パラメータが必要 |
| 4099 | ERR_END_OF_FILE | ファイル終端 |
| 4100 | ERR_SOME_FILE_ERROR | ファイルエラー |
| 4101 | ERR_WRONG_FILE_NAME | ファイル名が不正 |
| 4102 | ERR_TOO_MANY_OPENED_FILES | 開いているファイルが多すぎる |
| 4103 | ERR_CANNOT_OPEN_FILE | ファイルを開けない |
| 4104 | ERR_INCOMPATIBLE_FILEACCESS | ファイルアクセスモードが不適合 |
| 4105 | ERR_NO_ORDER_SELECTED | 注文が選択されていない |
| 4106 | ERR_UNKNOWN_SYMBOL | 不明な通貨ペア |
| 4107 | ERR_INVALID_PRICE_PARAM | 価格パラメータが不正 |
| 4108 | ERR_INVALID_TICKET | チケット番号が不正 |
| 4109 | ERR_TRADE_NOT_ALLOWED | 取引不許可 |
| 4110 | ERR_LONGS_NOT_ALLOWED | 買い注文不許可 |
| 4111 | ERR_SHORTS_NOT_ALLOWED | 売り注文不許可 |
ErrorDescription関数
string ErrorDescription(int errorCode)
{
switch(errorCode)
{
case 0: return "エラーなし";
case 1: return "結果なし(値変更なし)";
case 2: return "一般エラー";
case 3: return "無効な取引パラメータ";
case 4: return "サーバービジー";
case 6: return "サーバー接続なし";
case 8: return "リクエスト過多";
case 64: return "口座無効";
case 128: return "取引タイムアウト";
case 129: return "無効な価格";
case 130: return "無効なSL/TP";
case 131: return "無効なロット数";
case 132: return "市場が閉じている";
case 133: return "取引無効";
case 134: return "証拠金不足";
case 135: return "価格変更";
case 136: return "オフクオート";
case 137: return "ブローカービジー";
case 138: return "リクオート";
case 139: return "注文ロック中";
case 145: return "変更拒否(フリーズレベル内)";
case 146: return "取引コンテキストビジー";
case 148: return "注文数上限";
case 4013: return "ゼロ除算";
case 4105: return "注文未選択";
case 4108: return "無効なチケット";
case 4109: return "取引不許可";
default: return "不明なエラー(" + IntegerToString(errorCode) + ")";
}
}リトライ付きエラーハンドリング
int OrderSendRetry(int cmd, double lots, double price,
int slippage, double sl, double tp,
string comment, int magic, int maxRetry = 5)
{
int ticket = -1;
for(int retry = 0; retry < maxRetry; retry++)
{
ResetLastError();
// 最新レート取得
RefreshRates();
if(cmd == OP_BUY)
price = Ask;
else if(cmd == OP_SELL)
price = Bid;
ticket = OrderSend(Symbol(), cmd, lots, price, slippage,
sl, tp, comment, magic, 0, clrNONE);
if(ticket >= 0)
return ticket; // 成功
int err = GetLastError();
Print("注文失敗(リトライ", retry + 1, "/", maxRetry, "): ",
ErrorDescription(err));
// リトライ可能なエラーか判定
switch(err)
{
case ERR_SERVER_BUSY: // 4
case ERR_NO_CONNECTION: // 6
case ERR_TOO_FREQUENT_REQUESTS: // 8
case ERR_TRADE_TIMEOUT: // 128
case ERR_PRICE_CHANGED: // 135
case ERR_OFF_QUOTES: // 136
case ERR_BROKER_BUSY: // 137
case ERR_REQUOTE: // 138
case ERR_TRADE_CONTEXT_BUSY: // 146
Sleep(1000 * (retry + 1)); // 段階的にウェイト増加
break;
default:
// リトライ不可能なエラー
Print("リトライ不可能なエラー: ", err);
return -1;
}
}
Print("最大リトライ回数超過");
return -1;
}- ERR_INVALID_STOPS (130): SL/TPがStopLevel未満の距離に設定されている →
MarketInfo(Symbol(), MODE_STOPLEVEL)を確認し、十分な距離を確保 - ERR_INVALID_PRICE (129): 古い価格で注文している →
RefreshRates()で最新価格を取得してから再送 - ERR_NOT_ENOUGH_MONEY (134): 証拠金不足 →
AccountFreeMarginCheck()で事前確認し、ロットを縮小
- ERR_INVALID_STOPS (130): SL/TPがStopLevel未満の距離に設定されている →
MarketInfo(Symbol(), MODE_STOPLEVEL)を確認し、十分な距離を確保 - ERR_INVALID_PRICE (129): 古い価格で注文している →
RefreshRates()で最新価格を取得してから再送 - ERR_NOT_ENOUGH_MONEY (134): 証拠金不足 →
AccountFreeMarginCheck()で事前確認し、ロットを縮小
IsTradeContextBusy — 取引コンテキスト
bool WaitForTradeContext(int timeoutSeconds = 30)
{
datetime startTime = TimeCurrent();
while(IsTradeContextBusy())
{
if(TimeCurrent() - startTime > timeoutSeconds)
{
Print("取引コンテキスト待機タイムアウト");
return false;
}
Sleep(100);
}
return true;
}
// 安全な発注パターン
int SafeOrderSend(int cmd, double lots, double sl, double tp, int magic)
{
// 取引許可チェック
if(!IsTradeAllowed())
{
Print("自動売買が許可されていません");
return -1;
}
// 取引コンテキスト待機
if(!WaitForTradeContext())
return -1;
// 証拠金チェック
double price = (cmd == OP_BUY) ? Ask : Bid;
if(AccountFreeMarginCheck(Symbol(), cmd, lots) < 0)
{
Print("証拠金不足");
return -1;
}
return OrderSendRetry(cmd, lots, price, 3, sl, tp, "", magic);
}ランタイムエラー(4000番台)はプログラム実行中に発生するエラーです。最も多いのはERR_ZERO_DIVIDE (4013)とERR_ARRAY_INDEX_OUT_OF_RANGE (4002)です。ゼロ除算は必ず分母のチェックを入れ、配列アクセスは必ず範囲チェックをしましょう。
ランタイムエラー(4000番台)はプログラム実行中に発生するエラーです。最も多いのはERR_ZERO_DIVIDE (4013)とERR_ARRAY_INDEX_OUT_OF_RANGE (4002)です。ゼロ除算は必ず分母のチェックを入れ、配列アクセスは必ず範囲チェックをしましょう。
よくあるコンパイルエラーと対処法
| エラーメッセージ | 原因 | 対処法 |
|---|---|---|
| ‘変数名’ – undeclared identifier | 未宣言の変数を使用 | 変数を宣言するかスペルを確認 |
| ‘関数名’ – function not defined | 関数が定義されていない | 関数定義を追加するか#includeを確認 |
| ‘)’ – semicolon expected | セミコロンの欠落 | 前の行の末尾にセミコロンを追加 |
| ‘return’ – ‘int’ type expected | 戻り値の型が不一致 | 関数の戻り値の型を確認 |
| implicit conversion | 暗黙の型変換 | 明示的にキャスト |
| possible loss of data | 精度低下の警告 | (int)や(double)でキャスト |
| array out of range | 配列範囲外アクセス | インデックスの範囲チェックを追加 |
エラー関連関数一覧(MQL5対応表)
| MQL4関数/定数 | MQL5対応 | 説明 |
|---|---|---|
| GetLastError() | GetLastError() | 最後のエラーコード |
| ResetLastError() | ResetLastError() | エラーコードリセット |
| IsTradeContextBusy() | なし(不要) | 取引コンテキストビジー判定 |
| IsTradeAllowed() | TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) | 取引許可判定 |
| IsConnected() | TerminalInfoInteger(TERMINAL_CONNECTED) | 接続状態判定 |
| ERR_INVALID_PRICE (129) | TRADE_RETCODE_INVALID (10013) | 無効な価格 |
| ERR_INVALID_STOPS (130) | TRADE_RETCODE_INVALID_STOPS (10016) | 無効なSL/TP |
| ERR_NOT_ENOUGH_MONEY (134) | TRADE_RETCODE_NO_MONEY (10019) | 証拠金不足 |
| ERR_REQUOTE (138) | TRADE_RETCODE_REQUOTE (10004) | リクオート |
まとめ
MQL4のエラーハンドリングは、EAの安定運用に不可欠です。重要なポイントは以下の通りです。
- 取引関数の後は必ずエラーチェックする — OrderSend/OrderClose/OrderModifyの戻り値を確認
- リトライ可能なエラーとそうでないエラーを区別する — サーバービジーやリクオートはリトライ、証拠金不足は即中止
- RefreshRates()で最新レートを取得してからリトライ — 古い価格で再送するとまたエラーになる
- IsTradeContextBusy()で取引コンテキストを確認 — 他のEAと同時に取引操作しない
次のステップとして、MQLリファレンス総合ガイドで取引関数とエラーハンドリングを組み合わせた堅牢なEA開発を学びましょう。





