- 1 1. ArraySetAsSeriesとは何か(MQL5の配列方向を変更する関数)
- 2 2. ArraySetAsSeriesの構文と使い方(基本仕様)
- 3 3. CopyBufferとArraySetAsSeriesの関係(EA開発で最も重要なポイント)
- 4 4. ArraySetAsSeriesが使えない配列と制限事項
- 5 5. ArraySetAsSeriesを使った実践コード(EA開発例)
- 6 6. ArraySetAsSeriesに関するよくある質問
- 7 7. ArraySetAsSeriesを安全に使うためのベストプラクティス
- 8 8. ArraySetAsSeriesのFAQ
- 8.1 Q1. ArraySetAsSeriesとは何をする関数ですか?
- 8.2 Q2. ArraySetAsSeriesを使うと配列のデータは並び替えられますか?
- 8.3 Q3. CopyBufferを使う場合はArraySetAsSeriesが必要ですか?
- 8.4 Q4. Time[] や Close[] に ArraySetAsSeries は必要ですか?
- 8.5 Q5. ArraySetAsSeriesはどの配列でも使えますか?
- 8.6 Q6. ArraySetAsSeriesはどこで呼び出すべきですか?
- 8.7 Q7. buffer[0]は確定バーですか?
- 8.8 Q8. ArraySetAsSeriesを使わないとどうなりますか?
1. ArraySetAsSeriesとは何か(MQL5の配列方向を変更する関数)
ArraySetAsSeries は、MQL5で配列を「時系列データとして扱うかどうか」を設定するための関数です。
簡単に言うと、配列のインデックス(添字)の意味を、チャートの時間順に合わせるための設定です。
MQL5では、価格データやインジケータの値は 時間順のデータ(時系列データ)として扱われます。
しかし、通常のプログラミング言語における配列は、先頭から順番に古いデータ→新しいデータという構造になっています。
この違いを調整するために使用するのが ArraySetAsSeries です。
特に次のような処理では、ほぼ必ず使用されます。
- インジケータの値を取得する処理
- CopyBuffer関数でデータを取得する処理
- EA(自動売買プログラム)のシグナル判定
- バックテスト用データの取得
この関数を理解していないと、インジケータの値を誤って参照するバグが発生しやすくなります。
1.1 ArraySetAsSeriesの基本概念
MQL5のチャートデータは、最新のバーが最初に来る構造になっています。
例えば、次のような価格データを考えます。
| バー | 意味 |
|---|---|
| 0 | 最新のローソク足 |
| 1 | 1本前 |
| 2 | 2本前 |
つまり、MQL5では次のようなルールでデータを扱います。
index 0 = 最新バー
index 1 = 1本前
index 2 = 2本前
これは 時系列(Series)配列と呼ばれる構造です。
一方、通常の配列は次のような順序になります。
index 0 = 最も古いデータ
index n = 最新データ
この違いが、MQL5初心者が最も混乱しやすいポイントです。
ArraySetAsSeries を使うと、配列を以下のように扱えるようになります。
ArraySetAsSeries(array, true);
すると、その配列は Series配列(時系列配列)として扱われ、次のようになります。
array[0] = 最新データ
array[1] = 1つ前のデータ
array[2] = 2つ前のデータ
これにより、チャートデータと同じ感覚で配列を扱えるようになります。
1.2 なぜ配列方向を変更する必要があるのか
MQL5で配列方向を変更する理由は、チャートデータの構造に合わせるためです。
例えば、RSIの値を取得する処理を考えてみます。
double rsi[];
CopyBuffer(rsi_handle,0,0,10,rsi);
この状態では、配列の順序が 通常配列のままです。
つまり、次のような状態になります。
rsi[0] = 古いデータ
rsi[9] = 最新データ
しかし、多くのEAでは次のように使います。
最新RSI = rsi[0]
1本前RSI = rsi[1]
このとき ArraySetAsSeries を設定していないと、
最新データではなく古いデータを参照してしまう可能性があります。
その結果、次のような問題が発生します。
- 売買シグナルが逆になる
- バックテスト結果がおかしくなる
- EAが期待通りに動作しない
このため、実務のEA開発では CopyBufferを使う配列にはほぼ必ずArraySetAsSeriesを設定します。
1.3 使用される主な場面
ArraySetAsSeriesは、主に次のような場面で使われます。
① インジケータデータ取得
RSIや移動平均などの値を取得する場合です。
double rsi[];
ArraySetAsSeries(rsi,true);
CopyBuffer(handle,0,0,10,rsi);
② EAのシグナル判定
例えば次のようなロジックです。
RSIが30以下 → 買い
RSIが70以上 → 売り
このとき、通常は次のデータを使います。
rsi[0] = 現在
rsi[1] = 1本前
③ マルチタイムフレームEA
複数の時間足のデータを扱うEAでは、
配列方向の統一が非常に重要になります。
つまずきやすいポイント(初心者がよく失敗する部分)
以下は、MQL5開発でよく起きるミスです。
① ArraySetAsSeriesを設定していない
結果
- インジケータ値が逆順になる
② CopyBufferのあとに設定している
推奨順序
ArraySetAsSeries
↓
CopyBuffer
③ インデックスの意味を誤解している
初心者がよく勘違いする点
array[0] = 最新
array[1] = 1本前
④ バックテストとリアルで結果が変わる
配列方向のミスは、
バックテストの誤判定の原因になることがあります。
2. ArraySetAsSeriesの構文と使い方(基本仕様)
ArraySetAsSeries は、配列を時系列配列(Series配列)として扱うかどうかを設定する関数です。
主に 価格データ・インジケータデータ・CopyBufferで取得した配列を、チャートと同じ時間順で扱うために使用します。
この関数は 配列の中身を変更するのではなく、配列のインデックス解釈(参照方向)を変更するだけという点が重要です。
つまり、データ自体は変わらず、どの要素を index 0 として扱うかが変わります。
2.1 ArraySetAsSeriesの構文
ArraySetAsSeriesの基本構文は次のとおりです。
bool ArraySetAsSeries(
void& array[],
bool flag
);
引数の意味は以下の通りです。
| 引数 | 説明 |
|---|---|
| array | 対象となる配列 |
| flag | Series配列にするかどうか |
flag の値によって挙動が変わります。
| flag | 意味 |
|---|---|
| true | 時系列配列として扱う |
| false | 通常配列として扱う |
多くのEAでは true を指定して使用します。
2.2 基本的な使用例
最も基本的な使用例は、インジケータデータ取得です。
double rsi[];
ArraySetAsSeries(rsi,true);
CopyBuffer(rsi_handle,0,0,10,rsi);
このコードでは次の処理が行われています。
- RSI用の配列を用意
- 配列をSeries配列に設定
- CopyBufferでRSIデータ取得
結果として配列は次の構造になります。
rsi[0] = 最新RSI
rsi[1] = 1本前RSI
rsi[2] = 2本前RSI
EAではこの形が最も使いやすいため、ほぼ標準的な書き方になっています。
2.3 通常配列との違い
ArraySetAsSeriesを使わない場合、配列は通常配列になります。
double rsi[];
CopyBuffer(rsi_handle,0,0,10,rsi);
この場合の配列構造は次の通りです。
rsi[0] = 最も古いデータ
rsi[9] = 最新データ
つまり 最新値は配列の最後に格納されます。
そのため次のようなコードが必要になります。
double latest_rsi = rsi[9];
しかしEAでは通常、
最新値 = index 0
として扱うことが多いため、ArraySetAsSeriesを使う方が分かりやすくなります。
2.4 戻り値
ArraySetAsSeriesは bool型の値を返します。
| 戻り値 | 意味 |
|---|---|
| true | 設定成功 |
| false | 設定失敗 |
通常のEAでは戻り値をチェックしないケースもありますが、
堅牢なプログラムを書く場合は確認する方が安全です。
例
if(!ArraySetAsSeries(rsi,true))
{
Print("ArraySetAsSeries failed");
}
設定失敗はまれですが、不正な配列を指定した場合などに発生する可能性があります。
つまずきやすいポイント(よくある失敗)
ArraySetAsSeriesは単純な関数ですが、初心者が間違えやすいポイントがあります。
① 配列宣言前に使ってしまう
これはコンパイルエラーになります。
ArraySetAsSeries(rsi,true);
double rsi[];
必ず 配列宣言の後に書きます。
② CopyBufferの後に設定する
次の順序は推奨されません。
CopyBuffer(handle,0,0,10,rsi);
ArraySetAsSeries(rsi,true);
理由
- データ解釈が混乱する
- バグの原因になる
推奨順序
ArraySetAsSeries
↓
CopyBuffer
③ Series配列のインデックスを誤解する
初心者が最も混乱する部分です。
Series配列では
array[0] = 最新
array[1] = 1本前
array[2] = 2本前
になります。
④ 配列サイズを意識していない
CopyBufferで取得する数より配列サイズが小さいと、
Array out of range エラーが発生する可能性があります。
3. CopyBufferとArraySetAsSeriesの関係(EA開発で最も重要なポイント)
MQL5で ArraySetAsSeries が特に重要になるのは、CopyBuffer関数と組み合わせて使用する場合です。
実際のEA開発では、インジケータの値を取得する処理のほとんどが CopyBuffer+ArraySetAsSeries の形で実装されます。
この関係を理解していないと、最新データではなく古いデータを参照してしまうバグが発生するため注意が必要です。
3.1 CopyBufferとは何か(簡単なおさらい)
CopyBuffer は、インジケータの計算結果を配列へコピーする関数です。
基本構文
int CopyBuffer(
int indicator_handle,
int buffer_num,
int start_pos,
int count,
double buffer[]
);
主な引数の意味
| 引数 | 意味 |
|---|---|
| indicator_handle | インジケータハンドル |
| buffer_num | 取得するバッファ番号 |
| start_pos | 取得開始位置 |
| count | 取得するデータ数 |
| buffer | コピー先配列 |
この関数を使うと、インジケータ値を配列に取得できます。
例(RSI取得)
double rsi[];
CopyBuffer(rsi_handle,0,0,10,rsi);
ここで問題になるのが 配列の順序です。
3.2 CopyBufferで取得した配列の順序
CopyBufferで取得したデータは、通常配列として格納されます。
つまり、配列の構造は次のようになります。
rsi[0] = 最も古いデータ
rsi[1] = ...
rsi[9] = 最新データ
しかし、多くのEAでは次のように使いたいケースが多いはずです。
rsi[0] = 最新値
rsi[1] = 1本前
このときに使用するのが ArraySetAsSeries です。
3.3 CopyBufferとArraySetAsSeriesの正しい組み合わせ
EA開発での標準的なコードは次の形になります。
double rsi[];
ArraySetAsSeries(rsi,true);
CopyBuffer(rsi_handle,0,0,10,rsi);
この処理を行うと、配列は次の構造になります。
rsi[0] = 最新RSI
rsi[1] = 1本前RSI
rsi[2] = 2本前RSI
つまり チャートのバー番号と同じ感覚で配列を扱えるようになります。
3.4 EAの売買ロジック例
ArraySetAsSeriesを設定している場合、売買ロジックは次のように書けます。
例:RSIによる売買判定
if(rsi[0] < 30)
{
// 買いシグナル
}
if(rsi[0] > 70)
{
// 売りシグナル
}
また、クロス判定なども書きやすくなります。
例:RSIの反転
if(rsi[1] < 30 && rsi[0] > 30)
{
// 買い
}
このように 最新バーと1本前バーを簡単に比較できるため、
EAのロジックが非常に読みやすくなります。
3.5 よくあるバグ(非常に多い)
ArraySetAsSeriesを設定していない場合、次のようなコードは意図通り動きません。
double rsi[];
CopyBuffer(handle,0,0,10,rsi);
if(rsi[0] < 30)
{
Buy();
}
この場合、rsi[0] は 最新値ではなく古い値になります。
つまりEAは
- 古いデータ
- 過去のシグナル
を使って売買してしまいます。
結果として
- バックテスト結果がおかしい
- EAが遅れてエントリーする
- シグナルがずれる
といった問題が発生します。
3.6 CopyBuffer使用時の推奨テンプレート
実務では、次の書き方が最も安全です。
double buffer[];
ArraySetAsSeries(buffer,true);
if(CopyBuffer(handle,0,0,10,buffer) <= 0)
{
Print("CopyBuffer error");
return;
}
double current = buffer[0];
double prev = buffer[1];
このようにすると
- 配列方向のミス
- データ取得失敗
- バッファ不足
などの問題を防ぐことができます。
つまずきやすいポイント(CopyBuffer関連)
① ArraySetAsSeriesを忘れる
EA初心者が最もやりがちなミスです。
② CopyBufferの戻り値を確認していない
CopyBufferは 取得できたデータ数を返します。
失敗すると
0
または
-1
になることがあります。
③ 配列サイズ不足
取得数が配列サイズより大きいと
array out of range
エラーになります。
④ Series配列と通常配列を混在させる
同じロジック内で
- Series配列
- 通常配列
が混在すると、バグの原因になります。
4. ArraySetAsSeriesが使えない配列と制限事項
ArraySetAsSeriesは便利な関数ですが、すべての配列に対して使用できるわけではありません。
MQL5では配列の種類によって、Series配列(時系列配列)に変更できるものとできないものがあります。
この制限を理解していないと、コンパイルエラーや実行時エラーの原因になります。
4.1 ArraySetAsSeriesが使える配列
基本的に 動的配列(dynamic array)には使用できます。
動的配列とは、サイズを固定せずに宣言する配列のことです。
例
double price[];
このような配列には、次のように設定できます。
double price[];
ArraySetAsSeries(price,true);
また、以下のような型でも使用できます。
| 配列型 | 使用可否 |
|---|---|
| double[] | 使用可能 |
| int[] | 使用可能 |
| datetime[] | 使用可能 |
| long[] | 使用可能 |
| bool[] | 使用可能 |
つまり、通常の1次元動的配列であれば基本的に問題なく使用できます。
4.2 ArraySetAsSeriesが使えない配列
次のような配列では、ArraySetAsSeriesを使用できません。
① 固定サイズ配列
固定サイズで宣言した配列です。
例
double price[100];
この場合
ArraySetAsSeries(price,true);
は エラーになります。
理由は、固定サイズ配列はコンパイル時にメモリ配置が決定されるため、
配列方向を変更する仕組みが適用できないためです。
② 多次元配列
ArraySetAsSeriesは 1次元配列のみ対応しています。
例
double matrix[10][10];
この配列に対して
ArraySetAsSeries(matrix,true);
を使うことはできません。
③ 構造体配列
構造体を格納した配列でも使用できません。
例
struct Data
{
double value;
};
Data arr[];
このような配列に対してSeries設定を行うと、エラーになる場合があります。
※環境やコード構造により挙動が異なる場合があります。
4.3 MQL5の標準時系列配列
MQL5には、最初からSeries配列として扱われるデータがあります。
代表例
| 配列 | 意味 |
|---|---|
| Time[] | バー時間 |
| Open[] | 始値 |
| High[] | 高値 |
| Low[] | 安値 |
| Close[] | 終値 |
| Volume[] | 出来高 |
これらは チャートの価格データ配列です。
これらの配列は、最初から次の構造になっています。
index 0 = 最新バー
index 1 = 1本前
index 2 = 2本前
つまり ArraySetAsSeriesを設定する必要はありません。
4.4 ArraySetAsSeriesを解除する方法
Series配列を 通常配列に戻すことも可能です。
方法は、flagを false にするだけです。
例
ArraySetAsSeries(buffer,false);
この場合、配列は次のようになります。
buffer[0] = 古いデータ
buffer[n] = 最新データ
ただし、EA開発では falseに戻すケースはほとんどありません。
通常は
ArraySetAsSeries(array,true);
のまま使用します。
つまずきやすいポイント(制限関連)
① 固定サイズ配列で使ってしまう
次のコードはエラーになります。
double buffer[100];
ArraySetAsSeries(buffer,true);
解決方法
double buffer[];
に変更します。
② 多次元配列に適用する
Series設定は 1次元配列専用です。
③ 時系列配列と勘違いする
次の配列は すでにSeries配列です。
Close[]
Open[]
High[]
Low[]
そのため、通常はArraySetAsSeriesは不要です。
④ Series配列を前提にコードを書いてしまう
ArraySetAsSeriesを設定していない配列で
buffer[0] = 最新
としてしまうと、ロジックが破綻する可能性があります。
5. ArraySetAsSeriesを使った実践コード(EA開発例)
ArraySetAsSeriesは、実際のEA(自動売買プログラム)ではインジケータデータの取得処理と組み合わせて使用することがほとんどです。
ここでは、実務でよく使われる代表例として
- RSIによる売買判定
- 移動平均クロス判定
の2つを紹介します。
これらは CopyBuffer+ArraySetAsSeriesの典型パターンでもあります。
5.1 RSIを使った売買判定
まずは最もシンプルな例です。
RSIの値を取得し、過売り・過買い判定を行います。
コード例
int rsi_handle;
double rsi[];
int OnInit()
{
rsi_handle = iRSI(_Symbol,_Period,14,PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
void OnTick()
{
ArraySetAsSeries(rsi,true);
if(CopyBuffer(rsi_handle,0,0,3,rsi) <= 0)
return;
double current = rsi[0];
double previous = rsi[1];
if(current < 30)
{
Print("Buy signal");
}
if(current > 70)
{
Print("Sell signal");
}
}
処理の流れ
- RSIインジケータハンドルを作成
- RSI値を配列へ取得
- 最新値と1本前を参照
- 売買シグナル判定
Series配列にしているため
rsi[0] = 最新RSI
rsi[1] = 1本前
という形で扱えます。
5.2 移動平均クロス判定
EAで最もよく使われるロジックの1つが 移動平均クロスです。
- 短期MA
- 長期MA
を比較して売買判断を行います。
コード例
int fast_handle;
int slow_handle;
double fast_ma[];
double slow_ma[];
int OnInit()
{
fast_handle = iMA(_Symbol,_Period,10,0,MODE_EMA,PRICE_CLOSE);
slow_handle = iMA(_Symbol,_Period,50,0,MODE_EMA,PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
void OnTick()
{
ArraySetAsSeries(fast_ma,true);
ArraySetAsSeries(slow_ma,true);
if(CopyBuffer(fast_handle,0,0,3,fast_ma) <= 0)
return;
if(CopyBuffer(slow_handle,0,0,3,slow_ma) <= 0)
return;
if(fast_ma[1] < slow_ma[1] && fast_ma[0] > slow_ma[0])
{
Print("Golden Cross");
}
if(fast_ma[1] > slow_ma[1] && fast_ma[0] < slow_ma[0])
{
Print("Dead Cross");
}
}
Series配列を使うことで
fast_ma[0] = 現在
fast_ma[1] = 1本前
となるため、クロス判定が非常に書きやすくなります。
5.3 実務で使われる安全テンプレート
EA開発では、以下のようなテンプレートがよく使われます。
double buffer[];
ArraySetAsSeries(buffer,true);
int copied = CopyBuffer(handle,0,0,3,buffer);
if(copied <= 0)
{
Print("CopyBuffer error");
return;
}
double current = buffer[0];
double previous = buffer[1];
この書き方にすると
- データ取得失敗
- 配列順序ミス
- インデックスバグ
を防ぐことができます。
よくある失敗(実装時)
① OnInitでArraySetAsSeriesを書いてしまう
次の書き方は問題になることがあります。
int OnInit()
{
ArraySetAsSeries(buffer,true);
}
理由
- 配列が再生成される可能性
- CopyBufferで上書きされる可能性
安全なのは
OnTickで設定
です。
② CopyBufferの取得数が少ない
次のコードは危険です。
CopyBuffer(handle,0,0,1,buffer);
その後
buffer[1]
を参照すると
array out of range
になります。
③ 配列サイズを意識していない
安全な取得数
3〜10
程度にするのが一般的です。
④ Series配列を前提にロジックを書く
ArraySetAsSeriesを忘れると
最新 = buffer[0]
という前提が崩れます。
このミスは EA初心者の典型的なバグです。
6. ArraySetAsSeriesに関するよくある質問
ArraySetAsSeries は単純な関数に見えますが、実際のMQL5開発では CopyBuffer・価格配列・EAロジックと深く関係するため、初心者が混乱しやすいポイントが多くあります。
ここでは、実務で特によく出る質問とその考え方を整理します。
6.1 ArraySetAsSeriesを使うと配列の中身は並び替えられるのか
結論から言うと、配列の中身そのものを並び替えるわけではありません。
ArraySetAsSeries が変更するのは、あくまで 配列要素の参照方向です。
つまり、物理的に配列データを並べ替えるのではなく、index 0 を最新として扱うか、古いデータとして扱うかを切り替えています。
そのため、次の点は必ず理解しておく必要があります。
- データの意味付けが変わる
- ロジックの書き方が変わる
- 既存コードの添字の意味が変わる
例えば、同じ配列でも設定次第で意味が変わります。
double buffer[];
ArraySetAsSeries(buffer,true);
この場合は
buffer[0] = 最新
buffer[1] = 1本前
です。
一方で false の場合は
buffer[0] = 古いデータ
buffer[n] = 最新
になります。
ここを誤解すると、コードは動くのに売買判断だけ間違うという厄介な不具合が起きます。
6.2 CopyBufferを使うなら毎回ArraySetAsSeriesを書くべきか
実務上は、対象配列を使う前に明示しておく方が安全です。
特にEAでは、可読性と再現性を重視したほうがよいため、CopyBufferを使う配列には毎回同じルールで書くのが無難です。
推奨形は次の通りです。
double ma_buffer[];
ArraySetAsSeries(ma_buffer,true);
if(CopyBuffer(handle,0,0,3,ma_buffer) <= 0)
return;
この書き方の利点は次の通りです。
- 配列方向の見落としを防げる
- コードレビュー時に意図が明確
- 他人が見ても誤読しにくい
逆に、どこかで一度だけ設定して省略しようとすると、後からコードを修正したときに Series設定済みかどうか分からなくなることがあります。
6.3 Time[]やClose[]にもArraySetAsSeriesは必要か
通常、不要です。
Time[] Open[] High[] Low[] Close[] などの価格配列は、MQL5で時系列データとして扱う前提があるため、一般に 最新バーが index 0 です。
そのため、通常のEAやインジケータでこれらを参照するだけなら、あらためて ArraySetAsSeries を設定する必要はありません。
ただし注意点があります。
- 標準の価格配列と
- 自分で用意した配列
は別物です。
例えば CopyBuffer で取得した配列は、自分で方向を意識して管理しないと混乱しやすくなります。
つまり、標準配列は最初から時系列、独自配列は自分で管理するという整理が重要です。
6.4 ArraySetAsSeriesを使えばバグは防げるのか
完全には防げません。
正しく使えば配列方向のミスはかなり減らせますが、それだけでEA全体の安全性が保証されるわけではありません。
よくある失敗は次の通りです。
CopyBufferの戻り値を確認していない- 取得数が足りないのに
buffer[1]やbuffer[2]を参照する - Series配列と通常配列を混在させる
- 現在足と確定足を混同する
特に初心者が見落としやすいのが、現在足(形成中のバー)を使うか、確定足を使うかです。
例えば
buffer[0] = 現在進行中のバー
buffer[1] = 確定済みの1本前
として扱う場面があります。
戦略によっては buffer[0] を使うとシグナルが変動するため、確定足ベースで判定したい場合は buffer[1] を使う設計もあります。
つまり、ArraySetAsSeriesを理解した上で、どのバーを使うかまで設計しないと実運用では足りません。
6.5 初心者はどういうルールで使えばよいか
初心者が最も安全に運用するなら、次のルールに統一するのが実務的です。
CopyBuffer用の配列は動的配列にする- 取得前に
ArraySetAsSeries(array,true);を書く CopyBufferの戻り値を必ず確認する- 最新値は
array[0]、確定足はarray[1]と整理する - 同じEA内では配列方向のルールを統一する
特に重要なのは、配列方向をEAごとに統一することです。
一部はSeries、一部は通常配列、という状態にすると、後でロジックを追加したときに事故が起きやすくなります。
初心者向けの最小テンプレートは次の形です。
double buffer[];
ArraySetAsSeries(buffer,true);
int copied = CopyBuffer(handle,0,0,3,buffer);
if(copied <= 0)
return;
double current = buffer[0];
double previous = buffer[1];
この形を繰り返し使えば、ArraySetAsSeriesまわりの初歩的なミスはかなり減らせます。
つまずきやすい点・注意点・よくある失敗
① ArraySetAsSeriesだけ理解して満足してしまう
実際には
- CopyBuffer
- 配列サイズ
- 戻り値確認
- 現在足と確定足
までセットで理解する必要があります。
② 最新バーと確定バーを混同する
buffer[0] は最新でも、確定済みとは限りません。
③ 配列方向のルールを途中で変える
EAの保守性が大きく下がります。
④ 標準価格配列と自作配列を同じ感覚で扱う
ここを混同すると、ロジックが破綻しやすくなります。
7. ArraySetAsSeriesを安全に使うためのベストプラクティス
ArraySetAsSeriesは単純な関数ですが、EAの売買ロジックの正確性に直結する重要な設定です。
実務では、配列方向のミスが原因で
- シグナルが逆になる
- バックテスト結果が異常になる
- エントリータイミングがずれる
といった問題が発生することがあります。
ここでは、実務のMQL5開発で推奨される 安全な実装ルール(ベストプラクティス)を整理します。
7.1 CopyBufferと必ずセットで使用する
EAでArraySetAsSeriesが必要になる場面のほとんどは、CopyBufferでインジケータ値を取得する場合です。
このときは次の順序を必ず守ります。
ArraySetAsSeries
↓
CopyBuffer
↓
配列参照
コード例
double buffer[];
ArraySetAsSeries(buffer,true);
int copied = CopyBuffer(handle,0,0,3,buffer);
if(copied <= 0)
return;
double current = buffer[0];
double previous = buffer[1];
この順序を守ることで、配列方向の混乱を防ぐことができます。
7.2 EA内で配列方向のルールを統一する
EAの中で
- Series配列
- 通常配列
が混在すると、ロジックの可読性が大きく下がります。
特に複数のインジケータを使うEAでは、次のような混乱が起きやすくなります。
Aインジケータ → index0が最新
Bインジケータ → index0が古い
この状態では、売買ロジックを追加するたびにミスが起きやすくなります。
そのため、実務では次のルールが推奨されます。
「インジケータ配列はすべてSeries配列にする」
つまり
ArraySetAsSeries(array,true);
を基本ルールにします。
7.3 CopyBufferの戻り値を必ず確認する
CopyBufferは、取得したデータ数を返します。
| 戻り値 | 意味 |
|---|---|
| 正の数 | 取得成功 |
| 0 | 取得できない |
| -1 | エラー |
戻り値を確認しないと、次のような問題が起きることがあります。
データが存在しない
↓
buffer[0]参照
↓
不正データ
安全な書き方
int copied = CopyBuffer(handle,0,0,3,buffer);
if(copied <= 0)
{
Print("CopyBuffer failed");
return;
}
このチェックを入れるだけで、EAの安定性が大きく向上します。
7.4 必要以上のデータを取得しない
CopyBufferでは、取得するデータ数を指定できます。
例
CopyBuffer(handle,0,0,3,buffer);
EAのロジックでは通常
- 最新バー
- 1本前
- 2本前
程度で十分です。
そのため、実務では
3〜10本
程度の取得が一般的です。
必要以上のデータを取得すると
- 無駄なメモリ使用
- パフォーマンス低下
につながる可能性があります。
7.5 最新バーと確定バーを意識する
EAロジックで重要なのが、現在足(未確定バー)と確定バーの違いです。
Series配列では次の構造になります。
buffer[0] = 現在バー(未確定)
buffer[1] = 1本前(確定)
buffer[2] = 2本前
戦略によっては、buffer[0]を使うとシグナルが変動することがあります。
例えば
buffer[0] > buffer[1]
のような条件は、バー確定前に変わる可能性があります。
そのため、次のように設計するケースもあります。
buffer[1] を基準に判定
つまり
double current = buffer[1];
double previous = buffer[2];
とすることで、確定足ベースのロジックになります。
つまずきやすいポイント(実務で多いミス)
① ArraySetAsSeriesを忘れる
EA初心者で最も多いバグです。
結果
古いデータで売買
になります。
② CopyBufferの戻り値を確認していない
データ取得失敗時に
ゴミデータ
を参照する可能性があります。
③ buffer[0]を確定足だと思い込む
buffer[0] は 形成中のバーです。
④ 配列方向のルールが統一されていない
EAの保守性が大きく低下します。
実務で推奨される最小テンプレート
初心者が最も安全に使えるテンプレートは次の形です。
double buffer[];
ArraySetAsSeries(buffer,true);
int copied = CopyBuffer(handle,0,0,3,buffer);
if(copied <= 0)
return;
double current = buffer[0];
double previous = buffer[1];
この形をベースにすれば、ArraySetAsSeries関連の初歩的なミスはほぼ防げます。
8. ArraySetAsSeriesのFAQ
Q1. ArraySetAsSeriesとは何をする関数ですか?
ArraySetAsSeries は、MQL5の配列を 時系列データ(Series配列)として扱うための設定を行う関数です。
Series配列では、インデックスの意味が次のようになります。
array[0] = 最新データ
array[1] = 1本前
array[2] = 2本前
これはMetaTraderのチャート構造と同じ並び方です。
そのため、インジケータデータや価格データを扱うEAではよく使用されます。
Q2. ArraySetAsSeriesを使うと配列のデータは並び替えられますか?
いいえ。
配列のデータ自体は並び替えられません。
この関数は
- データの並び
- メモリ配置
を変更するのではなく、配列の参照方向(インデックスの解釈)だけを変更します。
そのため、ArraySetAsSeriesを設定すると
array[0]
が最新データとして扱われます。
Q3. CopyBufferを使う場合はArraySetAsSeriesが必要ですか?
多くの場合、使用することが推奨されます。
CopyBufferで取得した配列は、デフォルトでは通常配列になります。
つまり
array[0] = 古いデータ
array[n] = 最新データ
となります。
しかしEAのロジックでは
array[0] = 最新
array[1] = 1本前
として扱う方が自然です。
そのため次のように書くケースが一般的です。
double buffer[];
ArraySetAsSeries(buffer,true);
CopyBuffer(handle,0,0,3,buffer);
Q4. Time[] や Close[] に ArraySetAsSeries は必要ですか?
通常は 不要です。
次の価格配列は、最初から時系列配列として扱われます。
- Time[]
- Open[]
- High[]
- Low[]
- Close[]
- Volume[]
これらは
index 0 = 最新バー
の構造になっています。
Q5. ArraySetAsSeriesはどの配列でも使えますか?
いいえ。
使用できるのは主に1次元の動的配列です。
使用できない例
- 固定サイズ配列
- 多次元配列
- 一部の構造体配列
例(使用不可)
double buffer[100];
ArraySetAsSeries(buffer,true);
この場合はエラーになります。
Q6. ArraySetAsSeriesはどこで呼び出すべきですか?
通常は 配列を使用する直前に呼び出します。
特にCopyBufferと組み合わせる場合は次の順序が安全です。
ArraySetAsSeries
↓
CopyBuffer
↓
配列参照
例
ArraySetAsSeries(buffer,true);
CopyBuffer(handle,0,0,3,buffer);
Q7. buffer[0]は確定バーですか?
必ずしもそうではありません。
Series配列では
buffer[0] = 現在バー(形成中)
buffer[1] = 1本前(確定バー)
になります。
そのため、戦略によっては
buffer[1]
を使って売買判定することもあります。
Q8. ArraySetAsSeriesを使わないとどうなりますか?
EAのロジックが 古いデータを基準に動作する可能性があります。
例えば次のコード
if(buffer[0] > buffer[1])
が
古いデータ > さらに古いデータ
という意味になる可能性があります。
その結果
- 売買タイミングがずれる
- バックテスト結果が不自然になる
といった問題が発生することがあります。