「少し待ってから次の処理をしたい」

「ユーザーに確認してから動かしたい」

そう思ったときに使いたくなるのが、

SleepとMessageBoxという2つの関数です。

どちらも一見便利ですが、

EAで使うと処理が止まってしまう危険な関数でもあります。

この記事で分かること
・Sleep関数がカスタムインジケーターで使えない理由
・MessageBoxがEAのティック処理を止めてしまう仕組み
・両関数がストラテジーテスターでは意味を持たないこと
・待機処理・確認処理の安全な書き方
  1. SleepとMessageBoxが「危険な関数」と言われる理由
    1. どちらも処理を「止める」関数
    2. EAは24時間自動で動く前提のプログラム
    3. ChatGPT等が生成したコードに紛れ込みやすい
  2. Sleep関数のシグネチャと本来の使い道
    1. Sleep()のシグネチャ(docs.mql4.com確認済み)
    2. スクリプトでの一回限りの処理には使える
    3. 0.1秒ごとにEA停止フラグをチェックする仕組み
  3. Sleep関数をEAで使うとどうなるか
    1. カスタムインジケーターでは使用不可
    2. EAで使うと新しいティックを取りこぼす
    3. 非ブロッキングな待機処理に書き直す
  4. MessageBox関数のシグネチャと戻り値
    1. MessageBox()のシグネチャ(docs.mql4.com確認済み)
    2. 本来は手動確認用のダイアログ
    3. カスタムインジケーターでは使用不可
  5. MessageBoxをEAで使うとどうなるか
    1. EA自体はMessageBoxを呼び出せる
    2. クリックするまでそのEAの処理が止まる
    3. 通知はPrint・Comment・SendMail等で行う
  6. ストラテジーテスターでは両方とも意味を持たない
    1. Sleepはテスターでは実行を中断しない
    2. MessageBoxはテスターでは機能しない
    3. テストで問題が見えないまま本番稼働させない
  7. ChatGPT等が生成したコードへの対処
    1. コード内にSleep・MessageBoxが無いか検索する
    2. 用途ごとに置き換え先を選ぶ
    3. 置き換え後は必ずバックテストと通して確認する
  8. よくある質問
    1. Sleepをインジケーターで使うとどうなりますか?
    2. MessageBoxは絶対に使ってはいけませんか?
    3. Sleepを使わずに「数秒待つ」処理は作れますか?
  9. 【MQL4】SleepとMessageBoxをEAで使うと危険な理由(インジケーターでは使用不可・テスターでは無効):まとめ
    1. 関連記事

SleepとMessageBoxが「危険な関数」と言われる理由

まず、この2つの関数がなぜ注意を要するのかを確認します。

どちらも処理を「止める」関数

Sleepは指定した時間だけ、

MessageBoxはユーザーがボタンを押すまで、

プログラムの実行をその場で止めます。

EAは24時間自動で動く前提のプログラム

補足
・EAは人がチャートの前にいなくても動き続けることが前提
・処理が止まっている間は新しいティック(価格更新)に反応できない
・止まっている間に相場が大きく動くリスクがある

ChatGPT等が生成したコードに紛れ込みやすい

既刊chatgpt-ea-not-working-checklist-mt4.mdで

触れたとおり、

AIが生成したサンプルコードには、

一般的なプログラミングの作法としてSleepやMessageBoxが

そのまま含まれていることがあります。

Sleep関数のシグネチャと本来の使い道

実際の書式と本来の用途をdocs.mql4.comで確認済みの内容で見ていきます。

Sleep()のシグネチャ(docs.mql4.com確認済み)

void Sleep(int milliseconds);

引数`milliseconds`で指定した時間(ミリ秒)だけ、

実行を一時停止する関数です。

スクリプトでの一回限りの処理には使える

人が実行ボタンを押して1回だけ動かすスクリプトであれば、

処理の合間に少し待つ目的でSleepを使っても

実害は小さいです。

0.1秒ごとにEA停止フラグをチェックする仕組み

Sleep関数には、

0.1秒ごとにEAの停止操作が無いかを確認する仕組みが

組み込まれています。

Sleep関数をEAで使うとどうなるか

EAの中でSleepを使った場合の具体的な問題を確認します。

カスタムインジケーターでは使用不可

注意
・インジケーターはチャート描画と同じインターフェーススレッドで動く
・そこでSleepを呼ぶと画面の表示自体が固まってしまう
・そのためMQL4ではインジケーターからのSleep呼び出しが禁止されている

EAで使うと新しいティックを取りこぼす

//よくある誤用コード(非推奨)
for(int i = 0; i < 5; i++)
  {
   Sleep(1000);//1秒待つ×5回
   Print("waiting...");
  }

