インジケーターバッファの説明を読んでも、SetIndexBuffer()やSetIndexStyle()と実際どう組み合わせて使うのかイメージが湧かない——という人向けの記事です。

この記事では、バッファの基本概念に加えて、実際にコンパイルして動く移動平均線インジケーターのコードを紹介します。

バッファ

バッファとは、一般的には緩衝材を指すことが多いです。

例えば、仕事のスケジュールのバッファは?と聞かれた場合に

納期までに余裕のある日数はどれくらい?という意味になります。

プログラミングではバッファをデータの保管領域のことを指しています。

MQL インジケーター作成 バッファ

インジケーターバッファ

MQL言語では、バッファの中でもインジケーターバッファを使用します。

インジケーターバッファとは一言で言うとインジケーター用の配列になります。

インジケーターバッファは以下のような特徴を持っています。

  • チャート上にグラフィカルに値を示す機能を持った配列
  • 機能を実現するためにあらかじめいくつかの特別な仕様が定められている配列
  • バッファ保管領域はdouble型の動的配列で格納

MQLでのバッファの書き方

MQLでのバッファの書き方について説明していきます。

propertyにバッファを定義させる

まずpropertyにバッファを定義させます。

以下のように記述します。

//インジケーターバッファの数を宣言
#property indicator_buffers 1

今回は、インジケーターを1つ表示するのでバッファは1つだけです。

バッファのグローバル空間を確保

次にバッファをグローバル空間に確保します。この際に初期化は必要ありません。

インジケーターバッファとして使用する配列は必ずグローバルエリアで宣言するようにしましょう。

//インジケーターバッファ用の配列
double Buffer[];

SetIndexBuffer()で割り当てる

OnInit()内でインジケーターバッファとして使用する配列をインデックス番号で紐づけます。

その際にSetIndexBuffer()を使用してインジケータバッファを割り当てます。

SetIndexBuffer()とは、

各インジケーターバッファーをインジケーターバッファ領域に割り当てるために使用する関数です。

SetIndexBuffer()は以下のように記述します。

#property indicator_buffers 1

double Buffer[];

int OnInit()
  {
   SetIndexBuffer(0,Buffer);
   //……
   return(INIT_SUCCEEDED);
  }

※`OnInit()`の綴りに注意してください。`ONinit()`のように大文字・小文字を間違えると、MQL4がこの関数を初期化イベントハンドラとして認識できず、コンパイルは通ってもインジケーターの初期化処理が一度も実行されないというわかりにくいバグになります。

SetIndexStyle()でラインや矢印などの表示スタイル指定する

インジケーターバッファの値は、自動でラインや矢印などの形にビジュアル化されます。

その際の表示形式をSetIndexStyle()で指定します。

SetIndexStyle()は以下のように記述します。

//各インデックスのスタイルを設定
SetIndexStyle(0, DRAW_LINE, style_A, width_A, color_A);

各バッファの値を計算する

OnCalculate()内にて、各インジケーターバッファの値を計算します。

計算量を最小限にするために、まだ計算していないバッファのみが計算対象となるように処理を書きます。

下は、まだ計算していないバッファのインデックスをlimitとしています。

//まだ計算していない最古バーのインデックス番号を算出し、変数limitに代入
int limit = rates_total - prev_calculated - 1;
if(limit < 0) limit = 0;

//バッファの値を計算
CalculateBuffer(limit);

return(rates_total);

実際に使ってみる

ここまでの説明を組み合わせて、20期間の単純移動平均線を1本描画するインジケーターを作ってみましょう。

#property strict
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red

double Buffer[];

int OnInit()
  {
   SetIndexBuffer(0, Buffer);
   SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, Red);
   return(INIT_SUCCEEDED);
  }

int OnCalculate(const int rates_total,
                 const int prev_calculated,
                 const datetime &time[],
                 const double &open[],
                 const double &high[],
                 const double &low[],
                 const double &close[],
                 const long &tick_volume[],
                 const long &volume[],
                 const int &spread[])
  {
   int limit = rates_total - prev_calculated - 1;
   if(limit < 0) limit = 0;

   for(int i = limit; i >= 0; i--)
      Buffer[i] = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, i);

   return(rates_total);
  }
Copy

`OnCalculate()`の中で、まだ計算していないバーの分だけ`iMA()`の値をバッファに詰めています。`prev_calculated`(前回までに計算済みのバー数)を使うことで、毎ティック全バーを再計算する無駄を避けられます。

まとめ

今回はバッファについての説明でした。

ポイント

バッファ:データの保管領域のこと
インジケーターバッファ:インジケーター用の配列
SetIndexBuffer():バッファ領域に割り当てるために使用する関数
SetIndexStyle():インジケーターの表示形式などの関数

関連記事