EA(自動売買プログラム)を作っていると、「注文を出す前にサーバーと接続できているか確認したい」「バックテスト中は処理を軽くしたい」といった場面に必ず出くわします。こうした場面で活躍するのが、MQL4に用意されたユーティリティ関数たちです。
今回は、EA開発で特に使用頻度が高い以下の6つのユーティリティ関数をまとめて解説します。
- Sleep() — 処理の一時停止
- RefreshRates() — 価格データの最新化
- IsTradeAllowed() — 自動売買の許可状態を確認
- IsConnected() — サーバー接続の確認
- IsTesting() — バックテスト中かどうかの判定
- IsOptimization() — 最適化モードかどうかの判定
それぞれの基本的な使い方から、最後に6つすべてを組み合わせた実践テンプレートまで紹介しますので、ぜひ最後までお読みください。
Sleep() — ミリ秒単位で処理を一時停止する
基本構文
void Sleep(int milliseconds);
Sleep()は、指定したミリ秒(1000ミリ秒=1秒)だけEAの処理を一時停止する関数です。注文のリトライ処理やサーバーとの通信待ちなどで頻繁に使われます。
使用例:注文失敗時のリトライ
注文送信が失敗した場合、少し間をおいてからリトライするのが一般的なパターンです。
int ticket = -1;
int retryCount = 3;
for(int i = 0; i < retryCount; i++)
{
ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Buy Order", 0, 0, clrBlue);
if(ticket > 0)
{
Print("注文成功! チケット番号: ", ticket);
break;
}
else
{
int err = GetLastError();
Print("注文失敗(", i + 1, "回目) エラー: ", err);
Sleep(1000); // 1秒待ってからリトライ
}
}
Sleep()の注意点
- ストラテジーテスターでは無視されます。バックテスト中にSleep()を呼んでも、実際には一時停止しません。テスト速度に影響を与えないための仕様です。
- Sleep()の内部では約0.1秒ごとにEAの停止フラグがチェックされています。そのため、Sleep(10000)(10秒停止)を実行中でも、ユーザーがEAを停止すれば比較的すぐに処理が終了します。
- カスタムインジケーターの中では使用できません。EAおよびスクリプト専用の関数です。
RefreshRates() — 価格データを最新の状態に更新する
基本構文
bool RefreshRates();
RefreshRates()は、Bid、Ask、Volumeなどの定義済み変数を最新のサーバーデータに更新する関数です。更新に成功するとtrueを返します。
なぜRefreshRates()が必要なのか
EAのOnTick()が呼び出された瞬間に、BidやAskには最新の値がセットされます。しかし、その後にSleep()で待機したり、重い計算処理を行ったりすると、BidやAskの値が古くなってしまう可能性があります。
つまり、Sleep()の後にはRefreshRates()を呼ぶのが鉄則です。
使用例:Sleep()とRefreshRates()のセット
// 注文失敗 → 待機 → 価格を更新してリトライ
Sleep(1000);
RefreshRates(); // Bid/Askを最新に更新
// 更新後のAskで再度注文
ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Retry Order", 0, 0, clrBlue);
RefreshRates()を呼ばずに古いAsk値で注文を出すと、「Off quotes(無効な価格)」エラーが発生する原因になります。注意しましょう。
IsTradeAllowed() — 自動売買が許可されているか確認する
基本構文
bool IsTradeAllowed();
IsTradeAllowed()は、EAによる自動売買が許可されている場合にtrueを返す関数です。具体的には、以下の2つの条件を確認しています。
- MetaTraderのツールバーにある「自動売買」ボタンがONになっているか
- 他のEAやスクリプトが取引コンテキストを使用中(ビジー状態)でないか
使用例:注文前の安全チェック
void OnTick()
{
// 自動売買が許可されていなければ何もしない
if(!IsTradeAllowed())
{
Print("自動売買が無効です。ツールバーの自動売買ボタンを確認してください。");
return;
}
// ここから注文ロジック
// ...
}
取引コンテキストのビジー状態に対処する
同一のMetaTrader上で複数のEAが動作している場合、1つのEAが注文処理を行っている間は他のEAの取引がブロックされます。このような場合は、少し待ってから再確認するのが有効です。
// 取引コンテキストが空くまで待機(最大5秒)
for(int i = 0; i < 10; i++)
{
if(IsTradeAllowed())
break;
Print("取引コンテキストがビジー状態です。待機中...");
Sleep(500);
}
IsConnected() — サーバーとの接続状態を確認する
基本構文
bool IsConnected();
IsConnected()は、MetaTraderクライアントがブローカーのサーバーと接続されている場合にtrueを返す関数です。
使用例:接続チェック
void OnTick()
{
if(!IsConnected())
{
Print("サーバーに接続されていません! 注文処理をスキップします。");
return;
}
// 接続確認OK → 通常の処理へ
}
VPS運用時に特に重要
VPS(仮想専用サーバー)でEAを24時間稼働させている場合、ネットワークの一時的な切断は避けられません。IsConnected()で接続状態をチェックし、切断時にはアラートを出すなどの処理を組み込んでおくと安心です。
static datetime lastAlertTime = 0;
if(!IsConnected())
{
// 5分に1回だけアラート
if(TimeCurrent() - lastAlertTime > 300)
{
Alert("サーバー接続が切断されています!");
lastAlertTime = TimeCurrent();
}
return;
}
IsTesting() — バックテスト中かどうかを判定する
基本構文
bool IsTesting();
IsTesting()は、EAがストラテジーテスター上で動作しているときにtrueを返す関数です。ライブ口座やデモ口座で動かしている場合はfalseになります。
使用例:テスト時にGUI処理をスキップして高速化
バックテスト(特にビジュアルモードではない通常テスト)では、画面への描画処理は不要です。Comment()やObjectCreate()といった描画関数をスキップすることで、テスト速度を大幅に向上できます。
// グローバル変数としてフラグを用意
bool gIsTesting = false;
int OnInit()
{
// init()内で1度だけ判定すれば十分
gIsTesting = IsTesting();
return(INIT_SUCCEEDED);
}
void OnTick()
{
// テスト中でなければ画面に情報を表示
if(!gIsTesting)
{
Comment("Bid: ", Bid, " Ask: ", Ask, " Spread: ", MarketInfo(Symbol(), MODE_SPREAD));
}
// 売買ロジック...
}
ポイント:IsTesting()の戻り値はEAの実行中に変わることはありません。そのため、OnInit()内で一度だけ判定してグローバル変数に保存すれば十分です。OnTick()のたびに呼び出す必要はなく、わずかですがパフォーマンスの改善につながります。
IsOptimization() — 最適化モードかどうかを判定する
基本構文
bool IsOptimization();
IsOptimization()は、ストラテジーテスターの最適化モードで実行されているときにtrueを返す関数です。最適化モードでは、パラメータの組み合わせを大量にテストするため、不要な処理を極力省くことが重要になります。
使用例:最適化中はPrint()を抑制する
最適化モードでは、Print()による出力がログに記録されません。つまり、Print()を呼んでもデバッグの役に立たないだけでなく、処理のオーバーヘッドだけが残ります。
bool gIsOptimization = false;
int OnInit()
{
gIsOptimization = IsOptimization();
return(INIT_SUCCEEDED);
}
void OnTick()
{
// 最適化中はデバッグ出力をスキップ
if(!gIsOptimization)
{
Print("現在のBid: ", Bid, " Ask: ", Ask);
}
// 売買ロジック...
}
IsTesting()との使い分け
IsTesting()とIsOptimization()の関係を整理しておきましょう。
| 状態 | IsTesting() | IsOptimization() |
|---|---|---|
| ライブ口座 / デモ口座 | false | false |
| バックテスト(通常) | true | false |
| バックテスト(ビジュアルモード) | true | false |
| 最適化モード | true | true |
最適化モードのときはIsTesting()もtrueになります。つまり「IsTesting()がtrueかつIsOptimization()がfalse」であれば通常のバックテスト、「両方ともtrue」であれば最適化中ということになります。
実践テンプレート:6つの関数を組み合わせた安全な注文処理
ここまで紹介した6つの関数をすべて組み合わせた、実践的な注文処理テンプレートを紹介します。実際のEA開発でそのまま活用できる構成です。
//--- グローバル変数
bool gIsTesting = false;
bool gIsOptimization = false;
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 実行環境フラグを初期化時に1度だけ判定
gIsTesting = IsTesting();
gIsOptimization = IsOptimization();
if(!gIsOptimization)
Print("EA初期化完了 テストモード: ", gIsTesting);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 安全な買い注文関数 |
//+------------------------------------------------------------------+
int SafeBuyOrder(double lots, int slippage, double sl, double tp, string comment)
{
int maxRetry = 3;
int ticket = -1;
//--- 1. サーバー接続チェック(テスト時はスキップ)
if(!gIsTesting && !IsConnected())
{
Print("エラー: サーバーに接続されていません");
return(-1);
}
//--- 2. 自動売買許可チェック
if(!IsTradeAllowed())
{
Print("エラー: 自動売買が許可されていません");
return(-1);
}
//--- 3. リトライループ
for(int i = 0; i < maxRetry; i++)
{
// 価格データを最新に更新
RefreshRates();
// 注文送信
ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, slippage, sl, tp, comment, 0, 0, clrBlue);
if(ticket > 0)
{
if(!gIsOptimization)
Print("買い注文成功! チケット: ", ticket, " 価格: ", Ask);
break;
}
else
{
int err = GetLastError();
if(!gIsOptimization)
Print("買い注文失敗(", i + 1, "/", maxRetry, ") エラーコード: ", err);
// 最後のリトライでなければ待機
if(i < maxRetry - 1)
{
Sleep(1000); // 1秒待機(テスターでは無視される)
}
}
}
return(ticket);
}
//+------------------------------------------------------------------+
//| ティックごとの処理 |
//+------------------------------------------------------------------+
void OnTick()
{
//--- 画面表示(通常バックテスト・最適化時はスキップ)
if(!gIsTesting)
{
Comment("EA稼働中 | Bid: ", Bid, " | Ask: ", Ask,
" | 接続: ", (IsConnected() ? "OK" : "NG"),
" | 自動売買: ", (IsTradeAllowed() ? "許可" : "不可"));
}
//--- ここに売買条件を記述 ---
// 例: 買い条件を満たしたら注文
// int ticket = SafeBuyOrder(0.1, 3, 0, 0, "Sample EA");
}
//+------------------------------------------------------------------+
//| 終了処理 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(!gIsOptimization)
Print("EA停止 理由コード: ", reason);
// テスト時でなければコメントをクリア
if(!gIsTesting)
Comment("");
}
このテンプレートでは、以下のポイントを押さえています。
- OnInit()で環境フラグを一度だけ判定 — IsTesting()やIsOptimization()を毎ティック呼ぶ無駄を排除
- 注文前にIsConnected()とIsTradeAllowed()をチェック — 接続切れや自動売買無効時のエラーを未然に防止
- リトライ時にSleep() + RefreshRates()をセットで使用 — 待機後に最新価格を取得してから再注文
- 最適化中はPrint()をスキップ — 不要な処理のオーバーヘッドを削減
- テスト中はComment()による画面描画をスキップ — バックテストの高速化
まとめ
今回紹介した6つのユーティリティ関数を一覧表で振り返りましょう。
| 関数名 | 用途 | 主な使いどころ |
|---|---|---|
| Sleep() | 処理の一時停止 | 注文リトライ時の待機 |
| RefreshRates() | 価格データの更新 | Sleep()の後、重い計算の後 |
| IsTradeAllowed() | 自動売買許可の確認 | 注文送信前のチェック |
| IsConnected() | サーバー接続の確認 | 注文送信前、VPS運用時 |
| IsTesting() | バックテスト判定 | GUI処理のスキップ |
| IsOptimization() | 最適化モード判定 | Print()の抑制 |
これらの関数は単体で使うだけでなく、組み合わせて使うことで真価を発揮します。特に「Sleep() → RefreshRates()」のセットや、「IsTesting() / IsOptimization()による処理の出し分け」は、EA開発における定番テクニックです。
今回紹介した実践テンプレートをベースに、ご自身のEAに安全で効率的な処理を組み込んでみてください。堅牢なEAを作る第一歩になるはずです。

