インジケーター作成02

インジケーターを実行させた時点より前のローソク足の終値もラインで結ぼう!

ここでは、インジケーター表示が過去の部分が描画された状態で始まるようにする方法を解説します。

前回記事をまだ読んでない方は、まずはそちらから読み進めると良いでしょう。
インジケータ―作成1【新規作成の流れ】

前回記事のおさらい

前回記事では、現在終値のみをラインの値に格納するようにしました。

Dr.EADr.EA

前回記事で完成したインジケーターのコードがこちら

#property strict
#property indicator_chart_window
#property indicator_buffers 1          // インジケーターバッファ 1つ
#property indicator_color1 clrRed      // 1つ目の色 赤色
#property indicator_width1 2           // 1つ目の太さ 2

double buf[];                          // ライン用の配列を宣言

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, buf);             // 配列 buf[]をインジケーター用に割り当てる
   SetIndexStyle(0, DRAW_LINE);        // 描画タイプをラインと定義

   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[])
{
   buf[0] = Close[0];                  // 現在プライスを代入

   return(rates_total);
}

前回の完成ファイル【Sample_Indicator_01.mq4】をダウンロード

過去部分の描画方法

にゃんたにゃんた

最初からラインが表示されたほうがいいにゃ

チャート全体のローソク足の本数を知る

画面に表示されているローソク足のみではなく、左にスクロースしていった一番左端までさかのぼって数えた場合のローソク足の本数はrates_totalで取得できます。
※旧MQL4では、rates_totalの代わりにBarsを使用します。

左端から一つ一つ終値を格納していく

前回の完成ファイルの、OnCalculate()関数内のコードを次のように変更します。

   int i;
   int limit = rates_total - 1;
   for (i=limit; i>=0; i--)
   {
      buf[i] = Close[i];
   }

整数変数「i」を宣言します。この変数は、for()文で使用します。
次に整数変数「limit」を宣言して、左端のローソク足までのシフト数を代入します。

次の表は右端のローソク足から数えたシフト数です。

1本目 0本前 シフト数 0
2本目 1本前 シフト数 1
3本目 2本前 シフト数 2
rates_total 本目 (rates_total -1)本前 シフト数 rates_total -1

左端のローソク足までのシフト数は「rates_total -1」となります。

次にfor()文で左端から右端まで、ライン用配列 buf[]に終値を代入するのを繰り返します。

これで、コンパイルして表示確認してみると、ラインが左端からすべてつながって表示されます。

処理をスマートにする

にゃんたにゃんた

処理をスマートにゃ??

Dr.EADr.EA

要は無駄な処理を省くということじゃ

先ほどまでのコードでは、毎回すべてのローソク足の処理をすることになります。
しかし、過去のローソク足の終値は変動することがないので、インジケーター用配列 buf[]に何度も上書き代入する必要がなく、終値が変動したローソク足のみを処理するようにします。

そのために変数prev_calculatedを利用します。

変数「prev_calculated」について

OnCalculate()関数の終わり部分は、次のようなコードになっています。

   //--- return value of prev_calculated for next call (次回呼出しのprev_calculatedの値を返しなさい)
   return(rates_total);

変数「prev_calculated」の値は、前回OnCalculate()関数で返した値が格納されています。
このコードの場合では変数「rates_total」を返しているので、変数「prev_calculated」の値は最初は0で次からは前回のrates_total(前回のローソク足の本数)となります。

変数「limit」代入する値を変更

変数「limit」に値を代入する部分を、次のように変更します。

   int limit;
   if (prev_calculated == 0)
      limit = rates_total - 1;
   else
      limit = rates_total - prev_calculated;

※旧MQL4では「int limit = Bars – IndicatorCounted() – 1;」とします。

これで、OnCalculate()関数内のfor()文で行う処理は、次のようになります。

表示開始時 limit = rates_total – 1 左端からすべてのローソク足
ローソク足更新時 limit = 1 1本前と現在のローソク足
それ以外の通常時 limit = 0 現在のローソク足のみ

ローソク足の本数が例えば1,000本の場合なら、処理量が約1,000分の1になります。
※ローソク足の終値をつけたティックで必ずしもOnCalclate()関数が実行されるとは限らないので、ローソク足増加時には1本前のローソク足も処理するようにします。

表示・動作確認

変数「limit」の値を確認するために、次のコードを追加します。

   Print(limit);

テスターなどで、ライン表示や変数「limit」の値出力を確認してみましょう。

Dr.EADr.EA

今回完成ファイルのコードがこちら

#property strict
#property indicator_chart_window
#property indicator_buffers 1          // インジケーターバッファ 1つ
#property indicator_color1 clrRed      // 1つ目の色 赤色
#property indicator_width1 2           // 1つ目の太さ 2

double buf[];                          // ライン用の配列を宣言

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, buf);             // 配列 buf[]をインジケーター用に割り当てる
   SetIndexStyle(0, DRAW_LINE);        // 描画タイプをラインと定義

   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 i;
   int limit;
   if (prev_calculated == 0)              // 最初
      limit = rates_total - 1;               // 左端のローソク足から全部
   else                                   // それ以外
      limit = rates_total - prev_calculated; // ローソク足増加時「1」、通常「0」
   
   Print(limit);
   
   for (i=limit; i>=0; i--)               // limit本前から現在のローソク足を処理
   {
      buf[i] = Close[i];
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
}

今回の完成ファイル【Sample_Indicator_02.mq4】をダウンロード

あとがき

いかがだったでしょうか?
変数「rates_total」と「prev_calculated」を使った処理のスマート化などを理解できましたでしょうか?

ではまた、次回をお楽しみに!