このコードが実行されている間、

このEAは新しい価格更新に反応できません。

非ブロッキングな待機処理に書き直す

static int lastActionTime = 0;
if(GetTickCount() - lastActionTime > 5000)
  {
   lastActionTime = GetTickCount();
   DoSomething();
  }

直前に実行した時刻を変数に記録し、

一定時間経過したかをOnTick()の中で毎回判定する形にすれば、

ティックを取りこぼさずに「待つ」処理を実現できます。

MessageBox関数のシグネチャと戻り値

次に、MessageBox関数の書式を確認します。

MessageBox()のシグネチャ(docs.mql4.com確認済み)

int MessageBox(
   string text,          //表示するメッセージ
   string caption=NULL,  //タイトル(省略時はEA名)
   int    flags=0        //ボタン・アイコンの指定フラグ
   );

戻り値は、

ユーザーが押したボタンに対応する定数(`IDOK`等)です。

本来は手動確認用のダイアログ

MessageBoxは、

人が画面の前でボタンを押すことを前提にした

確認ダイアログ用の関数です。

カスタムインジケーターでは使用不可

Sleepと同様に、

MessageBoxもインターフェーススレッドの固まりを避けるため

カスタムインジケーターからは呼び出せません。

MessageBoxをEAで使うとどうなるか

EAでの呼び出しが許可されている点が、Sleepとの違いです。

EA自体はMessageBoxを呼び出せる

EAはインターフェーススレッドとは別に動くため、

コンパイル・起動自体はできてしまいます。

クリックするまでそのEAの処理が止まる

注意
・ダイアログが表示されている間、そのEAのOnTick()は先に進まない
・無人で稼働させている場面では誰もクリックできない
・ポジションを持ったまま長時間反応できなくなるリスクがある

通知はPrint・Comment・SendMail等で行う

EAからの通知には、

既刊get-last-error.mdのPrint()・

既刊のComment表示・SendMail()等、

処理を止めない手段を使います。

ストラテジーテスターでは両方とも意味を持たない

バックテストで検証する際の注意点を確認します。

Sleepはテスターでは実行を中断しない

docs.mql4.comで確認した通り、

Sleep関数はストラテジーテスター上では

実際には処理を止めません。

MessageBoxはテスターでは機能しない

同様に、MessageBoxもストラテジーテスター上では

機能しないことが公式リファレンスに明記されています。

テストで問題が見えないまま本番稼働させない

バックテストで何も問題が起きなかったとしても、

本番のリアルタイム実行では

前述の停止リスクがそのまま残っている点に注意してください。

ChatGPT等が生成したコードへの対処

実際にこれらの関数が紛れ込んでいた場合の直し方を確認します。

コード内にSleep・MessageBoxが無いか検索する

MetaEditorの検索機能で

`Sleep(`・`MessageBox(`という文字列を検索し、

使われている箇所をすべて確認します。

用途ごとに置き換え先を選ぶ

補足
・一定時間待ちたいだけ → GetTickCount()を使った非ブロッキング処理
・ユーザーへの通知が目的 → Print・Comment・Alert・SendMail
・起動時の確認のみ → OnInit()内なら実害は小さいが依然非推奨

置き換え後は必ずバックテストと通して確認する

置き換えたあとは、

既刊backtest-live-gap-mt4.mdで触れた点も踏まえ、

バックテストと可能であればデモ口座での実動作を確認します。

よくある質問

Sleep・MessageBoxについて、よく検索される疑問に回答します。

Sleepをインジケーターで使うとどうなりますか?

MQL4の仕様上、

カスタムインジケーターからのSleep呼び出しは許可されていません。

使用した場合はコンパイルエラーまたは実行時エラーになります。

MessageBoxは絶対に使ってはいけませんか?

人が手動で1回実行するスクリプトの確認用途であれば

問題になりにくいです。

無人稼働を前提とするEAのOnTick()内で使うことは避けてください。

Sleepを使わずに「数秒待つ」処理は作れますか?

作れます。

この記事で紹介したGetTickCount()を使った

時刻比較の書き方に置き換えれば、

ティックを取りこぼさずに同じ目的を実現できます。

【MQL4】SleepとMessageBoxをEAで使うと危険な理由(インジケーターでは使用不可・テスターでは無効):まとめ

SleepとMessageBoxはどちらも、

人がその場で操作することを前提にした関数です。

無人稼働が前提のEAにそのまま使うと、

処理が止まったままティックへの反応が遅れるリスクがあります。

GetTickCount()を使った非ブロッキングな書き方に

置き換えることをおすすめします。

関連記事