MQL5のEA開発で遭遇するエラーを網羅的にまとめました。EAが動かない時のチェックリスト、取引エラーの原因と解決法、コンパイルエラー対処法、エラーコード全一覧、エラーハンドリング実装、デバッグ手法まで、このページですべて解決できます。
EAが動かない時のチェックリスト
EAをチャートに設置したのに何も起きない。ログにエラーも出ない。この状態の原因はほとんどの場合、コードのバグではなくMT5側の設定にあります。上から順に確認してください。
1. 自動売買ボタンがOFFになっている
MT5ツールバーの「アルゴリズム取引」ボタン(Algo Trading)を確認。これがOFFだと全EAが停止します。チャート右上のEA名の横にニコちゃんマークが表示されていればON、灰色アイコンならOFFです。
void OnTick()
{
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Print("エラー: ターミナルの自動売買が無効です");
return;
}
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
{
Print("エラー: このEAの自動売買が許可されていません");
return;
}
}2. EAのプロパティで取引が許可されていない
チャート上のEA名を右クリック → プロパティ → 「共通」タブ → 「自動売買を許可する」にチェック。WebRequestやDLLを使うEAは、それぞれの許可チェックも必要です。
3. 口座が取引可能な状態ではない
投資家パスワード(読み取り専用)でログインしている、デモ口座の有効期限が切れている、口座が無効化されている、のいずれかです。
int OnInit()
{
if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
{
Print("この口座では取引できません");
Print("口座タイプ: ",
EnumToString((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE)));
}
return(INIT_SUCCEEDED);
}4. 市場が閉まっている
土日、祝日、メンテナンス時間帯はティックが配信されないため、OnTick()は一度も呼ばれません。MT5下部のステータスバーに接続状態が表示されます。
5. 通貨ペアまたは時間足が想定と違う
EAが特定の通貨ペアや時間足を前提にしている場合、違うチャートにセットしても想定通りに動きません。
int OnInit()
{
Print("通貨ペア: ", _Symbol, " 時間足: ", EnumToString(_Period));
return(INIT_SUCCEEDED);
}6. エントリー条件が成立していない
コードに問題はなく、単に売買条件が発生していないだけのケースです。OnTick()の先頭にPrintを入れて、ティックが来ているか、条件判定のどこで止まっているかを確認してください。
void OnTick()
{
static int count = 0;
count++;
Print("Tick #", count); // これが出力されればOnTickは呼ばれている
}7. スプレッドフィルターで弾かれている
早朝や指標発表前後はスプレッドが大きく広がります。EAにスプレッド制限を入れている場合、この時間帯はエントリーがブロックされます。
int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
Print("現在のスプレッド: ", spread, " point");8. 時間フィルターで弾かれている
取引時間帯を制限している場合、サーバー時間とローカル時間のずれに注意。ブローカーによってサーバー時間のタイムゾーンが異なります。
Print("サーバー時間: ", TimeCurrent());
Print("GMT: ", TimeGMT());
Print("ローカル: ", TimeLocal());
Print("GMTオフセット: ", (int)(TimeCurrent() - TimeGMT()) / 3600, "時間");9. 最大ポジション数に達している
EA側の制限またはブローカー側の制限でこれ以上ポジションを持てない状態です。
int myPositions = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)
myPositions++;
}
}
Print("このEAのポジション数: ", myPositions);10. コンパイルしていない / 古い.ex5が動いている
ソースコード(.mq5)を修正しても、MetaEditorでコンパイル(F7)しないと変更は反映されません。コンパイル後、MT5側でEAを再読み込みする必要がある場合もあります。
よくある取引エラーの原因と解決
OrderSendが失敗したとき、MqlTradeResult.retcodeにエラーコードが格納されます。ここではEA開発で特に遭遇頻度が高いエラーを、原因と解決コード付きで解説します。
10016: TRADE_RETCODE_INVALID_STOPS — SL/TPが不正
EA開発で最も遭遇頻度が高いエラーです。SL/TPの位置が現在価格に近すぎる、または買い/売りの方向に対してSL/TPの位置が論理的に矛盾しています。
主な原因: ブローカーが定める最小ストップレベル(SYMBOL_TRADE_STOPS_LEVEL)より現在価格に近い位置にSL/TPを設定している。
// ❌ 10016になる例: SLが現在価格に近すぎる
request.sl = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - 1 * _Point;
// ✅ 最小ストップレベルを考慮した設定
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int stopsLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
if(stopsLevel == 0) stopsLevel = 15; // 0の場合は安全マージンを取る
double minDistance = stopsLevel * _Point;
double sl = NormalizeDouble(ask - MathMax(50 * _Point, minDistance), _Digits);
double tp = NormalizeDouble(ask + MathMax(50 * _Point, minDistance), _Digits);- SL/TPと現在価格の距離が
SYMBOL_TRADE_STOPS_LEVEL × _Point以上あるか - 買い注文: SL < Ask、TP > Ask になっているか
- 売り注文: SL > Bid、TP < Bid になっているか
- SL/TPの値が
NormalizeDouble()で正規化されているか
10014: TRADE_RETCODE_INVALID_VOLUME — ロット数が不正
ロット数がブローカーの許容範囲外です。最小ロット未満、最大ロット超過、またはロットステップに合っていません。
double LotNormalize(string symbol, double lot)
{
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
lot = MathMax(minLot, lot);
lot = MathMin(maxLot, lot);
lot = MathFloor(lot / lotStep) * lotStep;
lot = NormalizeDouble(lot, 2);
return lot;
}10019: TRADE_RETCODE_NO_MONEY — 資金不足
指定したロット数を建てるための証拠金が口座にありません。
double margin;
if(!OrderCalcMargin(ORDER_TYPE_BUY, _Symbol, lot, ask, margin))
{
Print("証拠金計算エラー");
return;
}
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
if(margin > freeMargin)
{
Print("証拠金不足: 必要=", margin, " 利用可能=", freeMargin);
return;
}10013: TRADE_RETCODE_INVALID — リクエストが不正
MqlTradeRequest構造体のフィールドに矛盾や不備があります。最も多い原因はactionフィールドの指定漏れ、またはtype_fillingの未指定です。
MqlTradeRequest request = {};
request.action = TRADE_ACTION_DEAL; // 必須: 成行注文
request.symbol = _Symbol; // 必須: 通貨ペア
request.volume = 0.1; // 必須: ロット数
request.type = ORDER_TYPE_BUY; // 必須: 売買方向
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // 必須: 価格
request.deviation = 10; // 推奨: 許容スリッページ
request.type_filling = ORDER_FILLING_FOK; // 推奨: 充填タイプ
request.magic = MagicNumber; // 推奨: EA識別用10030: TRADE_RETCODE_INVALID_FILL — 充填タイプが不正
type_fillingに指定した充填タイプ(FOK/IOC/RETURN)を、そのブローカー・銘柄がサポートしていません。
ENUM_ORDER_TYPE_FILLING GetFillingType(string symbol)
{
int filling = (int)SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
if((filling & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
return ORDER_FILLING_FOK;
if((filling & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
return ORDER_FILLING_IOC;
return ORDER_FILLING_RETURN;
}10027: TRADE_RETCODE_CLIENT_DISABLES_AT — 自動取引が無効
MT5の「アルゴリズム取引」ボタンがOFFになっています。コードの問題ではなくMT5の設定の問題です。
int OnInit()
{
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Alert("自動売買を有効にしてください");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}コンパイルエラー一覧と対処法
MetaEditorでF7を押してコンパイルした際に表示されるエラーです。コンパイルエラーがあるとEAは動作しません。
エラーは上から順に直してください。最初の1つを直すだけで後続のエラーが消えることが多いです。
構文エラー
| エラーメッセージ | 原因 | 対処 |
|---|---|---|
';' expected | セミコロン忘れ | エラー行の前の行の末尾を確認 |
')' expected | 閉じ括弧の不足 | if文やfor文の条件式の括弧を確認 |
'}' expected | 閉じ波括弧の不足 | Ctrl+, でインデント整形して対応を可視化 |
unexpected token | 予期しない文字 | 前の行にセミコロン忘れがないか確認 |
expressions are not allowed on a global scope | 関数の外にコードがある | 実行文がOnTick等の関数内にあるか確認 |
変数・型エラー
| エラーメッセージ | 原因 | 対処 |
|---|---|---|
'xxx' - undeclared identifier | 変数が未宣言 | スペルミス(大文字小文字含む)か宣言忘れ |
'xxx' - variable already defined | 同名変数が2回宣言 | 同じスコープ内で重複していないか確認 |
implicit conversion | 数値→文字列の暗黙変換 | IntegerToString()やDoubleToString()で明示変換 |
possible loss of data | 精度が失われる型変換 | (int)等で明示キャストすれば消える(警告) |
constant variable cannot be modified | const変数への代入 | constを外すか別の変数に代入 |
関数エラー
| エラーメッセージ | 原因 | 対処 |
|---|---|---|
'xxx' - wrong parameters count | 引数の数が違う | MQL4とMQL5で引数が変わった関数に注意 |
'xxx' - function not defined | 関数が存在しない | スペルミスか、MQL4専用関数を使っていないか確認 |
not all control paths return a value | 一部のパスでreturnがない | if/elseの全分岐でreturnを入れる |
cannot open file 'xxx.mqh' | インクルードファイルが見つからない | <>はIncludeフォルダ、””はカレントフォルダ |
取引リターンコード全一覧(ENUM_TRADE_RETCODE)
OrderSend / OrderSendAsync の実行結果として MqlTradeResult.retcode に格納されるコードの全一覧です。
| コード | 定数名 | 意味 |
|---|---|---|
| 10004 | TRADE_RETCODE_REQUOTE | リクオート |
| 10006 | TRADE_RETCODE_REJECT | リクエスト拒否 |
| 10007 | TRADE_RETCODE_CANCEL | トレーダーによるキャンセル |
| 10008 | TRADE_RETCODE_PLACED | 注文が発注された |
| 10009 | TRADE_RETCODE_DONE | リクエスト完了 |
| 10010 | TRADE_RETCODE_DONE_PARTIAL | 部分的に完了 |
| 10011 | TRADE_RETCODE_ERROR | 一般的な処理エラー |
| 10012 | TRADE_RETCODE_TIMEOUT | タイムアウト |
| 10013 | TRADE_RETCODE_INVALID | 無効なリクエスト |
| 10014 | TRADE_RETCODE_INVALID_VOLUME | 無効なロット数 |
| 10015 | TRADE_RETCODE_INVALID_PRICE | 無効な価格 |
| 10016 | TRADE_RETCODE_INVALID_STOPS | 無効なSL/TP |
| 10017 | TRADE_RETCODE_TRADE_DISABLED | 取引無効 |
| 10018 | TRADE_RETCODE_MARKET_CLOSED | 市場閉鎖 |
| 10019 | TRADE_RETCODE_NO_MONEY | 資金不足 |
| 10020 | TRADE_RETCODE_PRICE_CHANGED | 価格変動 |
| 10021 | TRADE_RETCODE_PRICE_OFF | 気配値なし |
| 10022 | TRADE_RETCODE_INVALID_EXPIRATION | 無効な有効期限 |
| 10023 | TRADE_RETCODE_ORDER_CHANGED | 注文状態が変更された |
| 10024 | TRADE_RETCODE_TOO_MANY_REQUESTS | リクエスト過多 |
| 10025 | TRADE_RETCODE_NO_CHANGES | 変更なし |
| 10026 | TRADE_RETCODE_SERVER_DISABLES_AT | サーバー側で自動取引無効 |
| 10027 | TRADE_RETCODE_CLIENT_DISABLES_AT | クライアント側で自動取引無効 |
| 10028 | TRADE_RETCODE_LOCKED | リクエストがロック中 |
| 10029 | TRADE_RETCODE_FROZEN | 注文/ポジションが凍結 |
| 10030 | TRADE_RETCODE_INVALID_FILL | 無効な充填タイプ |
| 10031 | TRADE_RETCODE_CONNECTION | 接続なし |
| 10032 | TRADE_RETCODE_ONLY_REAL | リアル口座でのみ許可 |
| 10033 | TRADE_RETCODE_LIMIT_ORDERS | 待機注文数の上限 |
| 10034 | TRADE_RETCODE_LIMIT_VOLUME | ボリューム上限 |
| 10035 | TRADE_RETCODE_INVALID_ORDER | 無効な注文タイプ |
| 10036 | TRADE_RETCODE_POSITION_CLOSED | ポジションは既にクローズ済み |
| 10038 | TRADE_RETCODE_INVALID_CLOSE_VOLUME | 無効な決済ボリューム |
| 10039 | TRADE_RETCODE_CLOSE_ORDER_EXIST | 既に決済注文が存在 |
| 10040 | TRADE_RETCODE_LIMIT_POSITIONS | ポジション数の上限 |
| 10041 | TRADE_RETCODE_REJECT_CANCEL | キャンセル拒否 |
| 10042 | TRADE_RETCODE_LONG_ONLY | 買いのみ許可 |
| 10043 | TRADE_RETCODE_SHORT_ONLY | 売りのみ許可 |
| 10044 | TRADE_RETCODE_CLOSE_ONLY | 決済のみ許可 |
| 10045 | TRADE_RETCODE_FIFO_CLOSE | FIFO順の決済のみ許可 |
ランタイムエラー一覧
GetLastError() で取得できるランタイムエラーです。取引リターンコードとは別の体系です。
| コード | 定数名 | 意味 |
|---|---|---|
| 0 | ERR_SUCCESS | エラーなし |
| 4001 | ERR_INTERNAL_ERROR | 予期しない内部エラー |
| 4003 | ERR_INVALID_PARAMETER | 関数のパラメータ不正 |
| 4004 | ERR_NOT_ENOUGH_MEMORY | メモリ不足 |
| 4014 | ERR_FUNCTION_NOT_ALLOWED | システム関数の呼び出し不可 |
| 4101 | ERR_WRONG_FILENAME | 無効なファイル名 |
| 4103 | ERR_CANNOT_OPEN_FILE | ファイルを開けない |
| 4301 | ERR_UNKNOWN_SYMBOL | 不明なシンボル |
| 4302 | ERR_INDICATOR_CANNOT_INIT | インジケーター初期化失敗 |
| 4303 | ERR_INDICATOR_CANNOT_CREATE | インジケーター作成失敗 |
| 4401 | ERR_ARRAY_RESIZE_ERROR | 配列リサイズ失敗 |
| 5004 | ERR_WEBREQUEST_INVALID_ADDRESS | WebRequestのURL不正 |
| 5200 | ERR_WEBREQUEST_TIMEOUT | WebRequestタイムアウト |
| 5201 | ERR_WEBREQUEST_REQUEST_FAILED | WebRequestリクエスト失敗 |
エラーハンドリングの実装方法
GetLastError / ResetLastError
GetLastError() は直前の関数呼び出しで発生したランタイムエラーのコードを返します。取引エラー(retcode)とは別の仕組みです。
int handle = iMA(_Symbol, PERIOD_H1, 20, 0, MODE_SMA, PRICE_CLOSE);
if(handle == INVALID_HANDLE)
{
int err = GetLastError();
Print("iMA作成失敗: エラーコード=", err);
return;
}
// ResetLastError: エラーコードを0にリセット
// 複数の関数を連続して呼ぶ前にリセットしておくと
// どの関数でエラーが発生したか特定しやすい
ResetLastError();
double value[];
int copied = CopyBuffer(handle, 0, 0, 1, value);
if(copied <= 0)
{
int err = GetLastError();
Print("CopyBuffer失敗: エラーコード=", err);
}GetLastError() はエラーコードを返しますが、MQL5では自動リセットされません。エラーコードをリセットするには ResetLastError() を明示的に呼ぶ必要があります。複数の関数を連続して呼ぶ場合は、各呼び出しの前に ResetLastError() でリセットしてください。
リトライパターンの実装
リクオートや価格変動など、リトライで解決するエラーには自動リトライが有効です。ただしリトライすべきでないエラーを無限リトライすると問題になるので、エラー種別の判定が重要です。
// リトライ対象のエラーかどうか判定
bool IsRetryableError(uint retcode)
{
switch(retcode)
{
case TRADE_RETCODE_REQUOTE:
case TRADE_RETCODE_PRICE_CHANGED:
case TRADE_RETCODE_PRICE_OFF:
case TRADE_RETCODE_TIMEOUT:
case TRADE_RETCODE_CONNECTION:
return true;
default:
return false;
}
}
// リトライ付き注文送信
bool OrderSendWithRetry(MqlTradeRequest &request, MqlTradeResult &result, int maxRetry = 3)
{
for(int attempt = 1; attempt <= maxRetry; attempt++)
{
// 成行注文の場合、毎回最新価格を取得
if(request.action == TRADE_ACTION_DEAL)
{
if(request.type == ORDER_TYPE_BUY)
request.price = SymbolInfoDouble(request.symbol, SYMBOL_ASK);
else if(request.type == ORDER_TYPE_SELL)
request.price = SymbolInfoDouble(request.symbol, SYMBOL_BID);
}
if(!OrderSend(request, result))
{
Print("OrderSend失敗 (attempt ", attempt, "): ", GetLastError());
return false;
}
if(result.retcode == TRADE_RETCODE_DONE
|| result.retcode == TRADE_RETCODE_PLACED)
{
Print("注文成功: ticket=", result.order);
return true;
}
if(!IsRetryableError(result.retcode))
{
Print("リトライ不可: ", result.retcode, " ", result.comment);
return false;
}
Print("リトライ (", attempt, "/", maxRetry, "): ", result.retcode);
Sleep(300 * attempt); // 間隔を徐々に広げる
}
Print("リトライ上限に達しました");
return false;
}デバッグの方法
Print / Comment / Alert
MQL5で最も基本的な3つのデバッグ手段です。出力先が異なります。
| 関数 | 出力先 | 用途 |
|---|---|---|
Print() | 操作履歴タブ / ログファイル | メインのデバッグ手段。ログに残る |
Comment() | チャート左上 | リアルタイムの値をチャート上に表示 |
Alert() | ポップアップダイアログ | 重要なイベントの通知。多用注意 |
void OnTick()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
// ログに記録
Print("Ask=", ask, " Bid=", bid, " Spread=", spread);
// チャート上にリアルタイム表示
Comment("Ask: ", ask, "\n",
"Bid: ", bid, "\n",
"Spread: ", spread, " pt");
// PrintFormat: 書式指定で出力を整える
PrintFormat("残高: %.2f 証拠金: %.2f 損益: %+.2f",
AccountInfoDouble(ACCOUNT_BALANCE),
AccountInfoDouble(ACCOUNT_MARGIN),
AccountInfoDouble(ACCOUNT_PROFIT));
}MetaEditorのデバッガ
- MetaEditorでソースコードを開く
- 止めたい行の左側をクリック → 赤い丸(ブレークポイント)が表示される
- F5でデバッグ開始(ストラテジーテスターが起動する)
- ブレークポイントで停止したら「ウォッチ」ウィンドウで変数の値を確認
- F10でステップ実行(1行ずつ進む)、F11でステップイン(関数の中に入る)
ログの読み方
MT5のログは2箇所にあります。
- 操作履歴タブ(MT5画面下部 → ツールボックス → 操作履歴): EAのPrint出力とシステムメッセージが表示されます。右クリック →「自動スクロール」をONにすると便利です。
- ログファイル: MT5の「ファイル」→「データフォルダを開く」→ Logs フォルダ内に日付ごとに保存されます。
OnInit()で初期状態をまとめて出力しておくと、後からログを確認する際に便利です。
int OnInit()
{
Print("========== EA START ==========");
Print("EA: ", MQLInfoString(MQL_PROGRAM_NAME));
Print("Symbol: ", _Symbol, " Period: ", EnumToString(_Period));
Print("Account: ", AccountInfoInteger(ACCOUNT_LOGIN),
" Server: ", AccountInfoString(ACCOUNT_SERVER));
Print("Balance: ", AccountInfoDouble(ACCOUNT_BALANCE),
" Leverage: 1:", AccountInfoInteger(ACCOUNT_LEVERAGE));
Print("Trade allowed (terminal): ", TerminalInfoInteger(TERMINAL_TRADE_ALLOWED));
Print("Trade allowed (EA): ", MQLInfoInteger(MQL_TRADE_ALLOWED));
Print("==============================");
return INIT_SUCCEEDED;
}あなたのEAをシストレ.COMで販売しませんか? → 出品について





