OrderSend()が失敗して`GetLastError()`でエラーコードを確認したら「130」
が返ってきたので原因を直した。
ところが翌日、まったく別の場所で何気なく`GetLastError()`を呼んだら、
また同じ「130」が返ってきて混乱した——このパターンに心当たりがある人は少なくないはずです。
実はこれ、バグではなくMQL4の`GetLastError()`の仕様そのものです。
この記事では、EA・インジケーターのほぼすべての記事で登場するのに単独で解説されてこなかった`GetLastError()`について、
なぜ「起きていないはずのエラー」が返ってくるのか、`ResetLastError()`と組み合わせる正しい書き方、
そしてOrderSend失敗時によく出る代表的なエラーコードまで解説します。
GetLastError関数の書式
int GetLastError();
引数はなく、直近に発生したエラーコードを`int`型で返します。
一見シンプルですが、注意すべき仕様が1つあります。
最大の罠: GetLastError()は自動でリセットされない
`GetLastError()`が返す値は、MQL4の内部にある「最後に発生したエラーコードを覚えておくための変数」
の中身をそのまま返しているだけです。
**この変数は、何か操作が成功したからといって自動で0に戻るわけではありません。
** 一度エラーコード130がセットされると、その後に別の処理が正常に完了しても、
変数の中身は誰かが明示的に上書きするまで130のまま残り続けます。
②その後、別の場所で正常に完了する処理があっても、この変数は勝手に0へは戻らない
③しばらく経ってから何気なく別の場所でGetLastError()を呼ぶと、実際には何も起きていないのに130が返ってきて混乱する
これを避けるには、エラーを確認したい処理の**直前**に、変数を明示的に0へ戻す`ResetLastError()`を呼んでおく必要があります。
void ResetLastError();
こちらも引数・戻り値ともになく、直近のエラーコードを保持する変数を強制的に0にするだけの関数です。
正しい組み合わせ方
「確認したい処理の直前でResetLastError()→処理を実行→戻り値で成否を判定→失敗していたらGetLastError()でコードを取得」
という順序を徹底します。
ResetLastError();//直前のエラー状態をクリアしてから
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, Ask - 200 * Point, Ask + 200 * Point, "EA", 1234, 0, Red);
if(ticket < 0)//OrderSendの戻り値が-1(失敗)のとき
{
int errorCode = GetLastError();//このタイミングのエラーコードだけを確実に取得できる
Print("発注に失敗しました。エラーコード=", errorCode);
}
ポイントは、**エラーが起きたかどうかの一次判定はGetLastError()ではなく、
必ず関数自身の戻り値(この例ではOrderSendが返すticketが負の値かどうか)で行う**ことです。
GetLastError()はあくまで「なぜ失敗したか」を知るための補助情報であり、
`ResetLastError()`を挟まずに呼ぶと、前節の理由で古い情報を拾ってしまう可能性があります。
OrderSend失敗時によく出る代表的なエラーコード
数百種類あるエラーコードのうち、発注処理で特によく遭遇するものを挙げます。
- 130 (ERR_INVALID_STOPS) — 損切り・利確の価格がエントリー価格に近すぎる(ブローカーの最小ストップ距離未満)
- 134 (ERR_NOT_ENOUGH_MONEY) — 証拠金不足でロット数が発注できない
- 138 (ERR_REQUOTE) — リクオート(発注時と約定時で価格がズレた)
- 146 (ERR_TRADE_CONTEXT_BUSY) — 別の取引処理が実行中で、同時に発注できなかった
このうち130と134はパーフェクトオーダーEAの記事でも実際に遭遇する例として触れています。
エラーコードの一覧は数が多いため、実務では「頻出する数個の意味を覚えておき、
それ以外はPrint()で出力してから公式リファレンスで都度調べる」
という運用で十分です。
実際に動くコード全体
`ResetLastError()`→発注→戻り値チェック→`GetLastError()`という正しい順序を、
実際にエラーコードを日本語の簡易メッセージに変換する関数付きでまとめたサンプルです。
//+------------------------------------------------------------------+
//| GetLastErrorDemo.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
input double Lots = 0.1;
input int StopLoss = 200;//損切り(pips)
input int TakeProfit = 200;//利確(pips)
input int MagicNumber = 12345;
//+------------------------------------------------------------------+
//| よく出るエラーコードだけ日本語の簡易説明を返す |
//+------------------------------------------------------------------+
string ErrorDescription(int code)
{
switch(code)
{
case 130: return("損切り・利確の価格がエントリー価格に近すぎます");
case 134: return("証拠金が不足しています");
case 138: return("リクオートが発生しました");
case 146: return("取引処理が混み合っています(少し待って再試行してください)");
default: return("エラーコード一覧は公式リファレンスで確認してください");
}
}
void OnTick()
{
//既にこのマジックナンバーのポジションがあれば何もしない
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == MagicNumber)
return;
}
//発注直前にエラー状態をクリアする
ResetLastError();
int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 3,
Ask - StopLoss * Point,
Ask + TakeProfit * Point,
"EA", MagicNumber, 0, Red);
if(ticket < 0)
{
int errorCode = GetLastError();
Print("発注に失敗しました。エラーコード=", errorCode, " (", ErrorDescription(errorCode), ")");
}
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MT4の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
- 「ファイル」→「新規作成」からウィザードで「Expert Advisor(テンプレートを使用)」を選び、名前を「GetLastErrorDemo」にして作成する(あとの画面は「次へ」を数回押して「完了」まで進めれば構いません)
- テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
- F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- デモ口座のチャートへドラッグ&ドロップして動作を確認する(実際に発注するコードなので、必ずデモ口座で試してください)
コピペしてコンパイルが通らない・想定外の動きをするときに確認すること
- 拡張子が「.mq4」になっているか
- `ResetLastError()`を呼ばずに`GetLastError()`だけを別の場所で使い回していないか(前回のエラーコードを誤って拾っている可能性があります)
- `GetLastError()`の戻り値だけでエラー判定をしていないか(必ず`OrderSend()`等、確認したい関数自身の戻り値で成否を判定するのが先です)
まとめ
`GetLastError()`は、成功しても自動でリセットされない「最後のエラーコードを保持するだけの変数」
を読み取る関数です。
確認したい処理の直前で`ResetLastError()`を呼んでおかないと、
過去に起きた無関係なエラーコードを拾ってしまいます。
エラー判定の一次情報は関数自身の戻り値、`GetLastError()`はその原因を知るための補助情報、
という役割分担を意識すれば、この記事のコードはそのまま既存のEAへ組み込めます。
コメント