配列、バッファ及び時系列における索引付けの方向

全ての配列及び指標バッファの索引付けはデフォルトでは左から右です。最初の要素のインデックスは常にゼロに等しいです。従って、インデックス 0 の配列または指標バッファの最初の要素は一番左にあり、最後の要素は一番右にあるのがデフォルトです。

指標バッファは double 型の動的配列で、サイズは、常に指標が計算されているバーの数に等しいようにクライアント端末で管理されています。通常の double 型の動的配列は SetIndexBuffer() 関数を使用して指標バッファとして割り当てられます。指標バッファのサイズの設定は端末の実行システムによって行われるので ArrayResize() 関数を使用する必要はありません。

時系列は逆方向の索引付けを持つ配列です。 時系列の最初の要素は一番右、最後の要素は一番左にあります。履歴価格データの格納に使用される時系列には時間情報が含まれているので、最も古いデータが一番左にあって最新のデータが一番右にあると言えます。

従って、時系列のインデックス0 の要素は、シンボルの最新の相場に関する情報を含んでいます。時系列が 1 日の時間軸のデータを含んでいる場合は、まだ未完了の今日のデータがゼロの位置に配置されていて、インデックス1の位置には昨日のデータが含まれています。

索引付けの方向の変更

ArraySetAsSeries() 関数は、動的配列の要素にアクセスする方法を変更することが出来ます。コンピュータメモリに格納されるデータの物理的な順序は変更されません。この関数は、単に配列要素のアドレス指定する方法を変更するので、ArrayCopy() を使用して 1 つの配列をもう 1 つに複製する際には、受け取り側の配列の内容は元の配列に索引付け方向に依存しません。

索引付けの方向は静的配列では変更することは出来ません。配列を関数にパラメータとして渡す場合も、関数内での索引付けの方向を変更する試みは、何の効果ももたらしません。

指標バッファは、通常の配列の場合と同様に、索引付けの方向も反対に(時系列のように)設定出来ます。指標バッファでのゼロ位置への参照は対応する指標バッファの最後の値への参照を意味し最新のバーの指標値に対応します。それでも、指標バーの物理的な位置は変更されません。

指標の価格データの受け取り

カスタム指標は、指示バッファ内の値の計算に必要な価格データが渡されるOnCalculate() 関数を含まなければなりません。渡された配列内のインデックス方向は ArrayGetAsSeries() 関数を使用して見つけることが出来ます。

関数に渡された配列は価格データで時系列であるのでArrayIsSeries() でのチェックは true を返します。しかし、いずれの場合、インデックス方向のチェックは ArrayGetAsSeries() 関数で行われるべきです。

初期値に依存しないために ArraySetAsSeries() を作業する配列に無条件に呼び出し、必要な方向を設定するべきです。

価格データと指標値の受け取り

エキスパートアドバイザーの全ての配列、指標及びスクリプトの索引付けはデフォルトでは左から右です。MQL5 プログラムでは、必要に応じて、シンボル及び時間軸で計算された指標値、またその時系列値をリクエストすることが出来ます。

この目的には Copy...() 関数群を使用します。

  • CopyBuffer – 指標バッファの値をdouble 型の配列に複製する
  • CopyRates – 価格履歴を MqlRates 構造体の配列に複製する
  • CopyTime – Time 値をdatetime 型の配列に複製する
  • CopyOpen – Open 値をdouble 型の配列に複製する
  • CopyHigh – High 値をdouble 型の配列に複製する
  • CopyLow – Low 値をdouble 型の配列に複製する
  • CopyClose – Close 値をdouble 型の配列に複製する
  • CopyTickVolume – ティックボリュームを long 型の配列に複製する
  • CopyRealVolume – 資本金ボリュームを long 型の配列に複製する
  • CopySpread – スプレッド履歴を int 型の配列に複製する

 

これらの関数は全て同様の方法で動作します。CopyBuffer() の例でデ ータ取得メカニズムを考えてみましょう。リクエストされたデータの索引付け方向が時系列と同じであることを暗示し、現在まだ完了していないバーはインデックス0 (ゼロ)でデータを格納しています。これらのデータへのアクセスを取得するにはデータの必要量を受け取り側の配列バッファに複製する必要があります。

copyBuffer

複製時には、データが受け取り側の配列に複製され始める元の配列内の開始位置を指定する必要があります。成功した場合には、指定された数の要素が元の配列(ここでは指標バッファ( Indicator buffer ))から受け取り側の配列に複製されます。受け取り側の配列に設定された値の索引付けにかかわらず、コピーは常に上図に示されたように実行されます。

価格データが繰り返しの数が多いループ内で処理されることが期待されている場合 IsStopped() 関数を使用して強制的なプログラム終了を確認することをお勧めします。

int copied=CopyBuffer(ma_handle,// 指標値
                     0,       // 指標バッファのインデックス
                     0,       // コピー開始位置
                     number,   // 複製する値の数
                     Buffer   // 値を受け取る配列
                     );
if(copied<0) return;
int k=0;
while(k<copied && !IsStopped())
 {
  //--- k インデックスの値を取得する
  double value=Buffer[k];
  // ...
  // 値を操作する
  k++;
 }

例:

input int per=10; // 指数の期間
int ma_handle;   // 指標ハンドル
//+------------------------------------------------------------------+
//| エキスパート初期化に使用される関数                                        |
//+------------------------------------------------------------------+
int OnInit()
 {
//---
  ma_handle=iMA(_Symbol,0,per,0,MODE_EMA,PRICE_CLOSE);
//---
  return(INIT_SUCCEEDED);
 }
//+------------------------------------------------------------------+
//| エキスパートティック関数                                                 |
//+------------------------------------------------------------------+
void OnTick()
 {
//---
  double ema[10];
  int copied=CopyBuffer(ma_handle,// 指標ハンドル
                        0,       // 指標バッファのインデックス
                        0,       // コピー開始位置
                        10,       // 複製する値の数
                        ema       // 値を受け取る配列
                        );
  if(copied<0) return;
// .... 更なるコード
 }

参照

データアクセスの整理