2015年4月8日水曜日

時間足の中央値を描画するサンプル

単純な例として、時間足の中央値を線で結ぶプログラムを書きたいと思います。

まずプロパティにバッファーとプロット情報を追加します。
//バッファーを指定する。
#property indicator_buffers 1

//プロット数を指定する。
#property indicator_plots   1

//プロット情報を記述する。
#property indicator_label1  "Center"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2


indicator_buffersは内部で使用するバッファーの数になります。C言語でいうところの配列を1個使用するという宣言になります。
indicator_plotsは、indicator_buffersで指定したバッファのうち、いくつを描画に使用するか?という指定になります。indicator_buffersを2、indicator_plotsを1に指定した場合、一つ目のバッファを描画するという指定です。
2015/4/8 修正 MT4では、indicator_plots効かないようです。上記設定をしても、黒い線がチャート上に出てしまいます。

プロット情報は、バッファの内容をどのように描画するか?という宣言となります。
indicator_label? と?の部分には数字が入ります。プロットが複数ある場合、この中身が1,2,3と増えていきます。上から、ラベル名、インディケータ種別、色、描画スタイル、幅となります。タイプとスタイルは、いっぱいありますが、とりあえずは実線を描画するスタイルで進めたいと思います。
種類的には次の通りです。必要に応じて調べるため自分向けにメモも含めて^^;

タイプの一覧
スタイルの一覧

//インジケーター バッファ
double         centerBuffer[];
//------------------------------------------------------------------
//初期化
int OnInit()
{
//インジケーターバッファを初期化する。
SetIndexBuffer(0,centerBuffer);

return(INIT_SUCCEEDED);
}

インジケーター用のバッファをグローバル変数として宣言して、OnInit内で初期化します。

OnInit関数内で、SetIndexBuffer関数を使用してバッファを初期化します。
SetIndexBuffer関数は、第1引数にバッファのインデックス、第2引数に変数として宣言した配列名を指定します。
インデックスは0からindicator_buffers-1の値を指定します。今回は0だけです。
省略可能な第3引数にdata_typeがあります。省略すると、INDICATOR_DATAという形になります。こちらも後から必要に応じて調べる為に自分向けにメモを残して先にすすみます。(^^;;
data_typeの種類

//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{
//要素の0が一番新しいデータ
//0~要素数-処理済み要素数-1のデータを更新する。
for( int i = 0; i < (rates_total - prev_calculated); i++ )
{
centerBuffer[i] = (low[i] + high[i]) / 2;
}
//処理済みの要素数を戻り値に設定する。
//最新値は常に更新したいため、-1した値を戻り値とする。
return(rates_total - 1);
}

さて、早速中心値をプロットするプログラムを書きたいと思います。
まず、OnCaluculateの引数に分析に必要な値が含まれています。この値を使用して分析を行います。
各引数の役割はソース内のコメント通りですが、volumeだけ執筆時点では役割が分からず。元ドキュメントを見ると実ボリュームという説明になっていますが、実行してみても値が入ってないためよくわかりません。とりあえず後回しにします。

for( int i = 0; i < (rates_total - prev_calculated); i++ )

まず、for文で更新必要な要素数分だけループします。MQLでは時系列配列というインデックス値のカウント方法が異なる配列となっており、OnCalculate関数にわたってくる値は0が最新(チャートでいう一番右端のデータ)の値となっているようです。
��プログラマ的には0が最古、要素数-1が最新とか勝手に考えてしまうので少し混乱します(^^;;; )
 そのため、未処理である最新のデータだけを更新したい場合、0からrates_total-prev_calculated-1のインデックスまで配列を更新します。
centerBuffer[i] = (low[i] + high[i]) / 2;

中心値ですので(安値+高値)/2の値をcenterBuffer[i]に指定します。
return(rates_total - 1);

戻り値は、OnCalculateで処理した要素数を指定します。この値は、次回OnCalculateが呼び出される際に、prev_calculatedへ設定されます。OnCalculateはチャートのtick値が更新されるたびに呼び出されますので、そのたびに最新バー値を更新するため、rates_total-1に指定します。

ということで実行!見事中央値が描画できました!
sample1running.PNG

コード全文
//+------------------------------------------------------------------+
//|                                                      Sample1.mq4 |
//|                                         Copyright 2015,  Daisuke |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

//バッファーを指定する。
#property indicator_buffers 1

//プロット数を指定する。
#property indicator_plots   1

//プロット情報を記述する。
#property indicator_label1  "Center"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//インジケーター バッファ
double         centerBuffer[];
//------------------------------------------------------------------
//初期化
int OnInit()
{
//インジケーターバッファを初期化する。
SetIndexBuffer(0,centerBuffer);

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[])            //スプレット
{
//要素の0が一番新しいデータ
//0~要素数-処理済み要素数-1のデータを更新する。
for( int i = 0; i < (rates_total - prev_calculated); i++ )
{
centerBuffer[i] = (low[i] + high[i]) / 2;
}
//処理済みの要素数を戻り値に設定する。
//最新値は常に更新したいため、-1した値を戻り値とする。
return(rates_total - 1);
}