OrderSend()が失敗して`GetLastError()`でエラーコードを確認したら「130」

が返ってきたので原因を直した。

ところが翌日、まったく別の場所で何気なく`GetLastError()`を呼んだら、

また同じ「130」が返ってきて混乱した——このパターンに心当たりがある人は少なくないはずです。

実はこれ、バグではなくMQL4の`GetLastError()`の仕様そのものです。

この記事では、EA・インジケーターのほぼすべての記事で登場するのに単独で解説されてこなかった`GetLastError()`について、

なぜ「起きていないはずのエラー」が返ってくるのか、`ResetLastError()`と組み合わせる正しい書き方、

そしてOrderSend失敗時によく出る代表的なエラーコードまで解説します。

GetLastError関数の書式

int GetLastError();

引数はなく、直近に発生したエラーコードを`int`型で返します。

一見シンプルですが、注意すべき仕様が1つあります。

最大の罠: GetLastError()は自動でリセットされない

`GetLastError()`が返す値は、MQL4の内部にある「最後に発生したエラーコードを覚えておくための変数」

の中身をそのまま返しているだけです。

**この変数は、何か操作が成功したからといって自動で0に戻るわけではありません。

** 一度エラーコード130がセットされると、その後に別の処理が正常に完了しても、

変数の中身は誰かが明示的に上書きするまで130のまま残り続けます。

①OrderSend()が失敗し、GetLastError()の変数に130(Invalid stops)がセットされる
②その後、別の場所で正常に完了する処理があっても、この変数は勝手に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), ")");
     }
  }
//+------------------------------------------------------------------+
Copy

MetaEditorで実際に動かす手順

  1. MT4の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
  2. 「ファイル」→「新規作成」からウィザードで「Expert Advisor(テンプレートを使用)」を選び、名前を「GetLastErrorDemo」にして作成する(あとの画面は「次へ」を数回押して「完了」まで進めれば構いません)
  3. テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
  4. F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  5. デモ口座のチャートへドラッグ&ドロップして動作を確認する(実際に発注するコードなので、必ずデモ口座で試してください)

コピペしてコンパイルが通らない・想定外の動きをするときに確認すること

  • 拡張子が「.mq4」になっているか
  • `ResetLastError()`を呼ばずに`GetLastError()`だけを別の場所で使い回していないか(前回のエラーコードを誤って拾っている可能性があります)
  • `GetLastError()`の戻り値だけでエラー判定をしていないか(必ず`OrderSend()`等、確認したい関数自身の戻り値で成否を判定するのが先です)

まとめ

`GetLastError()`は、成功しても自動でリセットされない「最後のエラーコードを保持するだけの変数」

を読み取る関数です。

確認したい処理の直前で`ResetLastError()`を呼んでおかないと、

過去に起きた無関係なエラーコードを拾ってしまいます。

エラー判定の一次情報は関数自身の戻り値、`GetLastError()`はその原因を知るための補助情報、

という役割分担を意識すれば、この記事のコードはそのまま既存のEAへ組み込めます。

関連記事