【MQL4】時間関数の完全ガイド|TimeCurrent・TimeLocal・TimeToStruct・StructToTimeの使い方

【中級編】MQLプログラムの読み方・書き方

EA(自動売買)を開発していると、「東京時間だけトレードしたい」「金曜日はエントリーを避けたい」など、時間や曜日によって処理を切り替えたい場面が必ず出てきます。

MQL4には時間を扱うための便利な関数がいくつも用意されていますが、サーバー時間とローカル時間の違いや、datetime型と構造体の変換方法など、最初は混乱しやすいポイントも多いです。

この記事では、MQL4の時間関数の中でも特に重要なTimeCurrent・TimeLocal・TimeGMT・TimeToStruct・StructToTimeの5つを中心に、基本の使い方から実践的な時間帯フィルター・曜日フィルターの実装まで、まとめて解説します。

datetime型とは?

MQL4で日時を扱うときの基本データ型がdatetime型です。これは1970年1月1日 00:00:00(UTC)からの経過秒数を整数値として格納する型です。

// datetime型の基本
datetime now = TimeCurrent();
Print(now);             // 例: 1718000000(経過秒数)
Print(TimeToString(now)); // 例: "2024.06.10 12:00:00"(文字列に変換)

内部的にはただの数値なので、秒単位の計算が簡単にできます。例えば「1日後」を求めたければ now + 86400(60秒×60分×24時間)とするだけです。

ただし、datetime型のままでは「今は何月?」「何曜日?」といった情報を直接取り出せません。そこで後述するMqlDateTime構造体TimeToStruct()関数が活躍します。

現在時刻を取得する3つの関数

MQL4で「今の時刻」を取得する関数は3つあります。それぞれ返す時刻の基準が異なるため、目的に応じて使い分けることが重要です。

TimeCurrent() ― サーバー時刻

TimeCurrent()は、ブローカーのサーバー時刻を返します。EA開発では最も頻繁に使う関数で、チャート上のローソク足の時刻もこのサーバー時刻が基準になっています。

注意点として、サーバー時刻のタイムゾーンはブローカーによって異なります。GMT+2やGMT+3を採用しているブローカーが多いですが、必ず自分が使っているブローカーのタイムゾーンを確認しましょう。

TimeLocal() ― PC(ローカル)時刻

TimeLocal()は、MetaTraderが動作しているPC自体の時刻を返します。日本のPCであれば日本時間(GMT+9)が返ります。

TimeGMT() ― GMT時刻

TimeGMT()は、グリニッジ標準時(GMT/UTC)を返します。タイムゾーンの違いを気にせず統一的な基準で時刻を扱いたい場合に便利です。

3つの関数を比較するコード

void OnTick()
{
    datetime server_time = TimeCurrent();
    datetime local_time  = TimeLocal();
    datetime gmt_time    = TimeGMT();

    Print("サーバー時刻: ", TimeToString(server_time, TIME_DATE | TIME_SECONDS));
    Print("ローカル時刻: ", TimeToString(local_time, TIME_DATE | TIME_SECONDS));
    Print("GMT時刻:      ", TimeToString(gmt_time, TIME_DATE | TIME_SECONDS));
}

このコードを実行すると、それぞれの時刻の差を確認できます。例えば日本のPCでGMT+2のブローカーを使っている場合、ローカル時刻はサーバー時刻より7時間進んでいるはずです。

MqlDateTime構造体で時刻を分解する

datetime型は経過秒数という1つの数値ですが、「年」「月」「日」「時」「分」「秒」「曜日」などの個別情報を取り出したい場面は多くあります。そこで使うのがMqlDateTime構造体です。

MqlDateTime構造体には以下の8つのメンバがあり、すべてint型で格納されます。

// MqlDateTime構造体のメンバ一覧
struct MqlDateTime
{
    int year;         // 年(例: 2024)
    int mon;          // 月(1〜12)
    int day;          // 日(1〜31)
    int hour;         // 時(0〜23)
    int min;          // 分(0〜59)
    int sec;          // 秒(0〜59)
    int day_of_week;  // 曜日(0=日曜, 1=月曜, ..., 6=土曜)
    int day_of_year;  // 年初からの通算日数(1月1日=0)
};

