2015年4月28日火曜日

青赤荒れ狂う! MT4でS/Rオシレータのシグナルを青赤帯でチャートに表示する。その2

前回に続いてS/Rオシレータに青赤帯を出したいと思います。
組み込んだコードがこちらです。

修正箇所は赤字にしてあります。
//------------------------------------------------------------------
// ウィドナー博士のサポートレジスタンス オシレーター
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

#include <Arrays/ArrayDouble.mqh>

//オブジェクト名
#define WSRO_OBJECT_NAME "WSRO"

#property indicator_separate_window
#property indicator_minimum    0
#property indicator_maximum    100

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

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

//サポートオシレータ情報
#property indicator_label1  "Support"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//レジスタンスオシレータ
#property indicator_label2  "Resistance"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//入力パラメータ 期間
input int Period = 6;

//入力パラメータ HL期間(奇数)
input int HLPeriod = 9;

//入力パラメータ 売買シグナルをチャート上に表示するかどうか
input bool IsShowBuySellRect = true;

//入力パラメータ 売買シグナル 買時
input color BuyColor = C'0,0,128';

//入力パラメータ 売買シグナル 売時
input color SellColor = C'78,0,0';

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

//S1-Sn
CArrayDouble supports;
//R1-Rn
CArrayDouble resistances;
//------------------------------------------------------------------
//初期化
int OnInit()
{
if( HLPeriod % 2 == 0 || HLPeriod < 5) return (INIT_PARAMETERS_INCORRECT);
if( Period < 3 ) return (INIT_PARAMETERS_INCORRECT);

//インジケータバッファを初期化する。
SetIndexBuffer(0,wsoBuffer);
SetIndexBuffer(1,wroBuffer);

SetIndexDrawBegin(0, HLPeriod + 1);
SetIndexDrawBegin(1, HLPeriod + 1);

//サポート/レジスタンス保持用の配列クリア
supports.Clear();
supports.Resize(Period);
resistances.Clear();
resistances.Resize(Period);

//インジケータ短縮名を設定する。
string short_name = "WSRO( " + IntegerToString(Period)+" , "+  IntegerToString(HLPeriod) + " )";
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);

// 先頭文字列がWSRO_OBJECT_NAMEと一致する場合、削除する。
if( StringFind(name, WSRO_OBJECT_NAME) == 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[])            //スプレット
{
// 最終計算時間
static datetime lastCalculate = 0;

//元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
{
if( i >=  rates_total - Period - 2 )
{
wsoBuffer[i] = 0 ;
wroBuffer[i] = 0 ;
continue;
}

// 同一時間足の値は再計算不要
if( lastCalculate != time[i] )
{
lastCalculate = time[i];
int centerIndex =  i + 1 + (HLPeriod - 1) / 2;

//サポート
//if Low( four days back ) = Min(lows of previous nine days) then SL=Low(four days back)
if( iLowest(NULL, PERIOD_CURRENT, MODE_LOW, HLPeriod, i + 1) == centerIndex )
{
// 新しいサポートが構築された場合、Period数保持する。
if( supports.Total() >= Period )
{
supports.Delete(supports.Total() - 1);
}
supports.Insert(iLow(NULL, PERIOD_CURRENT, centerIndex), 0);
}

//レジスタンス
//if High( four days back ) = Max(high of previous nine days) then RL=High(four days back)
if( iHighest(NULL, PERIOD_CURRENT, MODE_HIGH, HLPeriod, i + 1) == centerIndex )
{
// 新しいレジスタンスが構築された場合、Period数保持する。
if( resistances.Total() >= Period )
{
resistances.Delete(resistances.Total() - 1);
}
resistances.Insert(iHigh(NULL, PERIOD_CURRENT, centerIndex), 0);
}
}

//wsoの計算 1 - ((int)S1/C + (int)S2/C +(int)S3/C +(int)S4/C +(int)S5/C +(int)S6/C) / 6
if( supports.Total() == Period )
{
double wso = 0 ;
for( int j = 0 ; j < supports.Total(); j++ )
{
wso += (int) (supports.At(j) / close[i]);
}
wsoBuffer[i] = (1 - wso / supports.Total()) * 100;
}
else
{
wsoBuffer[i] = 0;
}

if( resistances.Total() == Period )
{
//wroの計算 1 - ((int)R1/C + (int)R2/C +(int)R3/C +(int)R4/C +(int)R5/C +(int)R6/C) / 6
double wro = 0 ;
for( int j = 0 ; j < resistances.Total(); j++ )
{
wro += (int) ( resistances.At(j) / close[i]);
}
wroBuffer[i] = (1 - wro / resistances.Total()) * 100;
}
else
{
wroBuffer[i] = 0;
}

// シグナルをチャート上に表示する。
static datetime lastSignalTime = 0 ;
if( IsShowBuySellRect && wsoBuffer[i] == 100 && wroBuffer[i] == 100 )
{
if( lastSignalTime != time[i] ) CreateRectangleObject(time[i], SellColor);
lastSignalTime = time[i];
}
else if( IsShowBuySellRect && wsoBuffer[i] == 0 && wroBuffer[i] == 0 )
{
if( lastSignalTime != time[i] ) CreateRectangleObject(time[i], BuyColor);
lastSignalTime = time[i];
}
else
{
DeleteRectangleObject(time[i]);
}
}

return(rates_total - 1);
}

