📈

MQL5 ①Bufferの時系列データとかそうじゃないとかの理解を深めたい

2024/12/13に公開

MQL5のBufferの考え方

MQL5のBufferを検索するとでてくるのは下記のような説明です。


配列バッファに複製のされ方


時系列データとは?

  • 時系列データ とは、時間軸に沿って並んだデータの集合です。
  • MQL5では、新しいデータが配列の先頭に位置し、古いデータが後ろに並ぶ 配列形式で時系列データを管理します。

MQL5での時系列配列の特徴

MQL5の配列は特殊な仕様を持っており、時系列モードArraySetAsSeries)を使用することで、最新データがインデックス 0 に位置するようになります。

通常のインデックス順

  • 配列はデフォルトでは 古いデータから新しいデータへ 順にインデックスが付けられます。
    • price[0]: 最も古いデータ
    • price[rates_total-1]: 最新データ

時系列モードのインデックス順

  • 時系列モード(ArraySetAsSeries を使用) を有効にすると、配列の順序が逆転し、新しいデータが先頭に来ます。
    • price[0]: 最新データ
    • price[rates_total-1]: 最も古いデータ

これは、テクニカル指標やトレードロジックを実装する際に効率的です。ほとんどの計算で最新データを頻繁に参照するため、インデックス 0 に最新データがある方が便利です。

時系列モードの適用

以下のように ArraySetAsSeries を使って時系列モードを有効にできます:

ArraySetAsSeries(price, true); // price配列を時系列モードに設定

price 配列の性質

price[] は通常、終値(PRICE_CLOSE)など、特定の価格データを格納する時系列配列です。

データ例

以下のように、指定した価格データがバー(ローソク足)の時系列順に格納されています:

インデックス 時系列モード OFF (ArraySetAsSeries=false) 時系列モード ON (ArraySetAsSeries=true)
0 最も古い価格 最新価格
1 2番目に古い価格 2番目に新しい価格
... ... ...
rates_total-1 最新価格 最も古い価格
  • price[i] の値 は、例えば以下のように取得されます:
    price[i] = iClose(NULL, 0, i); // 終値データを取得
    

時系列モードを適切に設定することで、直感的で効率的なコードを書くことが可能になります。時系列モードが未設定の場合は、データの順序に注意が必要です。
試しにCopyRatesでArraySetAsSeriesの検証。

2024/12/13 GOLD

ArraySetAsSeries検証

まずはArraySetAsSeriesを設定せずに

void OnStart() {
//---
   //ArraySetAsSeriesの動きを知りたい。
   //MqlRates型のリストを作成
   MqlRates rates[];
   ZeroMemory(rates);
   
   //CopyRatesで現在から5本分価格データを取得(エラー処理は省略
   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates);

   int limit = ArraySize(rates); //rates.Size()でもサイズは取得できる   
   for(int i = 0; i < limit; i++){
      printf("[%d]:Time[%s]",i,(string)rates[i].time);
   }
}

出力

メッセージ
[0]:Time[2024.12.13 06:00:00]
[1]:Time[2024.12.13 07:00:00]
[2]:Time[2024.12.13 08:00:00]
[3]:Time[2024.12.13 09:00:00]
[4]:Time[2024.12.13 10:00:00]

おや、配列番号が若い方が最新のものになっていないな。

時系列配列設定

というわけでArraySetAsSeriesでrates を時系列配列に変換するとどうなのか。

void OnStart() {
//---
   //ArraySetAsSeriesの動きを知りたい。

   //MqlRates型のリストを作成
   MqlRates rates[];
   ZeroMemory(rates);
   
   //★時系列にする
   ArraySetAsSeries(rates,true);

   //CopyRatesで現在から5本分価格データを取得
   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates);
   
   int limit = ArraySize(rates); //rates.Size()でもサイズは取得できる
   
   for(int i = 0; i < limit; i++){
      printf("[%d]:Time[%s]",i,(string)rates[i].time);
   }
}

出力結果

メッセージ
[0]:Time[2024.12.13 10:00:00]
[1]:Time[2024.12.13 09:00:00]
[2]:Time[2024.12.13 08:00:00]
[3]:Time[2024.12.13 07:00:00]
[4]:Time[2024.12.13 06:00:00]
ちゃんと配列0が最新の足になりました。

ArraySetAsSeriesにFALSE を設定すると配列0が一番古い足になることを確認。
ArraySetAsSeriesを設定していない場合も同じ出力になるので明示してあげることが大事(フムフム)

メッセージ
[0]:Time[2024.12.13 06:00:00]
[1]:Time[2024.12.13 07:00:00]
[2]:Time[2024.12.13 08:00:00]
[3]:Time[2024.12.13 09:00:00]
[4]:Time[2024.12.13 10:00:00]

#ArraySetAsSeriesの設定タイミングで表示は変わるか。

void OnStart() {
//---
   //ArraySetAsSeriesのタイミングで動きは変わるのか。

   //MqlRates型のリストを作成
   MqlRates rates[];
   ZeroMemory(rates);

   //★時系列にするTRUE
   ArraySetAsSeries(rates, true);

   //CopyRatesで現在から5本分価格データを取得
   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates);

   int limit = ArraySize(rates);
   Print("ArraySetAsSeries:true");
   for(int i = 0; i < limit; i++) {
      printf("[%d]:Time[%s]", i, (string)rates[i].time);
   }

   //★時系列解除FALSE
   ArraySetAsSeries(rates, false);
   Print("ArraySetAsSeries:false");
   for(int i = 0; i < limit; i++) {
      printf("[%d]:Time[%s]", i, (string)rates[i].time);
   }
}
メッセージ
ArraySetAsSeries:true
[0]:Time[2024.12.13 10:00:00]
[1]:Time[2024.12.13 09:00:00]
[2]:Time[2024.12.13 08:00:00]
[3]:Time[2024.12.13 07:00:00]
[4]:Time[2024.12.13 06:00:00]
ArraySetAsSeries:false
[0]:Time[2024.12.13 06:00:00]
[1]:Time[2024.12.13 07:00:00]
[2]:Time[2024.12.13 08:00:00]
[3]:Time[2024.12.13 09:00:00]
[4]:Time[2024.12.13 10:00:00]

ArraySetAsSeriesのタイミングによらず時系列そうじゃないが決まるみたい。

今作ろうとしているものは手動でしこしこ配列にMAとかATRの値を入れて作るんだけど、どうにもうまくいかず。
もうちょい理解を深めたい。

Discussion