1. MQL5のCopyTimeとは何か
MQL5の CopyTime は、指定した通貨ペアと時間足の バー(ローソク足)の時間情報を取得するための関数です。
ここでいう「時間」とは、ローソク足の 開始時刻(バーのオープン時間) を指します。
MetaTrader 5(MT5)では、価格データは次のような要素で構成されています。
- 時間(datetime)
- 始値(Open)
- 高値(High)
- 安値(Low)
- 終値(Close)
- 出来高(Volume)
このうち CopyTimeは「時間」だけを取得する関数です。
取得した時間データは datetime型の配列に格納され、EA(自動売買)やインジケーターのロジックで使用できます。
例えば、EA開発では次のような用途でよく使われます。
- 新しいバー(ローソク足)が生成されたかを検出する
- 過去バーの時間を確認する
- 複数の時間足データを同期する
- インジケーター計算の基準時間を取得する
特に重要なのは 新バー検出(New Bar Detection)です。
EAを作るとき、毎Tick(価格更新のたび)に売買判断すると、同じバーで何度もエントリーしてしまう可能性があります。
そのため、次のような設計がよく使われます。
- 新しいバーが出た瞬間だけロジックを実行する
- 同一バー内では処理を行わない
この判定に CopyTimeが非常によく使われます。
1.1 CopyTimeの基本役割
CopyTimeの役割は非常にシンプルです。
指定したシンボルと時間足のバー時間を取得する
取得された時間は datetime型(日時データ型)として配列に格納されます。
datetimeは 「秒単位のタイムスタンプ」を扱うMQL5の基本型です。
典型的な取得イメージは次の通りです。
| インデックス | 内容 |
|---|---|
| time[0] | 最新バーの開始時間 |
| time[1] | 1本前のバー |
| time[2] | 2本前のバー |
ただし、ここで初心者がつまずきやすいポイントがあります。
よくある注意点
1. 配列の向き(インデックス順)
MQLでは配列の並び順を変更できます。
多くのEAでは次の設定を使います。
ArraySetAsSeries(array,true);
この設定を行うと
index0 = 最新バー
index1 = 1本前
になります。
設定しない場合は 逆順になる可能性があり、ロジックが崩れる原因になります。
2. CopyTimeは時間だけを取得する
初心者がよく混同する関数に次があります。
| 関数 | 取得内容 |
|---|---|
| CopyTime | バー時間 |
| CopyRates | OHLC(価格データ) |
| CopyBuffer | インジケーター値 |
つまりCopyTimeは
価格ではなく時間だけ取得する
関数です。
3. データが取得できないケース
環境によってはCopyTimeが -1を返す(取得失敗)ことがあります。
主な原因
- チャート履歴がロードされていない
- 通貨ペアが無効
- タイムフレーム指定ミス
- データ不足
この場合は 履歴ロードやシンボル確認が必要になります。
CopyTimeはシンプルな関数ですが、EA開発では
- 新バー判定
- データ同期
- 時間管理
といった重要な役割を担います。
2. CopyTimeの基本構文
CopyTimeを正しく使うためには、まず 関数の構文(シグネチャ)と 各引数の意味を理解する必要があります。
MQL5では価格データの取得系関数は似た構造を持っており、CopyTimeも同様の設計になっています。
CopyTimeの基本構文は次の通りです。
int CopyTime(
string symbol,
ENUM_TIMEFRAMES timeframe,
int start_pos,
int count,
datetime &time_array[]
);
この関数は、指定したシンボルと時間足のバー時間を取得し、datetime型配列にコピーします。
戻り値は コピーされたバー数です。
取得に失敗した場合は -1 が返ります。
2.1 CopyTimeの各引数の意味
CopyTimeには5つの引数があります。
それぞれの役割を理解しておくと、他のCopy系関数(CopyRates / CopyBufferなど)も理解しやすくなります。
| 引数 | 型 | 説明 |
|---|---|---|
| symbol | string | 通貨ペア(例:EURUSD) |
| timeframe | ENUM_TIMEFRAMES | 時間足(例:PERIOD_M15) |
| start_pos | int | 取得開始位置 |
| count | int | 取得するバー数 |
| time_array | datetime配列 | 結果を格納する配列 |
以下でそれぞれを解説します。
symbol(通貨ペア)
取得対象となる 金融商品(シンボル)を指定します。
例
"EURUSD"
または現在のチャートを使う場合は
_Symbol
を使うのが一般的です。
timeframe(時間足)
取得する 時間足(タイムフレーム)を指定します。
例
| 時間足 | 定数 |
|---|---|
| M1 | PERIOD_M1 |
| M5 | PERIOD_M5 |
| M15 | PERIOD_M15 |
| H1 | PERIOD_H1 |
| D1 | PERIOD_D1 |
現在のチャートの時間足を使用する場合は
_Period
を使うと便利です。
start_pos(取得開始位置)
どのバーから取得するかを指定します。
例
| 値 | 意味 |
|---|---|
| 0 | 最新バー |
| 1 | 1本前 |
| 2 | 2本前 |
通常は 0(最新バー)から取得します。
count(取得バー数)
取得するバー数です。
例
1
なら 最新バーのみ取得。
10
なら 直近10本のバー時間を取得します。
注意点として、配列サイズより多く取得すると失敗する場合があります。
time_array(datetime配列)
取得した時間を格納する配列です。
datetime型は 日時データ型で、バーの開始時間が格納されます。
例
datetime time[];
2.2 戻り値の意味
CopyTimeは 取得したバー数を整数で返します。
例
int copied = CopyTime(_Symbol,_Period,0,10,time);
成功した場合
copied = 10
失敗した場合
copied = -1
になります。
よくある失敗
初心者がつまずく典型例があります。
配列サイズ不足
配列サイズを確保していない場合、取得に失敗することがあります。
悪い例
datetime time[];
CopyTime(_Symbol,_Period,0,10,time);
安全な例
datetime time[];
ArrayResize(time,10);
CopyTime(_Symbol,_Period,0,10,time);
データ履歴不足
特定の時間足で履歴が不足していると取得できないことがあります。
例
- 新規チャート
- データ未ロード
この場合
- チャートをスクロールする
RefreshRates()を呼ぶ
などで解決する場合があります。
CopyTimeは構文自体はシンプルですが、配列管理とデータ取得の仕組みを理解しておくことが重要です。
3. CopyTimeの基本的な使用例
CopyTimeは、実際のEA開発では コードの中で時間データを取得する処理として使用されます。
ここでは、初心者でも理解しやすい 基本的な使用例を紹介します。
主に次の2パターンを覚えておくと実務で困りません。
- 最新バーの時間を取得する
- 複数のバー時間を取得する
3.1 最新バーの時間を取得する例
最も基本的な使い方は、最新バーの開始時間を取得する方法です。
コード例
void OnTick()
{
datetime time[];
ArrayResize(time,1);
int copied = CopyTime(_Symbol,_Period,0,1,time);
if(copied > 0)
{
Print("最新バーの時間: ",time[0]);
}
}
コードの流れ
- datetime配列を作成
- 配列サイズを1に設定
- CopyTimeで最新バーを取得
- 成功したら時間を表示
このコードを実行すると、ログに次のような情報が出ます。
最新バーの時間: 2026.03.15 10:00
この時間は ローソク足の開始時間です。
例えば
| 時間足 | 表示される時間 |
|---|---|
| M5 | 10:00 |
| M15 | 10:00 |
| H1 | 10:00 |
つまり そのバーが開始した時刻になります。
3.2 複数バーの時間を取得する例
過去のバー時間をまとめて取得したい場合は、countを増やします。
例
void OnTick()
{
datetime time[];
ArrayResize(time,5);
int copied = CopyTime(_Symbol,_Period,0,5,time);
if(copied > 0)
{
for(int i=0;i<copied;i++)
{
Print("time[",i,"] = ",time[i]);
}
}
}
このコードでは 直近5本のバー時間を取得します。
ログ出力例
time[0] = 2026.03.15 10:00
time[1] = 2026.03.15 09:55
time[2] = 2026.03.15 09:50
time[3] = 2026.03.15 09:45
time[4] = 2026.03.15 09:40
ただし、ここで 重要な注意点があります。
つまずきやすいポイント
配列の向き
配列の向きによってインデックスの意味が変わります。
通常EAでは次の設定を行います。
ArraySetAsSeries(time,true);
この設定を行うと
| index | 内容 |
|---|---|
| 0 | 最新バー |
| 1 | 1本前 |
| 2 | 2本前 |
になります。
設定しない場合は 逆順になることがあります。
CopyTimeの戻り値チェック
CopyTimeの戻り値を確認しないと、取得失敗に気づかないことがあります。
悪い例
CopyTime(_Symbol,_Period,0,5,time);
安全な例
if(CopyTime(_Symbol,_Period,0,5,time) <= 0)
{
Print("CopyTime失敗");
}
データ不足エラー
取得バー数が履歴より多い場合
CopyTime = -1
になることがあります。
例えば
- 新しいチャート
- 古い時間足
ではデータが不足する場合があります。
この場合
- チャート履歴をロードする
- バー数を減らす
ことで解決する場合があります。
CopyTimeは 時間取得専用の関数ですが、EA開発では非常に重要です。
特に 新バー検出ロジックで多用されます。
4. CopyTimeを使った新バー判定(New Bar Detection)
EA(自動売買)開発でCopyTimeが最もよく使われる用途は、新しいローソク足が生成されたかを検出する処理(新バー判定)です。
MT5のEAは通常 Tickごと(価格更新ごと) に OnTick() が実行されます。
しかし、そのまま売買ロジックを書くと 同じバーの中で何度もエントリーしてしまう可能性があります。
例:
1本のローソク足の中で100回Tickが来る
↓
売買条件が成立
↓
100回エントリー
これを防ぐため、EAでは次の設計が一般的です。
新しいバーが生成されたときだけロジックを実行する
このときに使われるのが CopyTimeによるバー時間の比較です。
4.1 新バー判定の基本ロジック
基本的な考え方はシンプルです。
- 最新バーの時間を取得
- 前回のバー時間と比較
- 時間が変わったら新バー
図で表すと次のようになります。
| Tick | バー時間 |
|---|---|
| 1 | 10:00 |
| 2 | 10:00 |
| 3 | 10:00 |
| 4 | 10:05 ← 新バー |
この 時間の変化を検出します。
4.2 CopyTimeを使った新バー判定コード
実務でよく使われる基本コードです。
datetime last_bar_time = 0;
void OnTick()
{
datetime time[];
ArrayResize(time,1);
if(CopyTime(_Symbol,_Period,0,1,time) <= 0)
return;
if(time[0] != last_bar_time)
{
last_bar_time = time[0];
Print("新しいバーが生成されました");
// ここに売買ロジックを書く
}
}
コードの流れ
- 最新バー時間を取得
- 前回時間と比較
- 違えば新バー
- ロジック実行
この方法を使うと 1バーにつき1回だけ処理が実行されます。
4.3 EA設計での典型的な使い方
新バー判定は次のようなロジックで使われます。
if(NewBar())
{
CheckSignal();
ExecuteTrade();
}
つまり
新バー
↓
シグナル判定
↓
トレード実行
という設計になります。
この構造にすると
- 同一バーでの多重エントリー防止
- CPU負荷軽減
- ロジック安定化
などのメリットがあります。
よくある失敗
last_bar_timeの初期化忘れ
初回Tickで比較対象がないと誤動作する場合があります。
対策
if(last_bar_time == 0)
{
last_bar_time = time[0];
return;
}
配列サイズ未設定
CopyTime前に配列サイズを確保しないと取得失敗することがあります。
ArrayResize(time,1);
は必ず行います。
CopyTime失敗チェック不足
CopyTimeが失敗すると time[0]は未定義になります。
必ず戻り値を確認します。
if(CopyTime(_Symbol,_Period,0,1,time) <= 0)
return;
CopyTimeを使う理由
新バー判定には次の方法もあります。
| 方法 | 特徴 |
|---|---|
| TimeCurrent | サーバ時間 |
| Bars | バー数 |
| CopyTime | バー時間 |
その中でも CopyTimeが最も正確です。
理由
- バー時間を直接取得
- タイムフレーム依存が少ない
- EA実装が安定
そのため、多くのEA開発者が CopyTime方式を採用しています。
CopyTimeは新バー判定以外にも、過去バー分析や時間同期などに利用できます。
5. CopyTimeの応用例(過去バー取得・時間足同期)
CopyTimeは新バー判定だけでなく、過去データの時間取得や複数時間足の同期処理にも使われます。
EAやインジケーター開発では、次のような用途で利用されることが多いです。
- 過去バーの時間を確認する
- 複数時間足のバー時間を同期する
- 特定時間のバーを探す
ここでは実務でよく使われる 代表的な応用パターンを解説します。
5.1 過去バー時間を取得する
過去のバー時間を取得する場合は、count を増やして取得します。
コード例
void OnTick()
{
datetime time[];
ArrayResize(time,10);
int copied = CopyTime(_Symbol,_Period,0,10,time);
if(copied <= 0)
{
Print("CopyTime失敗");
return;
}
for(int i=0;i<copied;i++)
{
Print("time[",i,"] = ",time[i]);
}
}
このコードでは 直近10本のバー時間を取得します。
取得結果イメージ
time[0] = 2026.03.15 10:00
time[1] = 2026.03.15 09:55
time[2] = 2026.03.15 09:50
このデータを使うことで
- 過去バー比較
- 時間フィルター
- 特定時間トレード
などのロジックを作れます。
5.2 特定時間のバーを検索する
トレード戦略によっては 特定時間のバーを判定する場合があります。
例
- ロンドンオープン
- ニューヨークオープン
- 東京市場開始
例コード
datetime time[];
ArrayResize(time,1);
if(CopyTime(_Symbol,_Period,0,1,time) > 0)
{
MqlDateTime t;
TimeToStruct(time[0],t);
if(t.hour == 9 && t.min == 0)
{
Print("9:00バーです");
}
}
このコードでは 9:00のバーを検出します。
注意点として
ブローカーのサーバー時間を使用する
ため、
- GMT+2
- GMT+3
など環境によって時間が異なります。
5.3 複数時間足の同期
EA開発では 複数時間足のデータを組み合わせることがよくあります。
例
- M5エントリー
- H1トレンドフィルター
この場合、各時間足のバー時間を取得して 同期させる必要があります。
コード例
datetime time_m5[];
datetime time_h1[];
ArrayResize(time_m5,1);
ArrayResize(time_h1,1);
CopyTime(_Symbol,PERIOD_M5,0,1,time_m5);
CopyTime(_Symbol,PERIOD_H1,0,1,time_h1);
Print("M5: ",time_m5[0]);
Print("H1: ",time_h1[0]);
取得例
M5: 10:05
H1: 10:00
このように
時間足によってバー開始時間が異なる
ことが確認できます。
つまずきやすいポイント
ブローカー時間の違い
MT5は サーバー時間ベースです。
つまり
| 環境 | サーバー時間 |
|---|---|
| ブローカーA | GMT+2 |
| ブローカーB | GMT+3 |
になる場合があります。
そのため 時間ロジックは環境依存になる場合があります。
データ未ロード
他の時間足を使う場合、履歴がロードされていないと
CopyTime = -1
になることがあります。
対策
- チャートで時間足を一度表示
- バックテスト環境で履歴ロード
配列サイズ不足
配列サイズより多く取得すると失敗する場合があります。
安全例
ArrayResize(time,100);
CopyTime(_Symbol,_Period,0,100,time);
CopyTimeは 時間データ取得の基本関数であり、EAの多くのロジックの基盤になります。
6. CopyTimeが失敗する原因と対処法
CopyTimeは構文自体は単純ですが、実際の開発では 「なぜか値が取れない」「-1が返る」 という場面がよくあります。
特に初心者は、コードの書き方よりも データ取得条件 でつまずきやすいです。
ここでは、CopyTimeで失敗しやすい代表パターンと、その対処法を整理します。
6.1 戻り値が -1 になる主な原因
CopyTimeは、正常に取得できた場合は コピーした本数 を返し、失敗した場合は -1 を返します。
そのため、まず最初にやるべきことは 戻り値の確認 です。
基本形
datetime time[];
ArrayResize(time,10);
int copied = CopyTime(_Symbol,_Period,0,10,time);
if(copied == -1)
{
Print("CopyTimeの取得に失敗しました");
return;
}
-1 になる原因は主に次の通りです。
- シンボル指定が不正
- 時間足指定が不正
- 履歴データが不足している
- 配列の扱いが不適切
- 取得直後でまだデータ準備が完了していない
6.2 シンボルや時間足の指定ミス
最も基本的な失敗は、symbol や timeframe の指定ミスです。
例
CopyTime("EURUSD",PERIOD_H1,0,10,time);
この書き方自体は正しいですが、環境によってはブローカー側のシンボル名が次のように異なることがあります。
- EURUSD
- EURUSD.a
- EURUSDm
つまり、見た目は同じ通貨ペアでも、実際のシンボル名は口座環境で異なる場合があります。
安全策としては、現在のチャートに対して処理するなら次を使うのが基本です。
CopyTime(_Symbol,_Period,0,10,time);
これなら 現在のチャートと一致したシンボル・時間足 が使われるため、初歩的なミスを減らせます。
6.3 履歴データが足りない
CopyTimeは、ターミナル内に 対象時間足の履歴データが存在していること が前提です。
履歴が不足していると、正しいコードでも取得に失敗することがあります。
典型例
- MT5を起動した直後
- 一度も開いていない通貨ペア・時間足
- 長い過去本数を要求した場合
例えば、次のコードで1000本取得したいとしても、
datetime time[];
ArrayResize(time,1000);
int copied = CopyTime(_Symbol,_Period,0,1000,time);
チャート側に十分な履歴がなければ、期待通りに取得できないことがあります。
対処法
- 対象チャートを開いて履歴を読み込む
- 取得本数を減らして試す
- 初回は少数本で動作確認する
初心者は最初から大量データを取ろうとしがちですが、まずは 1本、5本、10本 など小さく確認した方が安全です。
6.4 配列サイズや配列管理の問題
CopyTimeでは、取得先として datetime配列 を渡します。
このとき、配列サイズや配列の向きでつまずくことがよくあります。
基本例
datetime time[];
ArrayResize(time,10);
int copied = CopyTime(_Symbol,_Period,0,10,time);
よくある失敗は次です。
配列サイズを意識せずに使う
環境や書き方によっては、動的配列でも期待通りに扱えないケースがあります。
そのため、初心者は 事前にArrayResizeで必要サイズを確保する 形に統一した方が安全です。
ArraySetAsSeriesを忘れる
新しいバーを time[0] で扱う前提なら、配列方向の意識が必要です。
ArraySetAsSeries(time,true);
これを入れておけば、一般的なEAロジックで想定しやすい
time[0]= 最新バーtime[1]= 1本前
の形になります。
この設定を忘れると、ロジックは動いているのに判定だけズレる という厄介な不具合が起きます。
6.5 取得直後でデータ準備が終わっていない
MT5では、要求した時系列データが すぐに利用可能とは限らない 場面があります。
特に他シンボルや他時間足を扱う場合、内部で履歴準備が追いついていないことがあります。
この場合、コード上は正しくても初回取得で失敗することがあります。
実務上の対策は次です。
- 1回失敗したら即ロジックを進めない
- 次のTickで再取得する
- 取得失敗時は return して抜ける
例
datetime time[];
ArrayResize(time,1);
int copied = CopyTime(_Symbol,_Period,0,1,time);
if(copied <= 0)
{
Print("まだ時系列データを取得できません");
return;
}
このようにしておけば、取得失敗時に未定義データを参照する事故 を防げます。
6.6 よくある失敗パターンまとめ
初心者が特にやりやすい失敗は次の通りです。
- 戻り値を確認しない
_Symbolではなく固定文字列を雑に使う- いきなり大量データを取ろうとする
ArraySetAsSeriesを忘れる- 取得失敗後も
time[0]をそのまま読む
安全な基本形は次です。
datetime time[];
ArrayResize(time,1);
ArraySetAsSeries(time,true);
int copied = CopyTime(_Symbol,_Period,0,1,time);
if(copied <= 0)
{
Print("CopyTime失敗");
return;
}
Print("最新バー時間: ",time[0]);
この形を土台にすると、CopyTime関連の初歩的なミスはかなり減らせます。
7. CopyTimeを使うときの実務上の注意点(パフォーマンスと設計)
CopyTimeは便利な関数ですが、EA設計では 呼び出し回数や使い方によってパフォーマンスやロジックの安定性に影響します。
特に実運用EAでは、次のポイントを理解しておくことが重要です。
- CopyTimeの呼び出し頻度
- 新バー判定の設計
- データ取得の最適化
- CopyRatesとの使い分け
7.1 Tickごとに大量のCopyTimeを呼ばない
MT5のEAは TickごとにOnTick()が実行されます。
例えば、流動性の高い通貨ペアでは
- 1秒に数回〜数十回Tickが発生
することもあります。
そのため、次のようなコードを書くと 無駄なデータ取得が増える可能性があります。
void OnTick()
{
datetime time[];
ArrayResize(time,100);
CopyTime(_Symbol,_Period,0,100,time);
}
この場合
Tickごとに100本のバー時間取得
が実行されます。
通常は 最新バー1本だけ取得すれば十分です。
安全な設計
datetime time[];
ArrayResize(time,1);
CopyTime(_Symbol,_Period,0,1,time);
これだけで 新バー判定や時間取得は十分可能です。
7.2 新バー判定を関数化すると管理しやすい
EAが大きくなると、コードの可読性が重要になります。
そのため、新バー判定は 専用関数として分離する設計がよく使われます。
例
bool IsNewBar()
{
static datetime last_time = 0;
datetime time[];
ArrayResize(time,1);
if(CopyTime(_Symbol,_Period,0,1,time) <= 0)
return false;
if(time[0] != last_time)
{
last_time = time[0];
return true;
}
return false;
}
使用例
void OnTick()
{
if(IsNewBar())
{
Print("新バー検出");
}
}
この形にすると
- ロジック整理
- バグ減少
- 再利用性向上
というメリットがあります。
7.3 CopyRatesとの使い分け
CopyTimeは 時間だけ取得する関数です。
しかし、多くのEAでは価格データも必要になります。
その場合は CopyRatesを使う方が効率的です。
| 関数 | 取得データ |
|---|---|
| CopyTime | 時間 |
| CopyRates | OHLC + 時間 |
例
MqlRates rates[];
ArrayResize(rates,1);
CopyRates(_Symbol,_Period,0,1,rates);
取得できる情報
rates[0].time
rates[0].open
rates[0].high
rates[0].low
rates[0].close
つまり
- 時間だけ必要 → CopyTime
- 価格も必要 → CopyRates
という使い分けになります。
7.4 マルチタイムフレームEAでの注意
複数時間足を使うEAでは、CopyTimeの呼び方にも注意が必要です。
例
CopyTime(_Symbol,PERIOD_M5,0,1,time_m5);
CopyTime(_Symbol,PERIOD_H1,0,1,time_h1);
この場合、次のような状況が発生します。
M5バー更新
↓
H1バーはまだ更新されていない
つまり
時間足ごとに新バータイミングが異なる
ことを理解しておく必要があります。
設計を誤ると
- エントリータイミングズレ
- シグナル不一致
が起きます。
7.5 バックテスト環境での挙動
CopyTimeは バックテストでも正常に動作しますが、次の点に注意が必要です。
- テスターはTick生成方式に依存
- 時系列ロードタイミングが異なる
- 初回取得タイミングがズレることがある
そのため、次の基本ルールを守ると安定します。
- 戻り値チェックを必ず行う
- 未取得時は処理をスキップ
- 初期Tickを特別扱いしない
7.6 CopyTime設計の基本ルール
EA設計でCopyTimeを使うときの基本ルールをまとめます。
基本ルール
- 必ず戻り値をチェックする
- 取得本数は最小限にする
- 新バー判定は関数化する
_Symbol_Periodを優先使用- 配列サイズを明示する
安全なテンプレート
datetime time[];
ArrayResize(time,1);
ArraySetAsSeries(time,true);
int copied = CopyTime(_Symbol,_Period,0,1,time);
if(copied <= 0)
return;
このテンプレートをベースにすると、CopyTimeの実装で大きな問題が起きる可能性はかなり低くなります。
8. MQL5 CopyTimeのまとめ(初心者が覚えるべきポイント)
ここまで、MQL5の CopyTime関数の役割・構文・使用例・実務上の注意点を解説しました。
CopyTimeは構文自体はシンプルですが、EA開発では 時間管理の基盤となる重要な関数です。
最後に、初心者が最低限覚えておくべきポイントを整理します。
8.1 CopyTimeの基本役割
CopyTimeは ローソク足の開始時間を取得する関数です。
取得されるデータ
| データ | 内容 |
|---|---|
| time | バーの開始時間(datetime) |
そのため、次のような用途で使われます。
- 新バー判定
- 時間フィルター
- 過去バー分析
- マルチタイムフレーム同期
特にEAでは 新バー検出ロジックで頻繁に使用されます。
8.2 CopyTimeの基本構文
基本形は次の通りです。
int CopyTime(
string symbol,
ENUM_TIMEFRAMES timeframe,
int start_pos,
int count,
datetime &time_array[]
);
主なポイント
- symbol → 通貨ペア
- timeframe → 時間足
- start_pos → 開始バー位置
- count → 取得本数
- time_array → datetime配列
戻り値は
- 成功 → コピーしたバー数
- 失敗 → -1
です。
8.3 EA開発で最も多い使用パターン
実務で最もよく使われるのは 最新バー時間の取得です。
例
datetime time[];
ArrayResize(time,1);
int copied = CopyTime(_Symbol,_Period,0,1,time);
if(copied > 0)
{
Print(time[0]);
}
この時間を保存して比較することで
新しいバーが生成されたか
を判定できます。
8.4 CopyTime使用時の重要ポイント
CopyTimeを安全に使うために、次のポイントを意識してください。
戻り値を必ずチェックする
取得失敗時に time[0] を使うと、未定義データになる可能性があります。
if(CopyTime(_Symbol,_Period,0,1,time) <= 0)
return;
配列サイズを確保する
ArrayResize(time,1);
を事前に行うと安全です。
_Symbol と _Period を使う
固定文字列よりも、現在のチャートに合わせた指定の方が安全です。
CopyTime(_Symbol,_Period,0,1,time);
配列の向きを意識する
EAでは通常次を設定します。
ArraySetAsSeries(time,true);
これにより
| index | 内容 |
|---|---|
| 0 | 最新バー |
| 1 | 1本前 |
になります。
8.5 CopyTimeと他のCopy系関数の違い
MQL5には似た関数が複数あります。
| 関数 | 内容 |
|---|---|
| CopyTime | バー時間 |
| CopyRates | OHLC + 時間 |
| CopyBuffer | インジケーター値 |
そのため
- 時間だけ必要 → CopyTime
- 価格も必要 → CopyRates
という使い分けが一般的です。
8.6 CopyTimeを理解するとできること
CopyTimeを理解すると、EAの次の機能が作れるようになります。
- 新バー検出EA
- 時間フィルターEA
- セッション戦略
- マルチタイムフレーム戦略
- ボラティリティ時間分析
つまり、ほぼすべてのEA設計の基礎になる関数です。
9. FAQ(よくある質問)
Q1. MQL5のCopyTimeとは何ですか?
CopyTimeは、指定したシンボルと時間足のローソク足の開始時間を取得する関数です。
取得された時間は datetime 型の配列に格納され、EAやインジケーターで使用できます。
主に 新バー判定や時間管理ロジックで利用されます。
Q2. CopyTimeとCopyRatesの違いは何ですか?
両者の違いは 取得するデータの種類です。
| 関数 | 取得データ |
|---|---|
| CopyTime | バーの時間 |
| CopyRates | OHLC(始値・高値・安値・終値)+時間 |
そのため、
- 時間だけ必要 → CopyTime
- 価格も必要 → CopyRates
という使い分けが一般的です。
Q3. CopyTimeが -1 を返すのはなぜですか?
CopyTimeが -1を返す場合は取得失敗を意味します。
主な原因は次の通りです。
- 履歴データが不足している
- シンボル名が正しくない
- 時間足指定ミス
- 配列の扱いが不適切
- データロードが完了していない
まずは 戻り値をチェックするコードを書くことが重要です。
Q4. CopyTimeで取得した time[0] は何を意味しますか?
通常、time[0] は 最新バーの開始時間を意味します。
ただし、この挙動は **配列の向き(Series設定)**によって変わる場合があります。
EAでは一般的に次の設定を行います。
ArraySetAsSeries(time,true);
これにより
time[0]→ 最新バーtime[1]→ 1本前のバー
になります。
Q5. CopyTimeは新バー判定に使えますか?
はい、CopyTimeは新バー判定で最もよく使われる関数です。
方法はシンプルで、
- 最新バー時間を取得
- 前回保存した時間と比較
- 違えば新バー
というロジックになります。
これにより 同一バーでの多重エントリーを防ぐことができます。
Q6. CopyTimeで大量データを取得しても問題ありませんか?
技術的には可能ですが、必要以上のデータ取得は避けるべきです。
理由
- Tickごとに呼ぶと処理負荷が増える
- EAのパフォーマンスが低下する
多くのEAでは
1本〜10本程度
の取得で十分です。
Q7. CopyTimeはバックテストでも使えますか?
はい、MT5のストラテジーテスターでも正常に動作します。
ただし注意点として
- 時系列データのロードタイミング
- テスターのTick生成方式
によって、初回取得タイミングが環境依存になることがあります。
そのため、実務では
if(CopyTime(...) <= 0)
return;
のように 取得失敗時の処理を入れておくと安全です。