//------------------------------------------------------------------
//売買シグナルを矩形で描画する。
bool CreateRectangleObject(
datetime time,       //表示時間(横軸)
color backColor      //背景色
)
{
//オブジェクトを作成する。
long chartId = ChartID();

int period = PeriodSeconds(PERIOD_CURRENT);

string name = WSRO_OBJECT_NAME + TimeToStr(time);

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

if( !ObjectCreate(chartId, name, OBJ_RECTANGLE, 0, time, max, time + period, min) )
{
return false;
}
ObjectSetInteger(chartId, name, OBJPROP_COLOR, backColor);

return true;
}


//------------------------------------------------------------------
//オブジェクトを削除する。
bool DeleteRectangleObject(
datetime time        //表示時間(横軸)
)
{
//オブジェクトを作成する。
long chartId = ChartID();
string name = WSRO_OBJECT_NAME + TimeToStr(time);

if( ObjectDelete(chartId, name) )
{
#ifdef DEBUG
Print("Ojbect Deleted " + name);
#endif
}

return true;
}


赤字になっている部分が、前回との差分です。
組み込んだ関数を、シグナルが出ている時に作成するというコードを作成しています。

また、OnDeinitで作成したオブジェクトを消しています。これをしないと、例えばチャートの時間足を変更した場合などに作った図形がそのまま表示されてしまいます。後始末は忘れず行いましょう。
なお、ソースのコメントにも書いてありますが、ObjectsTotal()関数で、チャート上のオブジェクト数を取得して、インデックスの最大値から減らしていく形で消していっています。0から消していってしまうと、MT4が内部で持っているオブジェクトの配列と位置があわなくなり正しく消せなくなるので注意しましょう。

さて、さっそくシグナルをだしたS/Rオシレータを見てみたいと思います。EURUSDの1時間足です。
signal1.png
それっぽく赤い帯が出ていますね。入力パラメータのSellColorで指定してある色で描画しています。矩形を表示すると少し透過効果がでるようです。
うーん。なんとなくいい感じですが、結構広い幅でシグナルが出てしまっています。

signal4.pngsignal3.png

もう少し敏感に反応してほしいので、HLPeriodの値を9から5に変えてみました。(過去5本のうち2本目が最高値・安値だった場合サポートレジスタンスラインとするという設定になります)
まぁありかも?っていうふうな感じでしょうか?

このようにチャートの上に帯が出ているとわかりやすくなるのはないかと感じました。

ちなみに、時間を変えてもう一枚。
signal2.png
うーん。やっぱりこのオシレータ。だらだらと一方向に動き続ける局面だとダミーのシグナルを出し続けてしまいます。何かしらの別のやつと組み合わせないと大変なことになりそうです^^;
ただ、有効に機能している時間帯は有効に機能し続ける傾向にあるようにも感じます。前回シグナルタイミンが正しく判定できていた場合は、今回も有効かも?みたいな感じで使うのもありかも??

余談ですが、今日はMacbookで作業中・・。いやー仮想化ツールって便利だなー。MAC上からもMT4使えてます。とりあえず問題無く動作している雰囲気です。
etc1.png