「日をまたいでポジションを持ちたくない」
「深夜のスワップや窓リスクを避けたい」
「決めた時刻を過ぎたら機械的にポジションを閉じて、感情でホールドし続けるのを防ぎたい」
——こうした理由から、毎日決まった時刻になったら保有中のポジションを自動で決済したい、
という需要があります。
曜日・時間帯でエントリーを止めるEAとは逆に、今回は「既に持っているポジションを時刻で強制決済する」
というシンプルなEAのアイデアです。
この記事では、指定時刻になったら全ポジションを決済するEAの作り方と、
実装でつまずきやすい「指定時刻ちょうどにティックが来るとは限らない」
という問題を、日付フラグと時刻の範囲判定で解決する設計を、実際に動くコードで解説します。
設計の落とし穴: 「時刻が一致したら」は危険
最初に思いつくのは、現在時刻の「時」と「分」が指定値と一致したら決済する、という実装です。
//危険な実装: この分にティックが来なければ一生発動しない if(now.hour == CloseHour && now.min == CloseMinute) CloseAllPositions();
しかしMT4のEAは「時間になったら勝手に呼ばれる」わけではなく、
価格が動いてティックが発生したときにだけ`OnTick()`が呼ばれます。
深夜・早朝や流動性の低い通貨ペアでは、指定した1分間の間に一度もティックが来ないことがあり、
その場合は条件が一度も`true`にならず、その日は決済されないまま素通りしてしまいます。
解決策: 「時刻を過ぎていて、今日はまだ実行していない」で判定する
確実に発動させるには、「指定時刻ちょうど」ではなく「指定時刻を過ぎているかどうか」
で判定し、二重発動を防ぐために「今日はまだ実行していないか」
を別途チェックします。
//安全な実装: 時刻を過ぎていれば、その日最初のティックで発動する
datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));
if(now.hour * 60 + now.min >= CloseHour * 60 + CloseMinute && lastCloseDate != today)
{
CloseAllPositions();
lastCloseDate = today;
}
こうしておけば、指定時刻ちょうどにティックがなくても、その日最初にティックが来たタイミング(指定時刻を過ぎていれば)で確実に決済処理が走ります。
`lastCloseDate`という「最後に実行した日付」を記録しておくことで、
同じ日に何度もポジションを閉じようとする(すでにポジションがない状態で毎ティック処理を試みる)無駄な処理も防げます。
実際に動くコード全体
指定時刻(既定23:50)を過ぎたら、このEA(マジックナンバー)が保有する全ポジションを決済する、
実際にMetaEditorでコンパイルできるEAです。
//+------------------------------------------------------------------+
//| DailyCloseTimeEA.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 int CloseHour = 23;//決済を実行する時刻(時、サーバー時間)
input int CloseMinute = 50;//決済を実行する時刻(分)
input int Slippage = 3;//スリッページ
input int MagicNumber = 20260914;//このEAが管理するポジションのマジックナンバー(0なら全ポジション対象)
datetime lastCloseDate = 0;//最後に決済処理を実行した日(重複実行防止)
//+------------------------------------------------------------------+
//| 対象ポジションを全て決済する |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
continue;
if(OrderSymbol() != Symbol())
continue;
if(MagicNumber != 0 && OrderMagicNumber() != MagicNumber)
continue;
bool closed = false;
if(OrderType() == OP_BUY)
closed = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrRed);
else if(OrderType() == OP_SELL)
closed = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrBlue);
else
continue;//予約注文(指値・逆指値)は対象外、成行ポジションのみ決済する
if(!closed)
Print("チケット#", OrderTicket(), "の決済に失敗しました。エラーコード=", GetLastError());
else
Print("チケット#", OrderTicket(), "を時刻決済しました。");
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
MqlDateTime now;
TimeToStruct(TimeCurrent(), now);
datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));
int nowMinutes = now.hour * 60 + now.min;
int targetMinutes = CloseHour * 60 + CloseMinute;
//指定時刻を過ぎていて、かつ今日はまだ実行していない場合だけ発動する
if(nowMinutes >= targetMinutes && lastCloseDate != today)
{
CloseAllPositions();
lastCloseDate = today;//二重発動を防ぐため、実行した日付を記録する
}
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MT4のMetaEditorで「ファイル」→「新規作成」からウィザードで「Expert Advisor(テンプレートを使用)」を選び、名前を「DailyCloseTimeEA」にして作成する
- テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
- F7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- 「表示」→「ストラテジーテスター」で対象期間・通貨ペアを指定し、CloseHour/CloseMinuteを短い間隔(例: 現在時刻の数分後)に一時的に変更して、決済が実際に発動するかを確認する
- 確認後はCloseHour/CloseMinuteを本来運用したい時刻に戻し、デモ口座でのフォワードテストを経てから本番運用を検討してください
コピペしてコンパイルが通らない・想定通り決済されないときに確認すること
- 拡張子が「.mq4」になっているか
- CloseHour/CloseMinuteの時刻は「サーバー時間」であり、自分の生活時間帯とは異なる点に注意しているか(ブローカーごとにサーバー時間帯がずれる)
- MagicNumberを他のEAと同じ値にしていないか(同じ値だと、別のEAが持っているポジションまで巻き込んで決済してしまう)
- 週末など市場が閉まっている時間帯は`OnTick()`自体が呼ばれないため、金曜のクローズ時刻直前にポジションが残っていると、決済は次の市場再開後(週明け)まで実行されない点に注意する
- OrderClose失敗時にエラーコード135(価格が変わった)が出る場合、Slippageの値を少し大きくしてください
実運用する前に確認しておきたいこと
このEAは「時刻が来たら機械的に決済する」というシンプルな仕組みのため、
含み損の状態で時刻を迎えると、そのまま損失を確定させることになります。
実運用する前に、次の点を確認してください。
- 含み損を抱えたまま決済したくない場合、決済条件に「含み損が一定額以内なら見送る」等の例外を加えるかどうかを検討する
- MagicNumberを指定して、このEA以外が出したポジションを誤って決済しないようにする
- 複数の通貨ペアで同じEAを動かす場合、`OrderSymbol() != Symbol()`のチェックにより、このEAが動いているチャートの通貨ペアだけが対象になる(他の通貨ペアのポジションには影響しない)
- バックテストの結果は過去データに基づくものであり、将来の相場でも同じ挙動になるとは限らない
まずはデモ口座、または少額のロットでのフォワードテストを行ってから、
本番運用を検討してください。
まとめ
決まった時刻に自動でポジションを閉じるEAは、「指定時刻ちょうど」
で判定するとティックが来ない瞬間に発動を逃す危険があります。
「時刻を過ぎているか」と「今日はまだ実行していないか」を組み合わせた日付フラグ方式にすることで、
その日最初のティックで確実に決済処理が走るようになります。
week-time-stop.mdがエントリーを止める側の対策だったのに対し、
この記事は既にあるポジションを時間で片づける側の対策として、
スワップ・窓リスク対策やトレードの規律付けに活用してください。
コメント