見出し画像

暇だからバイナリーオプションのシグナル通知サインツールの作り方書いていく

さて、世の中はゴールデンウィーク。為替は歴史的円安で大騒ぎですが、私は土曜も開場しているHighLowオーストラリアでトレーディング。

と言っても、サインツールのサインが点灯するまでは、MT5を表示しながらYouTubeとXを見ているだけの一日。家族も出かけちゃったし、暇なんでnote書き始めました。

で、今日から何回かに分けて、サインツールの作り方とかを書いていこうかなぁって思ってます。


シグナル通知サインツールを何で作るか

いきなりタイトル見出しを書いちゃいましたが、何から始めようか決めてないし、行き当たりばったりです。読みにくかったらごめんなさいね。

まずは、何でシグナル通知ツールを作るかですが、メジャーなのはMT4かMT5かTradingViewですよね。

私は、外出時にスマホで確認する時はTradingView、家でチャートを表示する時とか過去検証する時はMT5使ってます。

TradingViewって数日分は見れるんですけど、それ以前のデータって見れないんですよね。だから過去検証には不向きかなって思ってます。

過去検証を簡単に高速で処理するなら、MT5から1分足かtickを吐き出してPythonで解析したら早いですが、ハードル高いし一般的じゃないですよね。

ってことで、MT5でシグナル通知サインツール作ります。


MT5の導入方法

面倒なんでググってください。このFX会社がおすすめ → IB口座 ってやってもいいですけど、面倒なんでお好きなFX会社のMT5口座用意してください。


シグナル通知サインツールのゴール

  1. チャートにエントリーの結果が表示されること

  2. エントリー条件に対し、過去検証と勝率が見れること

  3. エントリー直前に通知を出せること

これくらいですかね?


チャートにエントリーの結果を表示

よくあるサインツールみたいな矢印をチャートに表示するコード書いていきます。

まずは、チャート上にサインの矢印オブジェクトを作る関数を用意します。

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);
}

インジケータらしくバッファ配列に格納する方法もあるんですが、個人的にオブジェクトが好きなんで、今回はオブジェクトで作ります。


とりあえず10時になったらショートするようなサインを作ってみます。

#property indicator_chart_window

int OnInit()
{

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int  reason)
{
   ObjectsDeleteAll(0,"BoTest_");
}


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[])
{
   if(prev_calculated==0){
      for(int i=0; i<rates_total; i++){
         MqlDateTime dt;
         TimeToStruct(time[i],dt);
         if(dt.hour==10 && dt.min==0){
            makeArray(int(time[i]), time[i], high[i], 234, clrMagenta, ANCHOR_BOTTOM);
         }
      }
   }
   
   Comment("");
   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);
}

BoTestってオブジェクト名は付けましたが、これだけだと次のサインが出た時に過去のサインが上書きされちゃうんで、バー番号(barnum)って変数でオブジェクトを個別に管理できるようにしています。

10時にピンクの下矢印表示


10時にピンクの下矢印

これだけじゃ面白くないですよね。


次は、10時が陰線なら〇、陽線なら×にでもしてみましょうか。

#property indicator_chart_window

int OnInit()
{

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int  reason)
{
   ObjectsDeleteAll(0,"BoTest_");
}


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[])
{
   if(prev_calculated==0){
      for(int i=0; i<rates_total; i++){
         MqlDateTime dt;
         TimeToStruct(time[i],dt);
         if(dt.hour==10 && dt.min==0){
            if(open[i]>close[i]){
               makeArray(int(time[i]), time[i], high[i], 161, clrAqua, ANCHOR_BOTTOM);}
            if(open[i]<close[i]){
               makeArray(int(time[i]), time[i], high[i], 174, clrRed, ANCHOR_BOTTOM);}
         }
      }
   }
   
   Comment("");
   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);
}

〇はあったけど、×の記号がなかったので、爆発してるみたいなマークにして色も変えてみた。


水色:陰線 赤色:陽線


水色:陰線 赤色:陽線

まだ面白くないですね。


一個前が陽線で次が陰線、一個前が陰線で次が陽線のパターンを表示してみます。

陰線→陽線 もしくは 陽線→陰線
#property indicator_chart_window

int OnInit()
{

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int  reason)
{
   ObjectsDeleteAll(0,"BoTest_");
}


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[])
{
   if(prev_calculated==0){
      for(int i=1; i<rates_total; i++){
         // 陽線 → 陰線
         if(open[i-1]<close[i-1] && open[i]>close[i]){
            makeArray(int(time[i]), time[i], high[i], 161, clrAqua, ANCHOR_BOTTOM);
         }else if(open[i-1]<close[i-1] && open[i]<close[i]){
            makeArray(int(time[i]), time[i], high[i], 174, clrRed, ANCHOR_BOTTOM);
         }
         
         // 陰線 → 陽線
         if(open[i-1]>close[i-1] && open[i]<close[i]){
            makeArray(int(time[i]), time[i], low[i], 161, clrAqua, ANCHOR_TOP);
         }else if(open[i-1]>close[i-1] && open[i]>close[i]){
            makeArray(int(time[i]), time[i], low[i], 174, clrRed, ANCHOR_TOP);
         }
      }
   }
   
   Comment("");
   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");
}

オブジェクトを表示するだけのコードに計算に必要な変数を入れちゃいます。


#property indicator_chart_window

double highWin,highLost,lowWin,lowLost;

int OnInit()
{

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int  reason)
{
   ObjectsDeleteAll(0,"BoTest_");
}


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[])
{
   if(prev_calculated==0){
      for(int i=1; i<rates_total; i++){
         // 陽線 → 陰線
         if(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-1]<close[i-1] && open[i]<close[i]){
            makeArray(int(time[i]), time[i], high[i], 174, clrRed, ANCHOR_BOTTOM);
            lowLost++;
         }
         
         // 陰線 → 陽線
         if(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-1]>close[i-1] && open[i]>close[i]){
            makeArray(int(time[i]), time[i], low[i], 174, clrRed, ANCHOR_TOP);
            highLost++;
         }
      }
   }
   
   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");
}



勝率を表示

BTCUSDの15分足において、足が反転する確率は52.8%らしいです。検証したローソク足の数は216954本なので、そこそこ信用できる数字なのではないでしょうか?

1÷0.528=1.89…

ペイアウト率が1.9以上あれば、そこそこ使えます。

実際、15分足のBTCUSDでペイアウト率1.9以上で取り扱ってるところは無いです。(あったら教えてください。)


やっぱり55%とか57%は欲しいところですよね。

じゃあ次に何しよっか?RSI見てみる?みたいな感じでインジとかローソク足の条件を足して、勝率が上がるポイントを探します。

条件を厳しくすると勝率が上がったとしても、エントリー回数が減ります。このあたりのさじ加減が重要だと思います。


陰線陽線の反転だけを他通貨でも検証してみました。


水色:50%以下 ピンク色:53%以上

全通貨の1分足では反転する確率は50%以下です。

BTCUSDの30分、60分(1時間足)、240分(4時間足)では反転確率が53%以上と若干高いようです。


バックテストまで書いたところで1万文字になったんで終了。明日はアラート通知とか書いていきます。

こんな感じのサインツール欲しいみたいなんがあれば、XにDMください。

https://twitter.com/highlow_oyaji

ほなビットコイン動き始めたんで戻ります。

この記事が気に入ったらサポートをしてみませんか?