EAを再起動しても状態を引き継ぐ方法|MQL5のグローバル変数

EAが、チャートを閉じた時やMT5・VPSの再起動の時に、それまで数えていた値(今日の取引回数など)を忘れるのは、EAの変数がメモリの中だけにあるためです。再起動しても続きから動かすには、値をMT5の外(ディスク)に残して、OnInitで読み戻す作りにします。手軽なのはMT5のグローバル変数(端末に保存される名前付きの数値)で、MQL5リファレンスによると、最後に使ってから4週間保存されます。ポジションのように取引サーバーにあるものは、残すより読み直す方が確実です。

この記事では、EAが状態を失う場面、残し方の選び方、グローバル変数を使う例(0エラー・0警告でコンパイル確認)、気をつける点をまとめます。

(確認:MQL5リファレンス「グローバル変数」「GlobalVariableSet」「TimeCurrent」。確認日:2026年10月10日。サンプルは MetaEditor でコンパイル確認。口座での実行は、この記事では行っていません)

EAが状態を失う場面

MQL5リファレンス「プログラム実行」によると、EAは次の場合にアンロードされます。アンロードされると、次に読み込まれた時は、EAの変数は初期値から始まります。

一方、チャートの銘柄や時間足を変えた時は、EAはアンロードされません。OnDeinitとOnInitが呼ばれますが、グローバル変数と静的変数の値はリセットされない、とリファレンスに書かれています。OnInitで変数を毎回0に戻す書き方にしていると、ここで値を消してしまうことがあります。終了の理由ごとの見分け方はMQL5のOnDeinitの終了理由にまとめています。

何を、どこに残すか

状態の種類 おすすめの方法 理由
保有中のポジション・未決注文 OnInitで口座から読み直す(PositionsTotal など) 取引サーバーにあり、MT5を再起動しても消えない
今日の取引回数・決済した回数 口座の履歴から数え直す(HistorySelect など)か、グローバル変数 履歴もサーバーから取れる。数え方が複雑ならグローバル変数が手軽
EAだけが知っている値(最後に判断した時刻、段階など) グローバル変数、またはファイル 口座からは読み直せない
文字列や、たくさんの値 ファイル(FileWrite など) グローバル変数は数値(double)だけ

ファイルへの書き方はMQL5でCSVを出力する方法、読み方はMQL5でCSVを読み込む方法にあります。ポジションの決済の書き方はMQL5でポジションを決済する方法です。

グローバル変数の性質(MQL5リファレンス)

  • クライアント端末に保存される、名前付きの数値。MQL5のプログラムの中で宣言するグローバル変数とは別物
  • 最後にアクセスしてから4週間保存され、その後は自動で削除される(読み込みもアクセスに含まれる)
  • 名前は63文字まで
  • 端末で動いているすべてのMQL5プログラムから同時にアクセスできる
  • GlobalVariablesFlush() で、すぐにディスクへ保存できる。GlobalVariableTemp() で作った変数は、端末の今のセッションの間だけ存在する

例:今日の取引回数を、再起動しても引き継ぐ

1日の取引回数に上限があるEAで、回数をグローバル変数に残す例です。日付が変わったら0に戻します。日付の判断は、VPSの時計に左右されないよう、サーバー時刻(TimeCurrent)を使っています(理由はVPSの時計とEAの時刻)。

// EAの状態(今日の取引回数)を、端末のグローバル変数に残して、再起動後に読み戻す例
input int InpMaxTradesPerDay = 3;   // 1日の取引回数の上限

string g_keyCount;   // グローバル変数の名前(回数)
string g_keyDay;     // グローバル変数の名前(数えている日)
int    g_count = 0;  // 今日の取引回数

// 名前に口座番号と銘柄を入れて、他の口座や銘柄のEAとぶつからないようにする
string MakeKey(const string what)
  {
   return StringFormat("EA_%I64d_%s_%s", AccountInfoInteger(ACCOUNT_LOGIN), _Symbol, what);
  }

// サーバー時刻の「日付」(0時0分0秒)を返す
datetime TodayServer()
  {
   MqlDateTime t;
   TimeToStruct(TimeCurrent(), t);
   t.hour = 0; t.min = 0; t.sec = 0;
   return StructToTime(t);
  }

int OnInit()
  {
   g_keyCount = MakeKey("count");
   g_keyDay   = MakeKey("day");

   // 保存してある日付が今日なら、回数を読み戻す。違う日なら0から数える
   double savedDay = 0.0, savedCount = 0.0;
   if(GlobalVariableGet(g_keyDay, savedDay) && (datetime)savedDay == TodayServer()
      && GlobalVariableGet(g_keyCount, savedCount))
      g_count = (int)savedCount;
   else
      g_count = 0;

   PrintFormat("再開時の今日の取引回数: %d", g_count);
   return INIT_SUCCEEDED;
  }

// 取引したら呼ぶ(この例では、注文の処理は省略している)
void CountTrade()
  {
   g_count++;
   GlobalVariableSet(g_keyDay, (double)TodayServer());
   GlobalVariableSet(g_keyCount, g_count);
   GlobalVariablesFlush();   // すぐにディスクへ書き出す
  }

void OnTick()
  {
   // 日付が変わったら、回数を0に戻す
   double savedDay = 0.0;
   if(!GlobalVariableGet(g_keyDay, savedDay) || (datetime)savedDay != TodayServer())
     {
      g_count = 0;
      GlobalVariableSet(g_keyDay, (double)TodayServer());
      GlobalVariableSet(g_keyCount, 0);
     }

   if(g_count >= InpMaxTradesPerDay)
      return;   // 今日の上限に達したので、新しい取引はしない

   // ここで売買の条件を判断し、注文が成功したら CountTrade() を呼ぶ
  }

注文の処理そのものは省いています。注文が成功した時にCountTrade()を呼ぶ形で組み込みます。

気をつけること

  • 名前がぶつからないようにする:グローバル変数は、同じ端末のすべてのプログラムから見えます。同じEAを複数のチャートで動かすなら、銘柄やマジックナンバーを名前に入れて分けます
  • 4週間で消える:長く止めていたEAを再開すると、値が消えていることがあります。値がない時の扱い(0から始める、など)を決めておきます
  • 別のPC・VPSへ移すと、引き継がれない:グローバル変数は、その端末に保存されています。移した直後は、値がない前提で動くようにします(移し方はMT5の設定とEAを別のPC・VPSへ移す手順)
  • 口座から読み直せるものは読み直す:保存した値と、実際の口座の状態が食い違った時は、口座の方が正しい
  • テストでは、ストラテジーテスターでの動き(グローバル変数の扱い)も確かめてから使います。この記事では、テスターでの挙動は確認していません

まとめ

  • EAの変数はメモリの中だけにある。チャートを閉じる・再起動で、初期値に戻る
  • ポジションや履歴は、OnInitで口座から読み直す。EAだけが知っている値は、グローバル変数かファイルに残す
  • グローバル変数は、最後のアクセスから4週間で消える・全プログラムから見える。名前と、値がない時の扱いを決めておく

EAが動き続けているかの確認はMT5でEAが動いているかを確認する方法、再起動後にMT5を自動で立ち上げる方法はMT5を自動で起動する方法にあります。

本記事はプログラミングの説明であり、特定の売買を推奨するものではありません。