day_of_weekは0が日曜日で始まる点に注意してください。月曜日は1、金曜日は5です。FXの取引日で考えると、月曜(1)〜金曜(5)が平日の取引時間帯になります。

TimeToStruct() ― datetime型を構造体に変換

TimeToStruct()は、datetime型の値をMqlDateTime構造体に分解する関数です。「今は何時?」「何曜日?」といった情報を取り出すときに使います。

void OnTick()
{
    datetime now = TimeCurrent();
    MqlDateTime dt;

    // datetime型 → MqlDateTime構造体に変換
    TimeToStruct(now, dt);

    Print("年: ", dt.year);
    Print("月: ", dt.mon);
    Print("日: ", dt.day);
    Print("時: ", dt.hour);
    Print("分: ", dt.min);
    Print("秒: ", dt.sec);
    Print("曜日: ", dt.day_of_week, "(0=日, 1=月, ..., 6=土)");
}

TimeToStruct()の戻り値はbool型で、変換に成功するとtrueを返します。通常の使い方では失敗することは稀ですが、堅牢なコードを書くなら戻り値をチェックするのがベターです。

StructToTime() ― 構造体をdatetime型に変換

StructToTime()はTimeToStruct()の逆で、MqlDateTime構造体の内容をdatetime型に変換します。特定の日時を組み立てたいときに非常に便利です。

例えば、「今日の15時00分00秒」というdatetime値を作りたい場合、次のように書けます。

// 今日の指定時刻をdatetime型で作成する
datetime GetTodayTime(int target_hour, int target_min)
{
    MqlDateTime dt;
    TimeToStruct(TimeCurrent(), dt);  // 現在のサーバー時刻を分解

    // 時・分・秒を上書き
    dt.hour = target_hour;
    dt.min  = target_min;
    dt.sec  = 0;

    return StructToTime(dt);  // MqlDateTime → datetime型に変換
}

void OnTick()
{
    datetime start_time = GetTodayTime(9, 0);   // 今日の09:00
    datetime end_time   = GetTodayTime(18, 30);  // 今日の18:30

    Print("開始: ", TimeToString(start_time));
    Print("終了: ", TimeToString(end_time));
}

このテクニックはEAの時間帯フィルターを作るときに欠かせません。次のセクションで実践的な使い方を見ていきましょう。

【実践】時間帯フィルターの実装

EA開発でよくある要件が「特定の時間帯だけエントリーする」というフィルターです。以下のコードは、開始時刻と終了時刻をパラメータで設定でき、日またぎにも対応した実用的な時間帯フィルターです。

// --- 入力パラメータ ---
input int StartHour = 9;    // 開始時(サーバー時間)
input int StartMin  = 0;    // 開始分
input int EndHour   = 17;   // 終了時(サーバー時間)
input int EndMin    = 30;   // 終了分

// 取引可能な時間帯かどうかを判定する関数
bool IsTradeTime()
{
    MqlDateTime dt;
    TimeToStruct(TimeCurrent(), dt);

    // 現在時刻を「分」に換算して比較
    int current_minutes = dt.hour * 60 + dt.min;
    int start_minutes   = StartHour * 60 + StartMin;
    int end_minutes     = EndHour * 60 + EndMin;

    // 日またぎ対応(例: 22:00〜03:00 の場合)
    if(start_minutes <= end_minutes)
    {
        // 通常パターン(例: 09:00〜17:30)
        return (current_minutes >= start_minutes && current_minutes < end_minutes);
    }
    else
    {
        // 日またぎパターン(例: 22:00〜03:00)
        return (current_minutes >= start_minutes || current_minutes < end_minutes);
    }
}

void OnTick()
{
    if(!IsTradeTime())
    {
        // 取引時間外なので何もしない
        return;
    }

    // ここに通常のエントリーロジックを記述
    // ...
}

ポイントは時刻を「分」に換算して比較している点です。こうすることで、時と分をまとめて1つの数値として扱えるので、条件分岐がシンプルになります。また、日またぎ(開始時刻 > 終了時刻)のケースにも対応しています。

