2015年5月14日木曜日

東京時間がもっとわかりやすくしてほしい。MT4レンジインジケータを改造してみた。

矩形レンジ.PNG
この前作成した東京時間を表示するインジケータですが、友人から東京時間をもっとわかりやすくしたよと改造プログラムを頂きました。線の色が変わってくるぐらいじゃ見えにくいとのことで矩形を表示するようにしたそうです。

ちなみに友人の環境だと、OnInit内のPeriodを取得する処理を入れてしまうと、
M15とH1を切り替えた時にチャートが消える現象が発生するとのことでしたが、私の環境では発生しませんでした。さておき、環境によってOnInit内でPeriod関数が正しく値を返してこない事があるようです。
描画できない時間足の確認はOnCalculateでやったほうがよさそうですね。

このインジケータですがオブジェクトをたくさん生成して少し重たい為、MT4メニューのツール→オプションで変更できるチャートタブ内ヒストリー内最大バー数とチャートの最大バー数を5000にしておくことをお勧めします。
オプション.PNG

//+------------------------------------------------------------------+
//|                                                     MyRange2.mq4 |
//|                                                           Heecho |
//+------------------------------------------------------------------+
#property copyright "Heecho"
#property version   "1.00"
#property strict
#property indicator_chart_window

#define RangeRectangleName "RANGERECT"

#define SecOfDay 60 * 60 * 24

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

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

#property indicator_label1  "HIGH"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_DOT
#property indicator_width1  1

#property indicator_label2  "LOW"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrAqua
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

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

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

// 入力パラメータ 矩形背景色
input color RectBackColor = clrLavender;

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

//------------------------------------------------------------------
//初期化
int OnInit()
{
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 );

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

return INIT_SUCCEEDED;
}

//------------------------------------------------------------------
//終了処理
void OnDeinit( const int reason )
{
//オブジェクトを作成する。
long chartId = ChartID();

int total = ObjectsTotal( chartId );
//生成したオブジェクトを削除する。
//0から削除するとインデックス位置がずれて
//正しく削除できないため、後ろから削除するようにする。
for( int i = total - 1; i >= 0 ; i--)
{
string name = ObjectName( chartId, i );

// 先頭文字列がRangeRectangleNameと一致する場合、削除する。
if ( StringFind( name, RangeRectangleName ) == 0 )
{
ObjectDelete( chartId, name );
}
}
}

//------------------------------------------------------------------
//計算イベント
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 priod = Period();
if ( priod > PERIOD_H1 )
{
return rates_total;
}

// 開始時間から終了時間までの高値安値を更新する。
double highValue = 0;
double lowValue = 100000;

long chartID = ChartID();
for ( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
{
MqlDateTime tm;
TimeToStruct( time[ i ], tm );
tm.hour = StartHour;
tm.min = 0;
tm.sec = 0;
datetime startTime = StructToTime( tm );
tm.hour = EndHour;
datetime endTime = StructToTime( tm );
if ( StartHour > EndHour )
{
int hour = TimeHour( time[ i ] );
if ( hour < StartHour )
{
startTime -= SecOfDay;
}

if ( hour < 24 )
{
endTime += SecOfDay;
}
}

string rectName = GetRectangleName( startTime );
int rectID = ObjectFind( chartID, rectName );
if ( rectID < 0 )
{
CreateRectangleObject( rectName, startTime, endTime, RectBackColor );
}

if ( i < rates_total - 1 )
{
highValue = highBuffer[ i + 1 ];
lowValue = 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 ];
rectID = ObjectFind( chartID, rectName );
ObjectMove( chartID, rectName, 0, startTime, highValue );
ObjectMove( chartID, rectName, 1, endTime, lowValue );
}
else if ( ( StartHour < EndHour &&  StartHour <= hour && hour < EndHour )
|| ( StartHour > EndHour && ( StartHour <= hour || hour < EndHour ) )
)
{
bool changed = false;
if ( high[ i ] > highValue )
{
highValue = high[ i ];
changed = true;
}
if ( low[ i ] < lowValue )
{
lowValue = low[ i ];
changed = true;
}
if ( changed != false )
{
// 高値安値が切り替わったので過去にさかのぼって更新する。
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;
}

highBuffer[ j ] = highValue;
lowBuffer[ j ] = lowValue;
}

rectID = ObjectFind( chartID, rectName );
ObjectMove( chartID, rectName, 0, startTime, highValue );
ObjectMove( chartID, rectName, 1, endTime, lowValue );
}
}
highBuffer[ i ] = highValue;
lowBuffer[ i ] = lowValue;
}

return rates_total - 1;
}

//------------------------------------------------------------------
//矩形名を取得する。
string GetRectangleName
(
datetime time        //現在時刻
)
{
return RangeRectangleName + TimeToString( time );
}

//------------------------------------------------------------------
//矩形を生成する。
bool CreateRectangleObject
( string name
, datetime startTime    // 開始時間
, datetime endTime      // 終了時間
, color backColor       // 背景色
)
{
//オブジェクトを作成する。
long chartId = ChartID();

//チャート縦幅いっぱいに表示する。
double min = 0;
double max = ChartGetDouble( chartId, CHART_PRICE_MAX ) * 4;

if ( ObjectCreate( chartId, name, OBJ_RECTANGLE, 0, startTime, max, endTime, min ) == false )
{
return false;
}
ObjectSetInteger( chartId, name, OBJPROP_COLOR, backColor );

return true;
}

//------------------------------------------------------------------
//矩形を削除する。
bool DeleteRectangleObject(
datetime startTime   //開始時刻
)
{
//オブジェクトを作成する。
long chartId = ChartID();
string name = GetRectangleName( startTime );

if( ObjectDelete( chartId, name) )
{
}

return true;
}