MT4(MQL4)でEAを自作していると、「いつエントリーするか」「どのタイミングで決済するか」といった時間の制御が非常に重要な課題となります。
本記事では、MT4と日本時間の違い、サマータイムの考慮方法、時間指定によるトレード制御や決済方法まで、時間にまつわるロジックを段階的に解説します。
MQL4での実装例も交えつつ、EA開発に必要な時間制御・時間決済・時間指定ロジックを一通りカバーしているため、読み終える頃には時間処理で迷うことがなくなるでしょう。
EA開発で「時間」の壁に直面している方にとって、実践的なコードと考え方が得られる一記事です。
日本時間とMT4の表示時間は違う

まず、MT4に表示される時間と日本時間に差異があります。
MT4に表示される時間は多くのサーバーがGMT+2 or GMT3です。対して日本時間はGMT+9です。
GMTとは世界の標準時間を表す時間です。GMT+2の場合は標準時間から2時間進んでいる状態です。
たとえば、日本時間の朝7時とは、MT4の時間だと0時 or 1時です。MT4に表示されている時間に+6時間、または+7時間をすれば日本時間になります。
EAのサマータイムについて

MT4の表示時間と日本時間には差がありますが、さらにサマータイムと呼ばれる時間の考慮が必要です。
サマータイムとは、日の出が早まる時期に時計を針を1時間進める考え方です。
時計の針が1時間進んでいる時期を夏時間、それ以外の時間を冬時間と呼んでいます。
MT4はサマータイムの考え方にしたがって動いているわけです。
MT4の表示時間は冬時間の場合はGMT+2、夏時間の場合はGMT+3です。
さらに、サマータイムには米国式、英国式の2種類があります。それぞれ夏時間と冬時間の時期が違っています。
EAを動かす際は2種類のサマータイムを考慮しないと正常な動作をしない場合がありますので注意が必要です。
米国式
英国式
MQLのコードで書いてみる
サマータイムの判定
他サイトから参考にさせてもらったコードです。年が足りなくなったら自身で調べて追加しましょう。
https://auto-ts.net/archives/1926
// inIsUSがtrueの場合米国式、それ以外英国式
bool IsSummerTime(bool inIsUS){
//datetime Time_Summer = 21600; //6時間
//datetime Time_Winter = 25200; //7時間
if(inIsUS){
switch(Year()){
case 2005: if(StringToTime("2005.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2005.11.6"))return true; break;
case 2006: if(StringToTime("2006.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2006.11.5"))return true; break;
case 2007: if(StringToTime("2007.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2007.11.4"))return true; break;
case 2008: if(StringToTime("2008.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2008.11.2"))return true; break;
case 2009: if(StringToTime("2009.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2009.11.1"))return true; break;
case 2010: if(StringToTime("2010.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2010.11.7"))return true; break;
case 2011: if(StringToTime("2011.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2011.11.6"))return true; break;
case 2012: if(StringToTime("2012.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2012.11.4"))return true; break;
case 2013: if(StringToTime("2013.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2013.11.3"))return true; break;
case 2014: if(StringToTime("2014.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2014.11.2"))return true; break;
case 2015: if(StringToTime("2015.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2015.11.1"))return true; break;
case 2016: if(StringToTime("2016.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2016.11.6"))return true; break;
case 2017: if(StringToTime("2017.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2017.11.5"))return true; break;
case 2018: if(StringToTime("2018.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2018.11.4"))return true; break;
case 2019: if(StringToTime("2019.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2019.11.3"))return true; break;
case 2020: if(StringToTime("2020.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2020.11.1"))return true; break;
case 2021: if(StringToTime("2021.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2021.11.7"))return true; break;
case 2022: if(StringToTime("2022.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2022.11.6"))return true; break;
case 2023: if(StringToTime("2023.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2023.11.5"))return true; break;
case 2024: if(StringToTime("2024.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2024.11.3"))return true; break;
case 2025: if(StringToTime("2025.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2025.11.2"))return true; break;
case 2026: if(StringToTime("2026.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2026.11.1"))return true; break;
case 2027: if(StringToTime("2027.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2027.11.7"))return true; break;
case 2028: if(StringToTime("2028.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2028.11.5"))return true; break;
case 2029: if(StringToTime("2029.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2029.11.4"))return true; break;
case 2030: if(StringToTime("2030.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2030.11.3"))return true; break;
case 2031: if(StringToTime("2031.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2031.11.2"))return true; break;
case 2032: if(StringToTime("2032.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2032.11.7"))return true; break;
case 2033: if(StringToTime("2033.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2033.11.6"))return true; break;
case 2034: if(StringToTime("2034.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2034.11.5"))return true; break;
case 2035: if(StringToTime("2035.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2035.11.4"))return true; break;
case 2036: if(StringToTime("2036.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2036.11.2"))return true; break;
case 2037: if(StringToTime("2037.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2037.11.1"))return true; break;
case 2038: if(StringToTime("2038.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2038.11.7"))return true; break;
}
}else{
switch(Year()){
case 2005: if(StringToTime("2005.3.27")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2005.10.30"))return true; break;
case 2006: if(StringToTime("2006.3.26")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2006.10.29"))return true; break;
case 2007: if(StringToTime("2007.3.25")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2007.10.28"))return true; break;
case 2008: if(StringToTime("2008.3.30")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2008.11.26"))return true; break;
case 2009: if(StringToTime("2009.3.29")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2009.11.25"))return true; break;
case 2010: if(StringToTime("2010.3.28")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2010.11.31"))return true; break;
case 2011: if(StringToTime("2011.3.27")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2011.11.30"))return true; break;
case 2012: if(StringToTime("2012.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2012.11.28"))return true; break;
case 2013: if(StringToTime("2013.3.31")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2013.11.27"))return true; break;
case 2014: if(StringToTime("2014.3.30")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2014.11.26"))return true; break;
case 2015: if(StringToTime("2015.3.29")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2015.11.25"))return true; break;
case 2016: if(StringToTime("2016.3.27")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2016.11.30"))return true; break;
case 2017: if(StringToTime("2017.3.26")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2017.11.29"))return true; break;
case 2018: if(StringToTime("2018.3.25")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2018.11.28"))return true; break;
case 2019: if(StringToTime("2019.3.31")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2019.11.27"))return true; break;
case 2020: if(StringToTime("2020.3.29")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2020.11.25"))return true; break;
case 2021: if(StringToTime("2021.3.28")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2021.11.31"))return true; break;
case 2022: if(StringToTime("2022.3.27")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2022.11.30"))return true; break;
}
}
return false;
}
時間指定決済をする場合
MT4時間を取得する関数は以下の通りです。以下の関数を使って時間を比較していきます。
int Hour();
int Minute();
int Seconds();
ある時間になったら決済をしたい等、時間指定決済をしたい場合は以下のようなコードになります。
// 買いポジションを保有している場合
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
// マジックナンバーが一致する場合
if(OrderMagicNumber() == MagicNo) {
// 通貨ペアが一致する場合
if(OrderSymbol() == Symbol()) {
// 買いの場合
if(OrderType() == OP_BUY) {
// 現在時間が買いトレード終了時間の場合
if(Hour() == tradeEndTime) {
// 決済処理
}
}
// 売りの場合
else if(OrderType() == OP_SELL) {
// 現在時間が売りトレード終了時間の場合
// 売り終わり時間の場合
if(Hour() == tradeEndTime) {
// 決済処理
}
}
}
}
}
}
トレードの時間制限
同じように取引の時間制限したい場合は以下のコードになります。
// トレード時間以外の場合
if (Hour() == 20) {
return;
}
たとえば、アジア時間等、ある特定の時間だけ取引をしたい場合があると思います。そんな時は下のコードで取引を制限できます。
MT4の時間で8時から12時の間だけ取引したい場合の例です。
int StartTime = 8; //開始時刻(時)
int EndTime = 20; //終了時刻(時)
isTradeTime = false;
if(StartTime < EndTime) {
if(Hour() <= StartTime && Hour() <= EndTime) {
isTradeTime = true;
}
}
if(StartTime > EndTime) {
if(Hour() >= StartTime || Hour() <= EndTime) {
isTradeTime = true;
}
}
if(isTradeTime){
// トレード処理
}
日本時間の朝8時から昼の12時の間だけ取引したい場合のコードです。
// サマータイムの方式(米国方式の場合true)
bool IsUS = true;
int StartTime = 1; // 開始時刻(時)
int EndTime = 5; // 終了時刻(時)
if(IsSummerTime(IsUS)) {
int StartTime = 2; // 開始時刻(時)
int EndTime = 6; // 終了時刻(時)
}
if(StartTime < EndTime) {
if(Hour() <= StartTime && Hour() <= EndTime) {
isTradeTime = true;
}
}
if(StartTime > EndTime) {
if(Hour() >= StartTime || Hour() <= EndTime) {
isTradeTime = true;
}
}
if(isTradeTime){
// トレード処理
}
一定時間経過後の決済
ポジションを持ってから一定時間経過後に決済をしたい場合のコードです。
int time = 86400; // 一定時間
datetime tradeTime = TimeCurrent() - time;
// 注文チケットを選択
if (OrderSelect(OrderSendなどの注文) {
BuytradeTime = OrderOpenTime();
}
// 注文時の時間と現在の時間の差が一定時間だったら
if (TimeCurrent() - BuytradeTime > time) {
// 決算処理
}
まとめ
MT4でEAを自作する際に欠かせないのが「時間」の制御です。本記事では、日本時間とMT4表示時間のズレ、サマータイムの種類とその判定方法、トレードの開始・終了時間指定や、保有時間による決済方法など、時間にまつわる実装を網羅しています。
時間に悩まされがちなEA開発者にとって、実践的な指針となる内容です。
【要点まとめ】
- MT4は多くがGMT+2またはGMT+3で、日本時間との差を理解する必要がある
- サマータイムは米国式と英国式があり、切り替え日に注意が必要
- サマータイムの有無によってトレード時間を柔軟に変更すべき
- Hour()やTimeCurrent()関数で時間取得が可能
- トレード開始・終了時刻の指定はHour()で管理できる
- 保有時間ベースの決済はOrderOpenTime()とTimeCurrent()で実装可能
- 日本時間に合わせたロジックではGMT補正が必要
- トレード時間の制御により特定セッションだけ取引が可能になる
- サマータイム判定関数の更新を年ごとに行う必要がある
この記事を読めば、EAにおける時間制御の設計と実装がスムーズにできるようになります。
面倒だった時間の壁を超えて、より精度の高いEAが構築できるようになるはずです。