今回はバックテストを行うにあたっての準備としてアローのカウント方法とその表示について説明していこうと思います。
サインツール編の方で紹介しているRSIのサインサンプルを元に今回も進めていきます。
今回の内容
今回行う内容は
- 下矢印、上矢印のカウントを行う
- カウントした数字を実際に表示する(ラベルオブジェクト)
上記2点の内容を説明していきます。
サンプルコード(アローカウント+ラベル表示)
まずは全体のサンプルコードから
アローのカウント方法は様々ありますが、今回はブログ管理人の経験からコード追加量の少ない方法でご紹介します。
#property copyright "TAKULOG"
#property version "1.00"
#property strict
#property indicator_chart_window//メインウィンドウに表示
#property indicator_buffers 2 //インジケータのバッファを2つ用意
#property indicator_color1 Red //1つ目のインジケータを赤色に設定
#property indicator_color2 Blue //2つ目のインジケータを青色に設定
#property indicator_width1 1 //1つ目のインジケータの太さを3に設定
#property indicator_width2 1 //2つ目のインジケータの太さを3に設定
//バッファー用意///////////////////////////////////////////////
double ArrowUp[]; //上矢印用バッファー
double ArrowDown[]; //下矢印用バッファー
datetime Timeflag = 0;//時間保有用変数
int COUNT=0; //アローカウント保有用変数
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit(){ //初期化関数---主に初期条件やチャート更新時に決めておく内容を書く項目
//下矢印1
SetIndexBuffer(0,ArrowDown); //バッファを用意
SetIndexStyle(0,DRAW_ARROW); //矢印を出す
SetIndexArrow(0,238); //矢印の種類設定 調べると各矢印形等の番号が出る
SetIndexEmptyValue(0,0.0);
SetIndexLabel(0,"arrow_Down");//ラベル(名前)を決める
//上矢印1
SetIndexBuffer(1,ArrowUp); //バッファを用意
SetIndexStyle(1,DRAW_ARROW); //矢印を出す
SetIndexArrow(1,236); //矢印の種類設定 調べると各矢印形等の番号が出る
SetIndexEmptyValue(1,0.0);
SetIndexLabel(1,"arrow_Up"); //ラベル(名前)を決める
LABEL("COUNT",50,50,20,clrGold);//ラベル関数でラベルを生成
//---
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 limit = rates_total - prev_calculated;
int n = 2; //array out of range対処
if (limit > 1) {limit = rates_total - n - 1;}
// <<アロー用forループ開始>>///////////////////////////////////////////
for(int i=limit; i>=0; i--){//for開始
if(i+1 >= Bars-1){continue;}
////// 【RSI値取得】 ///////////////////////////////////////////
double RsiCL =iRSI(NULL,0,14,PRICE_CLOSE,i); //現行足RSI
// <<アロー条件定義>> ////////////////////////////////////////////
if(RsiCL>=70){ //条件①
ArrowUp[i] =0; //0に返す
ArrowDown[i]=High[i]; //下矢印を高値に表示
}
else if(RsiCL<=30){ //条件②
ArrowUp[i]=Low[i]; //上矢印を安値に表示
ArrowDown[i]=0; //0に返す
}
else{
ArrowDown[i]=0; //0に返す
ArrowUp[i] =0; //0に返す
}
if(Timeflag!=Time[i]){
if(ArrowUp[i+1]!=0||ArrowDown[i+1]!=0){
COUNT++;
ObjectSetString(0,"COUNT",OBJPROP_TEXT,(string)COUNT);
}
Timeflag=Time[i];
}
}
// <<アロー用forループ終了>> ///////////////////////////////////
//--- return value of prev_calculated for next call
return(rates_total);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>自作関数
// ------ << テキスト >>--------------------------------------------------------
void LABEL(string label,int posx,int posy,int FS,color fontcolor){
ObjectCreate(label,OBJ_LABEL,0,0,0); // ラベルを生成
ObjectSetString (0,label,OBJPROP_FONT,"メイリオ"); // ラベルのフォントを指定
ObjectSetInteger(0,label,OBJPROP_FONTSIZE,FS); // 文字のサイズ
ObjectSetInteger(0,label,OBJPROP_CORNER,0); // オブジェクトの表示コーナー
ObjectSetInteger(0,label,OBJPROP_XDISTANCE,posx); // オブジェクトのX(横方向)表示位置
ObjectSetInteger(0,label,OBJPROP_YDISTANCE,posy); // オブジェクトのY(縦方向)表示位置
ObjectSetInteger(0,label,OBJPROP_COLOR,fontcolor); // 文字色を設定する
ObjectSetInteger(0,label,OBJPROP_BACK,false); // 前景(false)または背景(true)に表示
ObjectSetInteger(0,label,OBJPROP_SELECTABLE,false);// オブジェクトの選択可否設定
ObjectSetInteger(0,label,OBJPROP_HIDDEN,true); // オブジェクトリスト表示設定
}
コンパイルしたもの
今回追加したコード
今回追加したコードは下記の通り(追加している位置等に注意)
//グローバル変数で追加したコード
datetime Timeflag = 0;//時間保有用変数
int COUNT=0; //アローカウント保有用変数
//int OnInit()内で追加したコード
LABEL("COUNT",50,50,20,clrGold);//ラベル関数でラベルを生成
//int OnCalculate内で追加したコード
if(Timeflag!=Time[i]){
if(ArrowUp[i+1]!=0||ArrowDown[i+1]!=0){
COUNT++;
ObjectSetString(0,"COUNT",OBJPROP_TEXT,(string)COUNT);
}
Timeflag=Time[i];
}
}
//最下部で追加したコード(グローバル変数)
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>自作関数
// ------ << テキスト >>--------------------------------------------------------
void LABEL(string label,int posx,int posy,int FS,color fontcolor){
ObjectCreate(label,OBJ_LABEL,0,0,0); // ラベルを生成
ObjectSetString (0,label,OBJPROP_FONT,"メイリオ"); // ラベルのフォントを指定
ObjectSetInteger(0,label,OBJPROP_FONTSIZE,FS); // 文字のサイズ
ObjectSetInteger(0,label,OBJPROP_CORNER,0); // オブジェクトの表示コーナー
ObjectSetInteger(0,label,OBJPROP_XDISTANCE,posx); // オブジェクトのX(横方向)表示位置
ObjectSetInteger(0,label,OBJPROP_YDISTANCE,posy); // オブジェクトのY(縦方向)表示位置
ObjectSetInteger(0,label,OBJPROP_COLOR,fontcolor); // 文字色を設定する
ObjectSetInteger(0,label,OBJPROP_BACK,false); // 前景(false)または背景(true)に表示
ObjectSetInteger(0,label,OBJPROP_SELECTABLE,false);// オブジェクトの選択可否設定
ObjectSetInteger(0,label,OBJPROP_HIDDEN,true); // オブジェクトリスト表示設定
}
アローカウント方法の理屈
上矢印または下矢印が前足(i+1)に表示されている時にCOUNTに1を足すコード
if(ArrowUp[i+1]!=0||ArrowDown[i+1]!=0){ // サンプルコードではアロー条件が無い場合は0を返しているので !=0 :0以外の数値がある=アローがある
COUNT++; //COUNT=COUNT+1;と同じ意味
}
int OnCalculate内で一度だけ処理を行うコード。通常 int OnCalculate内は通常テイック毎の処理になる為、確定足のみ処理するループ等や今回紹介するコード等を使用しないとテイックが動くたびカウント数が増えるので注意。
if(Timeflag!=Time[i]){ //Timeflag:初期値0 と現行足の時間が同じじゃない場合
//処理したい項目
Timeflag=Time[i]; //処理したい項目終了後 Timeflagを現行足の時間にする
}
処理のイメージは下記の画像参照
この処理とアローのカウントの理屈を足して
if(Timeflag!=Time[i]){
if(ArrowUp[i+1]!=0||ArrowDown[i+1]!=0){
COUNT++;
ObjectSetString(0,"COUNT",OBJPROP_TEXT,(string)COUNT); //COUNTというオブジェクトにCOUNTの数字を表示
}
Timeflag=Time[i];
}
}
このようにしてあげることでアローを一つ一つカウントすることが可能になります。
自作関数 LABEL() での処理
今回自作関数にてラベルを表示しています。一つのオブジェクトを生成する場合であれば必要はなかったりしますが、今後勝率表示する項目を増やす際、ある方が便利(コード自体を短縮できる)である為、この段階で使用しています。
今はあまり理解できなくても、今後表示するラベルを増やしていく際に、理解してもらえたらと思いますが、簡単に説明していきます。
LABEL("COUNT",50,50,20,clrGold);//ラベル関数でラベルを生成
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>自作関数
// ------ << テキスト >>--------------------------------------------------------
void LABEL(string label,int posx,int posy,int FS,color fontcolor){
ObjectCreate(label,OBJ_LABEL,0,0,0); // ラベルを生成
ObjectSetString (0,label,OBJPROP_FONT,"メイリオ"); // ラベルのフォントを指定
ObjectSetInteger(0,label,OBJPROP_FONTSIZE,FS); // 文字のサイズ
ObjectSetInteger(0,label,OBJPROP_CORNER,0); // オブジェクトの表示コーナー
ObjectSetInteger(0,label,OBJPROP_XDISTANCE,posx); // オブジェクトのX(横方向)表示位置
ObjectSetInteger(0,label,OBJPROP_YDISTANCE,posy); // オブジェクトのY(縦方向)表示位置
ObjectSetInteger(0,label,OBJPROP_COLOR,fontcolor); // 文字色を設定する
ObjectSetInteger(0,label,OBJPROP_BACK,false); // 前景(false)または背景(true)に表示
ObjectSetInteger(0,label,OBJPROP_SELECTABLE,false);// オブジェクトの選択可否設定
ObjectSetInteger(0,label,OBJPROP_HIDDEN,true); // オブジェクトリスト表示設定
}
このコードを関数を使わずに書くと
ObjectCreate("COUNT",OBJ_LABEL,0,0,0); // ラベルを生成
ObjectSetString (0,"COUNT",OBJPROP_FONT,"メイリオ"); // ラベルのフォントを指定
ObjectSetInteger(0,"COUNT",OBJPROP_FONTSIZE,20); // 文字のサイズ
ObjectSetInteger(0,"COUNT",OBJPROP_CORNER,0); // オブジェクトの表示コーナー
ObjectSetInteger(0,"COUNT",OBJPROP_XDISTANCE,50); // オブジェクトのX(横方向)表示位置
ObjectSetInteger(0,"COUNT",OBJPROP_YDISTANCE,50); // オブジェクトのY(縦方向)表示位置
ObjectSetInteger(0,"COUNT",OBJPROP_COLOR,clrGold); // 文字色を設定する
ObjectSetInteger(0,"COUNT",OBJPROP_BACK,false); // 前景(false)または背景(true)に表示
ObjectSetInteger(0,"COUNT",OBJPROP_SELECTABLE,false);// オブジェクトの選択可否設定
ObjectSetInteger(0,"COUNT",OBJPROP_HIDDEN,true); // オブジェクトリスト表示設定
となります。それぞれ対応する項目に数値や文字が入るようになります。
アンカーは上から順に(0.1.2.3)で指定可能です。
この関数のみであれば本来テキストの部分は「LABEL」と表示されるのですが、文字をカウントする処理の場所にて
ObjectSetString(0,"COUNT",OBJPROP_TEXT,(string)COUNT); //COUNTというオブジェクトにCOUNTの数字を表示
テキストを指定するコードを差し込んでいる為、カウントした数字の363が入っている感じになります。
本コードの余談
Oninit内でラベル関数を使用してラベルを生成、OnCalculate内でラベルのテキストのみを変更している処理にしていますが、少しでも軽量化していこうという点でこういった仕様にしています。
Oninitでは主にチャート更新時や時間軸切替時のみ処理をする項目ですので、そこでラベルを生成だけしておくことで、OnCalculate内でアローのカウント数が変更された際に文字だけ変更すればいいという感じです。