金曜の深夜にポジションを持ったまま放置すると、
月曜の始値が大きく飛ぶ「窓(ギャップ)」や、
数日分のスワップを一気に受け取ってしまうことがあります。
この記事では、金曜日の指定した時刻になったら、
保有中のポジションだけを自動で決済するシンプルなEAを作ります。
・TimeDayOfWeek関数で金曜日だけを判定する方法
・指定時刻をまたいだ瞬間だけ決済する重複防止の設計
・保有中のポジションを一括決済する関数の作り方
・実際に動くEAのコード全体
週末決済EAの全体像
まず、このEAが解決したい問題と、全体の方針を確認します。
なぜ土日をまたぐポジションにリスクがあるのか
・窓(ギャップ): 土日は市場が閉まるため、月曜の始値が金曜の終値から飛ぶことがある
・スワップ: 水曜日のロールオーバーで3日分付与されるのが一般的
・どちらも「持ち越す側」が一方的にリスクを受け取る構造である
このEAが対応するポジションの数
このEAは、自分のEAかどうかを区別せず、
その通貨ペアで保有中のポジションをすべて決済する設計にしています。
マジックナンバーでの絞り込みはオプションにしています。
決済のみ・新規停止はしない設計方針
このEAは決済だけを行い、新規エントリーの停止は行いません。
新規エントリーの停止も含めたい場合は、
既刊istradeallowed-mt4.mdの、
AutoTrading制御と組み合わせてください。
TimeDayOfWeek関数で曜日を判定する
決済タイミングの土台になる、曜日判定の関数を確認します。
TimeDayOfWeekのシグネチャ
int TimeDayOfWeek(datetime date);
渡した`datetime`の曜日を、
0(日曜)から6(土曜)の整数で返します。
DayOfWeek()との違い
・DayOfWeek()は引数を取らず、必ず「現在のサーバー時刻」の曜日しか判定できない
・TimeDayOfWeek(date)は任意の時刻を渡せ、過去の曜日も判定できる
・本記事はTimeCurrent()を渡し、DayOfWeek()と同じ用途で使う
金曜日の判定
int dow = TimeDayOfWeek(TimeCurrent()); bool isFriday = (dow == 5);
0が日曜なので、月曜1・火曜2・水曜3・木曜4と数えると、
金曜日は5になります。
決済タイミングの条件を組み立てる
曜日判定から、実際に決済を実行する条件を作ります。
金曜の指定時刻を過ぎたら決済
int hour = TimeHour(TimeCurrent());
int minute = TimeMinute(TimeCurrent());
bool pastCloseTime = (hour > InpCloseHour) ||
(hour == InpCloseHour && minute >= InpCloseMinute);
`InpCloseHour`・`InpCloseMinute`は、
サーバー時刻での指定時刻です。
ブローカーのサーバー時刻は日本時間と異なるため、
既刊server-time-jst-indicator-mt4.mdの、
換算方法で事前に確認してください。
同じ金曜に何度も決済処理が走らないようにする
static bool closedThisWeek = false; if(dow != 5) closedThisWeek = false;
金曜日以外になった時点でフラグをリセットすることで、
翌週の金曜に再び決済処理が実行されるようにします。
サマータイム・サーバー時刻のズレの注意
ブローカーによってサーバー時刻の基準(GMT+2やGMT+3等)が異なり、
サマータイムの切り替え時期にも1時間ずれることがあります。
決済時刻は余裕を持った値(例: 市場が閉まる1〜2時間前)に設定してください。
全ポジションを決済する関数
実際に決済を行う処理を作ります。
OrdersTotalループで後ろから処理する理由
・決済すると注文リストの番号がずれるため、前から順に処理すると取りこぼしが起きる
・OrdersTotal()-1から0へ向かって後ろから処理すると、ずれの影響を受けない
決済する関数の中身
void CloseAllPositionsOnThisSymbol()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
continue;
if(OrderSymbol() != _Symbol)
continue;
if(InpMagicNumber != 0 && OrderMagicNumber() != InpMagicNumber)
continue;
int type = OrderType();
if(type == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrOrange);
else if(type == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrOrange);
else
OrderDelete(OrderTicket());
}
}
買い・売りのポジションはOrderCloseで決済し、
約定前の予約注文(OP_BUYLIMIT等)はOrderDeleteで取り消します。
InpMagicNumberを0にすると全EA対象になる設計
`InpMagicNumber`を0のまま使うと、
マジックナンバーを問わずその通貨ペアの全ポジションが対象になります。
自分のEAの注文だけに絞りたい場合は、
他のEAと重複しないマジックナンバーを指定してください。
実際に動くEAのコード全体
ここまでの要素をまとめたEAの全体です。
//+------------------------------------------------------------------+
//| WeekendPositionCloseEA.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property strict
input int InpCloseHour = 23; //決済を始める時(サーバー時刻)
input int InpCloseMinute = 0; //決済を始める分
input int InpSlippage = 3; //許容スリッページ
input int InpMagicNumber = 0; //0なら全EA対象、それ以外は一致するEAだけ対象
void CloseAllPositionsOnThisSymbol()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
continue;
if(OrderSymbol() != _Symbol)
continue;
if(InpMagicNumber != 0 && OrderMagicNumber() != InpMagicNumber)
continue;
int type = OrderType();
if(type == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrOrange);
else if(type == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrOrange);
else
OrderDelete(OrderTicket());
}
}
void OnTick()
{
static bool closedThisWeek = false;
int dow = TimeDayOfWeek(TimeCurrent());
if(dow != 5)
{
closedThisWeek = false;
return;
}
if(closedThisWeek)
return;
int hour = TimeHour(TimeCurrent());
int minute = TimeMinute(TimeCurrent());
bool pastCloseTime = (hour > InpCloseHour) ||
(hour == InpCloseHour && minute >= InpCloseMinute);
if(pastCloseTime)
{
CloseAllPositionsOnThisSymbol();
closedThisWeek = true;
Comment("週末決済を実行しました: ", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
}
}
`closedThisWeek`はEAを再起動すると初期値に戻るため、
VPS等で再起動なく連続稼働させることを前提にした設計です。
MetaEditorでのコンパイル・バックテスト手順
実際に動かすまでの手順です。
- MetaEditorで新規EA「WeekendPositionCloseEA」を作成し、上のコードを貼り付けてコンパイルする
- 「0 error(s), 0 warning(s)」になることを確認する
- 手動で任意のポジションを持ち、InpCloseHour・InpCloseMinuteに直近の時刻を設定してチャートに適用する
- 指定時刻を過ぎた最初のティックで決済され、Comment欄にログが表示されることを確認する
よくあるエラーと注意点
実装・運用でつまずきやすいポイントをまとめます。
EAが起動していないと決済されない
・このEAはOnTickでしか動かないため、ティックが来なければ処理も走らない
・取引が閑散とする金曜深夜はティック自体が減ることがある
・決済時刻は余裕を持たせ、VPS等でMT4を起動し続けることが前提になる
OrderCloseの戻り値チェックがない
このコードは解説用にOrderCloseの戻り値チェックを省略しています。
実運用では戻り値がfalseの場合にGetLastError()で原因を調べ、
リトライする処理を追加してください。
暗号資産CFD等、土日も動く銘柄の扱い
一部のブローカーでは暗号資産CFDが土日も取引できる場合があります。
その銘柄にも本EAを適用すると意図せず決済されるため、
対象銘柄ごとにチャートを分けて適用してください。
よくある質問
週末決済EAについて、よく検索される疑問に回答します。
新規エントリーの停止も一緒にできますか?
このEA単体では決済だけを行います。
新規エントリーの停止を含めたい場合は、
既刊istradeallowed-mt4.mdのAutoTradingボタン制御や、
発注前のdow==5チェックを自分のEA側に追加してください。
月曜の再開時刻も設定できますか?
このEAは決済専用のため、再開処理は含んでいません。
月曜の朝だけ新規エントリーを止める、
という逆の制御を作りたい場合は、
既刊weekday-hour-filter-ea-mt4.mdの、
曜日フィルターの考え方が応用できます。
決済時刻を過ぎてもポジションが残ることはありますか?
あります。
ティックが来ない・OrderCloseが失敗する等の理由で、
決済が実行されない可能性はゼロではありません。
重要な口座では手動での最終確認もおすすめします。
【MQL4】土日をまたぐポジションだけ自動で決済するEAの作り方(スワップ・窓リスク対策):まとめ
TimeDayOfWeek関数で金曜日だけを判定し、
指定時刻をまたいだ瞬間だけ決済を実行することで、
窓・スワップのリスクを持ち越さずに週末を迎えられます。
EAが起動し続けていることが前提の仕組みのため、
VPS等での安定稼働と組み合わせて使ってください。
コメント