見出し画像

ハイロー用サインツールを作ってみた② リアルタイムの動き部分の実装

昨日の続き。

ハイローオーストラリアとかHighLowバイナリーオプションのシグナル通知サインツール作っていきます。

前回記事はこちらから。


前回はMT5で過去のデータに対して、サインの矢印と勝率を表示するところまで作りました。

今回は、リアルタイムに表示される新しいローソク足に対してサインの矢印を表示させ、勝率を計算させます。

アラートとかLINE通知とかは次回にします。


期間を指定してサインを表示する

ローソク足の出現に合わせてサインを表示させる前に、サインを計算させる期間を指定します。例えば、2024年3月1日0時0分からみたいに。

現在のコードのままだとMT5に保存されている一番古いデータから全部計算されます。時間がかかりすぎるし、そんな古い時期のデータいらんわってこともあると思います。

ってことで、計算期間を指定する部分を実装していきます。

#property indicator_chart_window

input datetime startDate = D'2024/1/15 0:00';      // 計算する期間の開始日付

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[])
{
   // 開始日付のバー番号を取得する
   int startBar = iBarShift(_Symbol,PERIOD_CURRENT,startDate);

   if(prev_calculated==0){
      // 開始日付のバー番号から計算を開始する
      for(int i=rates_total-startBar; 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");
}


変更した部分は、inputで日付入力する部分と変数startBar、計算繰り返し部分をrates_total-startBarにしたくらいです。

input使えばパラメータとして、開始日を指定可能
指定した日付からしかサインが表示されません


これをすることで、検証期間の開始位置を指定することができます。2005年からじゃなくて2024年からだけでいい、とか、今月4月だけで良いって選択ができるようになります。

計算期間が短くなると計算が早くなり、サイン描写までにかかる時間が短くなります。

メリットしかないですね。



新しいローソク足に対してサインを表示する

さて、では新しいローソク足に対してサインを表示させていきましょう。

今回のサインは時間の切り替わりで表示され、予想通りの動きであれば水色〇、違えば赤色の●になるようにしています。

例えば、陰線の次が陽線になると予想した場合は次のようになります。

  1. 予想通り陽線 : 水色〇

  2. 予想と異なり陰線 : 赤色●

これはtickの更新毎に再計算されます。

陰線→陽線:水色〇 陰線→陰線:赤色●


#property indicator_chart_window

input datetime startDate = D'2024/4/15 0:00';      // 計算する期間の開始日付

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[])
{
   // 開始日付のバー番号を取得する
   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-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++;
         }
      }
   }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-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-1]<close[lastBar-1] && open[lastBar]<close[lastBar]){
         makeArray(int(time[lastBar]), time[lastBar], high[lastBar], 174, clrRed, ANCHOR_BOTTOM);
         lowLost++;
      }
      
      // 陰線 → 陽線
      if(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-1]>close[lastBar-1] && open[lastBar]>close[lastBar]){
         makeArray(int(time[lastBar]), time[lastBar], low[lastBar], 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");
}


if(prev_calculated==0) の部分でインジケータを入れた時間までに表示されているローソク足の計算を行います。

else以下の部分で、新たに出現したローソク足を計算します。

      // 勝率計算に必要な値を減算
      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])));
      }


この部分で、オブジェクトを一度消しています。ローソク足が確定する前に陰線から陽線になったりすることもあるかと思います。そういった場合にサインの表示が変更されるようにしています。

なお、勝率計算に必要な勝ち数と負け数のカウントも毎回減算するようにしています。


さて、ここまでチャートに対して勝率を表示することを行ってきましたが、実際に必要なサイン表示がまだできていません。

本来なら、「次の足が陽線になりそう」って時に、一つ前の足で予告サインが出て、切り替わり直前にGOのサインが欲しいところです。

ということで、次回は「次の足でエントリーした方が良さそうだよ」って予告サインと、「次の時間切り替わりでエントリーしろよ」ってサインを表示する部分を作成していこうと思います。

ってところで1万文字を超えてきたので、今日はここまでにします。

お疲れさまでした。


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

https://twitter.com/highlow_oyaji

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