2015年5月12日火曜日

MT4プログラムの小ネタ 時間別に横線を引く。/線の途中で色を変える。

線の途中で色を変える.PNG

MT4でチャート上に線を引きたい。線の途中で色を変えたい。ラインを使って高値安値を複数表現すると線がつながってしまってチャートが汚くなる! TrendLineオブジェクトだとずーっと表示されてしまうので邪魔!などの問題点・・どうやって解決すればよいのでしょうか?

答えとしてはバッファをたくさん作るということのようです。

MT4のライン描画用に確保したバッファですが、初期値のままにしておくと描画しないという特徴があります。これを利用して複数バッファをまたいで同じラインを描画すると、線の途中で途切れさせたり、色を変えたりできます。

サンプルとして「東京時間をぶっ壊せ!MT4で時間レンジブレイク向けインジケータを作ってみた。」を東京時間とそうでない場合色を変えてみました。

//------------------------------------------------------------------
// 時間帯別レンジ表示

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

// 正式なデータではない値
#define NONDATAVALUE 10000

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

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

#property indicator_label1  "HIGH"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

#property indicator_label2  "LOW"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#property indicator_label3  "ZONEHIGH"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrYellow
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

#property indicator_label4  "ZONELOW"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrWhite
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

// 入力パラメータ 開始サーバー時間
input int StartHour = 3;

// 入力パラメータ 終了サーバー時間
input int EndHour = 9;

// バッファー
double highBuffer[];
double lowBuffer[];
double zoneHighBuffer[];
double zoneLowBuffer[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
// 時間足以下のみ有効
int priod = Period();
if( priod > PERIOD_H1 ) return INIT_PARAMETERS_INCORRECT;

if( StartHour < 0 || StartHour > 23 ) return INIT_PARAMETERS_INCORRECT;
if( EndHour < 0 || EndHour > 23 ) return INIT_PARAMETERS_INCORRECT;
if( StartHour == EndHour ) return INIT_PARAMETERS_INCORRECT;

SetIndexBuffer(0, highBuffer);
SetIndexBuffer(1, lowBuffer);
SetIndexBuffer(2, zoneHighBuffer);
SetIndexBuffer(3, zoneLowBuffer);

string short_name = "TR(";
short_name += IntegerToString(StartHour) + "," + IntegerToString(EndHour) + ")";
IndicatorShortName(short_name);

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[])            //スプレット
{
// 開始時間から終了時間までの高値安値を更新する。
double highValue = 0;
double lowValue = 100000;

for( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
{
if( i < rates_total - 1 )
{
highValue = highBuffer[i + 1] > NONDATAVALUE ? zoneHighBuffer[i + 1] : highBuffer[i + 1];
lowValue = lowBuffer[i + 1] > NONDATAVALUE ? zoneLowBuffer[i + 1] : lowBuffer[i + 1];
}

int hour = TimeHour(time[i]);

if( hour == StartHour && TimeMinute(time[i]) == 0 && TimeSeconds(time[i]) == 0 )
{
highValue = high[i];
lowValue = low[i];
zoneHighBuffer[i] = highValue;
zoneLowBuffer[i] = lowValue;

}
else if( ( StartHour < EndHour &&  StartHour <= hour && hour < EndHour) ||
( StartHour > EndHour && (StartHour <= hour || hour < EndHour)))
{
bool changeFlag = false;
if( high[i] > highValue )
{
highValue = high[i];
changeFlag = true;
}
if( low[i] < lowValue )
{
lowValue = low[i];
changeFlag = true;
}
if( changeFlag )
{
// 高値安値が切り替わったので過去にさかのぼって更新する。
for( int j = i + 1; j < rates_total; j++ )
{
int currentHour = TimeHour(time[j]);
if( StartHour <= hour && currentHour < StartHour ) break;
if( StartHour > hour && currentHour < StartHour && TimeDay(Time[j]) != TimeDay(time[i]) ) break ;

zoneHighBuffer[j] = highValue;
zoneLowBuffer[j] = lowValue;
}
}
zoneHighBuffer[i] = highValue;
zoneLowBuffer[i] = lowValue;
}
else
{
// 線をつなげるために切り替え時間までは描画する。
if( hour == EndHour && TimeMinute(time[i]) == 0 && TimeSeconds(time[i]) == 0 )
{
zoneHighBuffer[i] = highValue;
zoneLowBuffer[i] = lowValue;
}
highBuffer[i] = highValue;
lowBuffer[i] = lowValue;
}
}

return(rates_total - 1);
}


高値を例にとると、highBufferとzoneHighBufferでバッファを使い分けることで色変えを実現しています。東京時間の間はzoneHighBufferを更新して、highBuffer側は初期値のままにしています。そのため、東京時間ではhighBufferは描画されず、zoneHighBufferのみ描画されています。東京時間以外では逆のことを行っています。こうすることで、単純な横線と色変えを実現してみました。

2015.5.12 月が切り替わった際、表示が崩れる不具合修正
過去データを更新する際に、日付の切り替わりを<で比較していましたが、23時から6時とかの設定をされると、表示が崩れる障害がありました。
TimeDay(Time[j]) < TimeDay(time[i])

TimeDay(Time[j]) != TimeDay(time[i])
と修正しました。