【実践】曜日フィルターの実装

「金曜日はポジションが週末に持ち越されるリスクがあるからエントリーしない」など、曜日で制御したい場合はMqlDateTimeのday_of_weekを使います。

// --- 入力パラメータ ---
input bool TradeMon = true;   // 月曜トレード
input bool TradeTue = true;   // 火曜トレード
input bool TradeWed = true;   // 水曜トレード
input bool TradeThu = true;   // 木曜トレード
input bool TradeFri = false;  // 金曜トレード

// 取引可能な曜日かどうかを判定する関数
bool IsTradeDay()
{
    MqlDateTime dt;
    TimeToStruct(TimeCurrent(), dt);

    switch(dt.day_of_week)
    {
        case 1: return TradeMon;  // 月曜
        case 2: return TradeTue;  // 火曜
        case 3: return TradeWed;  // 水曜
        case 4: return TradeThu;  // 木曜
        case 5: return TradeFri;  // 金曜
        default: return false;    // 土日
    }
}

void OnTick()
{
    if(!IsTradeDay() || !IsTradeTime())
        return;

    // エントリーロジック
    // ...
}

input変数をbool型にしているので、MetaTraderのパラメータ設定画面からチェックボックスで簡単にON/OFFを切り替えられます。先ほどの時間帯フィルターと組み合わせれば、「月〜木の9:00〜17:30だけトレードする」といった細かい制御が可能です。

注意点とTips

サーバー時間と日本時間のズレに注意

ブローカーによってサーバー時間のタイムゾーンは異なります。多くの海外ブローカーはGMT+2(冬時間)/ GMT+3(夏時間)を採用しています。日本時間はGMT+9なので、日本時間との差は6〜7時間になります。

日本時間基準で制御したい場合は、TimeLocal()を使うか、TimeCurrent()に時差を加算する方法があります。ただし、次の注意点も合わせて把握しておきましょう。

バックテスト時のTimeLocal()の挙動

ストラテジーテスター(バックテスト)では、TimeLocal()はTimeCurrent()と同じ値を返します。これはバックテスト時にはPCの現在時刻ではなく、テスト中の仮想時刻が使われるためです。

そのため、TimeLocal()を使ったEAはバックテストでは正確に時間帯フィルターが機能しない場合があります。バックテストとの互換性を考えるなら、TimeCurrent()をベースにして時差をパラメータで調整する設計がおすすめです。

旧来のHour()・Minute()関数との比較

MQL4にはHour()Minute()といった、現在のサーバー時間の時・分を直接返す関数もあります。簡単な用途にはこちらでも十分ですが、TimeToStruct()を使う方法には以下のメリットがあります。

  • 任意のdatetime値に対して使える(過去の時刻の分析にも対応)
  • 曜日や通算日数など、より多くの情報を一度に取得できる
  • MQL5への移行時にもほぼ同じコードが使える

新しくコードを書く場合は、TimeToStruct()を使った方法を推奨します。

まとめ

この記事で紹介した関数・構造体を一覧表で整理します。

関数・型 役割
TimeCurrent() ブローカーのサーバー時刻を取得(最も基本)
TimeLocal() PCのローカル時刻を取得
TimeGMT() GMT(UTC)時刻を取得
TimeToStruct() datetime型 → MqlDateTime構造体に分解
StructToTime() MqlDateTime構造体 → datetime型に変換
MqlDateTime 年・月・日・時・分・秒・曜日を格納する構造体

EA開発での基本パターンは以下の3ステップです。

  1. TimeCurrent()で現在のサーバー時刻を取得する
  2. TimeToStruct()で年・月・日・時・分・秒・曜日に分解する
  3. 分解した情報を使って時間帯や曜日の条件判定を行う

逆に特定の日時をdatetime型で組み立てたいときは、MqlDateTime構造体に値をセットしてからStructToTime()で変換します。

時間関数をマスターすれば、取引時間の制御だけでなく、年末年始の停止処理や重要指標発表時間の回避など、より高度なEAの制御が可能になります。ぜひ実際のコードに組み込んで、使い方を身につけてください。