ハイロー用サインツールを作ってみた④ シグナル表示の実装
バイナリーオプションで使うためのサインツールを作っていく第4弾です。
今回は、サインの表示部分を実装していきます。
前回までの記事はこちらから。
これまでの振り返り
前回までに作成した内容は、過去のチャートに対して、ある条件でHighもしくはLowにエントリーした場合に、成功するか失敗するかの確率を求めることまでが含まれています。
つまり、バックテストにおける勝率計算部分になります。
陽線のローソク足が2本続いたら、次が陰線になる確率はどれくらいかな?みたいなことを調べることができます。
しかし、実際のトレードでは、エントリーするかもの予告演出が無いと準備ができません。YouTubeみながらボーっとしているとき、急にエントリーですって言われても対応できないですよね。
しかも、時間切り替わりでのエントリーならば、少しの遅れが命取りになり、過去検証通りの結果が得られないかもしれません。
そこで、今回実装する予告演出が必要になってきます。
本当にエントリーしたいローソク足の一本前の足で判定させ、次の足でエントリーしても良さそうならHighかLowを表示します。
コード内容
#property indicator_chart_window
input datetime startDate = D'2024/4/15 0:00'; // 計算する期間の開始日付
double highWin,highLost,lowWin,lowLost;
int OnInit()
{
// 0.1秒ごとにタイマーイベントを動かす
EventSetMillisecondTimer(100);
setLabel("BoTest_Timer", clrWhite, CORNER_RIGHT_UPPER, 100, 30, "00:00:00", 16);
setBox("BoTest_Box",clrNONE,CORNER_RIGHT_UPPER,100,60,90,30);
setLabel("BoTest_Signal", clrWhite, CORNER_RIGHT_UPPER, 80, 65, "-", 16);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// BoTestで始まるオブジェクトを全削除
ObjectsDeleteAll(0,"BoTest_");
// タイマーイベントを削除
EventKillTimer();
Comment("");
}
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 startBar = iBarShift(_Symbol,PERIOD_CURRENT,startDate);
if(prev_calculated==0){
// 開始日付のバー番号から計算を開始する
for(int i=rates_total-startBar; i<rates_total; i++){
MqlDateTime dt;
TimeToStruct(time[i],dt);
// 陽線 → 陽線 → 陰線
if(open[i-2]<close[i-2] && open[i-1]<close[i-1] && open[i]>close[i]){
makeArray(int(time[i]), time[i], high[i], 161, clrAqua, ANCHOR_BOTTOM);
lowWin++;
}else if(open[i-2]<close[i-2] && open[i-1]<close[i-1] && open[i]<close[i]){
makeArray(int(time[i]), time[i], high[i], 174, clrRed, ANCHOR_BOTTOM);
lowLost++;
}
// 陰線 → 陰線 → 陽線
if(open[i-2]>close[i-2] && open[i-1]>close[i-1] && open[i]<close[i]){
makeArray(int(time[i]), time[i], low[i], 161, clrAqua, ANCHOR_TOP);
highWin++;
}else if(open[i-2]>close[i-2] && open[i-1]>close[i-1] && open[i]>close[i]){
makeArray(int(time[i]), time[i], low[i], 174, clrRed, ANCHOR_TOP);
highLost++;
}
}
}else{
// 最新のバー番号
int lastBar = rates_total-1;
// 勝率計算に必要な値を減算
if(ObjectFind(0,"BoTest_"+string(int(time[lastBar])))==0){
if(ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ARROWCODE)==161 &&
ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ANCHOR)==ANCHOR_BOTTOM){
lowWin--;
}else if(ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ARROWCODE)==174 &&
ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ANCHOR)==ANCHOR_BOTTOM){
lowLost--;
}
if(ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ARROWCODE)==161 &&
ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ANCHOR)==ANCHOR_TOP){
highWin--;
}else if(ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ARROWCODE)==174 &&
ObjectGetInteger(0,"BoTest_"+string(int(time[lastBar])),OBJPROP_ANCHOR)==ANCHOR_TOP){
highLost--;
}
// すでにオブジェクトがあった場合は、削除
ObjectDelete(0,"BoTest_"+string(int(time[lastBar])));
}
// 最新のバーの動きに合わせて、結果変更
// 陽線 → 陽線 → 陰線
if(open[lastBar-2]<close[lastBar-2] && open[lastBar-1]<close[lastBar-1] && open[lastBar]>close[lastBar]){
makeArray(int(time[lastBar]), time[lastBar], high[lastBar], 161, clrAqua, ANCHOR_BOTTOM);
lowWin++;
}else if(open[lastBar-2]<close[lastBar-2] && open[lastBar-1]<close[lastBar-1] && open[lastBar]<close[lastBar]){
makeArray(int(time[lastBar]), time[lastBar], high[lastBar], 174, clrRed, ANCHOR_BOTTOM);
lowLost++;
}
// 陰線 → 陰線 → 陽線
if(open[lastBar-2]>close[lastBar-2] && open[lastBar-1]>close[lastBar-1] && open[lastBar]<close[lastBar]){
makeArray(int(time[lastBar]), time[lastBar], low[lastBar], 161, clrAqua, ANCHOR_TOP);
highWin++;
}else if(open[lastBar-2]>close[lastBar-2] && open[lastBar-1]>close[lastBar-1] && open[lastBar]>close[lastBar]){
makeArray(int(time[lastBar]), time[lastBar], low[lastBar], 174, clrRed, ANCHOR_TOP);
highLost++;
}
// 予告サインの表示
// 陽線 → 陽線 なら点灯
if(open[lastBar-1]<close[lastBar-1] && open[lastBar]<close[lastBar]){
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"Low");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrRed);
// 陰線 → 陰線 なら点灯
}else if(open[lastBar-1]>close[lastBar-1] && open[lastBar]>close[lastBar]){
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"High");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrGreen);
// それ以外はなし
}else{
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"-");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrNONE);
}
}
showComment();
return(rates_total);
}
void makeArray(int barnum, datetime time, double price, int code, color clr, int anch)
{
ObjectCreate(0,"BoTest_"+string(barnum), OBJ_ARROW, 0, time, price);
ObjectSetInteger(0, "BoTest_"+string(barnum), OBJPROP_ARROWCODE, code);
ObjectSetInteger(0, "BoTest_"+string(barnum), OBJPROP_COLOR, clr);
ObjectSetInteger(0, "BoTest_"+string(barnum), OBJPROP_ANCHOR, anch);
}
void showComment()
{
string HW = DoubleToString( 100* highWin / (highWin+highLost), 1);
string LW = DoubleToString( 100* lowWin / (lowWin+lowLost), 1);
string TW = DoubleToString( 100* (highWin+lowWin) / (highWin+highLost+lowWin+lowLost), 1);
string Hsum = DoubleToString( highWin+highLost, 0);
string Lsum = DoubleToString( lowWin+lowLost, 0);
string Tsum = DoubleToString( highWin+highLost+lowWin+lowLost, 0);
Comment( "│ High Win : ", HW, " % ( " +Hsum+ " ) |\n",
"| Low Win : ", LW, " % ( " +Lsum+ " ) |\n",
"| TotalWin : ", TW, " % ( " +Tsum+ " ) |\n");
}
void OnTimer()
{
int now = TimeCurrent();
int PerInt = PeriodToInteger()*60;
int amari = PerInt-now%PerInt;
int rhour = amari>3600 ? amari/3600 : 0;
int rmin = amari-rhour*3600>60 ? (amari-rhour*3600)/60 : 0;
int rsec = amari-3600*rhour-60*rmin!=60 ? amari-3600*rhour-60*rmin : 0;
string txt = StringFormat("%02d:%02d:%02d", rhour, rmin, rsec);
ObjectSetString(0,"BoTest_Timer",OBJPROP_TEXT,txt);
}
void setLabel(string name, color clr, int corner, int x, int y, string txt, int FontSize)
{
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_FONTSIZE,FontSize);
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
ObjectSetString(0,name,OBJPROP_TEXT,txt);
ObjectSetInteger(0,name,OBJPROP_BACK,false);
}
void setBox(string name, color clr, int corner, int xdist, int ydist, int xsize, int ysize)
{
ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xdist);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,ydist);
ObjectSetInteger(0,name,OBJPROP_XSIZE,xsize);
ObjectSetInteger(0,name,OBJPROP_YSIZE,ysize);
ObjectSetInteger(0,name,OBJPROP_BGCOLOR,clr);
ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
ObjectSetInteger(0,name,OBJPROP_BACK,true);
}
int PeriodToInteger()
{
int PerInt = _Period;
if(_Period==16385) PerInt=60;
if(_Period==16386) PerInt=120;
if(_Period==16387) PerInt=180;
if(_Period==16388) PerInt=240;
if(_Period==16390) PerInt=360;
if(_Period==16392) PerInt=480;
if(_Period==16396) PerInt=720;
if(_Period==16408) PerInt=1440;
if(_Period==32769) PerInt=10080;
if(_Period==49153) PerInt=43200;
return (PerInt) ;
}
新たにsetBoxって関数を作って、Highなら緑の四角、Lowなら赤の四角が表示されるようにしています。
// 予告サインの表示
// 陽線 → 陽線 なら点灯
if(open[lastBar-1]<close[lastBar-1] && open[lastBar]<close[lastBar]){
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"Low");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrRed);
// 陰線 → 陰線 なら点灯
}else if(open[lastBar-1]>close[lastBar-1] && open[lastBar]>close[lastBar]){
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"High");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrGreen);
// それ以外はなし
}else{
ObjectSetString(0,"BoTest_Signal",OBJPROP_TEXT,"-");
ObjectSetInteger(0,"BoTest_Box",OBJPROP_BGCOLOR,clrNONE);
}
予告サインの表示って形で作成しています。
今回のサンプルは陽線→陽線ならLowサイン、陰線→陰線ならHighサインが出るって単純な条件しか設定していません。
今後、この条件部分だけをいじるだけでサインツールが作れるようなものを作っていこうと考えています。
ちなみに、陰線→陰線の次が陽線になる確率と、陽線→陽線の次が陰線になる確率は以下の通りです。
4年分のローソク足で検証したのですが、BTCUSD以外は、なかなか渋い結果ですね。
条件を増やせば確率は上がりますが、エントリー回数が減少します。
1日に10回前後のエントリー回数、月に200回くらい、年間2000回くらいで勝率57%以上あれば、十分な条件だと思います。
私自身運用しているのが、それくらいの条件なので。
ってことで、今日はここまで。
次回は、ロジック部分をもう少し綺麗にして、インジケータを入れた場合などの検証結果も紹介していきますね。
ここまで読んでいただき、ありがとうございます。
お疲れさまでした。
こんな感じのサインツール欲しいみたいなんがあれば、XにDMください。
この記事が気に入ったらサポートをしてみませんか?