2015年4月13日月曜日

子ウィンドウタイプのインジケーターを作成する。

今度は子ウィンドウを表示して、それっぽいデータを描画したいと思います。
意味があるかどうかはわかりませんが、価格移動の分速を求めて表示したいと思います。

speed.PNG

//------------------------------------------------------------------
// 移動速度オシレーター

#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

//(1)indicator_separate_windowを指定すると、子ウィンドウを追加する動作
#property indicator_separate_window

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

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

//移動平均速度
#property indicator_label1  "Speed"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//入力パラメータ 適用価格
input ENUM_APPLIED_PRICE SpeedPrice = PRICE_CLOSE;

//インジケーター バッファ
double         speedValues[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
//インジケーターバッファを初期化する。
SetIndexBuffer(0,speedValues);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 period = PeriodSeconds(PERIOD_CURRENT) / 60;

//(2)元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
{
// 最も古い要素は速度算出不可
if( i == (rates_total - 1) )
{
speedValues[i] = 0 ;
continue;
}

// 現在の価格
double currentPrice;
// ひとつ前の価格
double beforePrice;

switch( SpeedPrice )
{
case PRICE_CLOSE:
currentPrice = close[i];
beforePrice = close[i + 1];
break;
case PRICE_OPEN:
currentPrice = open[i];
beforePrice = open[i + 1];
break;
case PRICE_HIGH:
currentPrice = high[i];
beforePrice = high[i + 1];
break;
case PRICE_LOW:
currentPrice = low[i];
beforePrice = low[i + 1];
break;
case PRICE_MEDIAN:
currentPrice = (high[i] + low[i]) / 2;
beforePrice = (high[i + 1] + low[i + 1]) / 2;
break;
case PRICE_TYPICAL:
currentPrice = (high[i] + low[i] + close[i]) / 3;
beforePrice = (high[i + 1] + low[i + 1] + close[i + 1]) / 3;
break;
case PRICE_WEIGHTED:
currentPrice = (high[i] + low[i] + close[i] + close[i]) / 4;
beforePrice = (high[i + 1] + low[i + 1] + close[i + 1] + close[i + 1]) / 4;
break;
}

//(3)単位がチャート上の通貨ではない単位(この場合 通貨/分)の値を入れる。
speedValues[i] = (currentPrice - beforePrice) / period;
}
return(rates_total);
}


じつは、チャート上に表示するのも、子ウィンドウに表示するのもコードはほとんど変わりません。
��1)にてindicator_separate_windowを指定していますが、基本これだけで子ウィンドウが表示されてチャートが描画されます。
��2)にて計算のもととなる値を求めて、(3)にてバッファに設定する流れはほぼ同じです。

インジケーターが挿入されているチャートの秒数を取得する為、PeriodSeconds関数を使用しました。これは指定の足を秒単位で戻してくれる関数です。引数を省略すると現在チャートの足の秒数を戻します。
��例:5分足で表示していた場合、300が戻ってきます。)
PeriodSeconds
int PeriodSeconds(
ENUM_TIMEFRAMES period=PERIOD_CURRENT // chart period
);

サブウィンドウには、チャート上と単位が違い扱えないデータを表示するのに向いている仕組みです。この場合は価格/分という速度ベースのデータを表示してみましたが、通常は指数値などオシレーター系のデータを表示するのに使うようです。
オシレーターを自力で開発というと結構数学的知識が必要で大変ですよね。私もあれこれ考えるのは好きですが、どうしても確率論や集合論との格闘になってしまい、頭が固まってしまいます。EA開発の前段階として自分なりのオシレーターが作れるよう日々努力です。