見出し画像

無料公開中のEA「バイナリーオプション」が更に進化!勝率90%以上のロジックのEAとなって無料配布決定!

本日は、クリスマス特別企画ということで、「勝率60%超えのEA「BinaryOptionというEA」に、特別なチューンを施し、勝率9割超えのスペシャルなEAを作成しました。

もちろん完成したEAのソースコードはこのページの最後の方で無料ダウンロードできます。

もとになるEAのソースコードは以前のnoteの記事よりダウンロードできます。


https://note.com/aimjey/n/nc5d00526fb57

このEAは、ユーロドルとドル円において、異なるロジックで動く、マルチロジックのEAになります。

ユーロドルのロジックは、わたしの最高傑作のEAでもある、Grid Rashのロジックを採用しています。

https://www.gogojungle.co.jp/systemtrade/fx/55503

ゴゴジャンで販売している有料版のEAは、ナンピンモードを搭載していて、無料版の上位グレードという位置付けです。


また、裁量トレードに特化したサインインジケーターも販売しています。

ロジックはすべて共通のものとなります。

わたしのEA開発に費やした4年の集大成ともいえるスキャルのEAが無料で手に入るのですから、ぜひダウンロードしてください。

このBinaryOptionというEA、ドル円にも対応させるべくマルチロジック化を行いました。

ゴゴジャンにてFibonacci Trend Indicatorという名前で販売しているサインインジケーターになります。

ボリンジャーバンドとRSIを使用したスキャルの手法に、フィボナッチリトレースメントの手法を融合させたドル円1分足チャートで動作するサインインジケーターです。


https://www.gogojungle.co.jp/tools/indicators/54005


インジケーターはドル円の1分足チャートに最適化してありますが、今回無料配布するEAは5分足チャートで動作するように再設計しました。

このロジックは、億トレーダーのしんさんや、ひろしさん、それからジュンさんの手法を分析し、ボリンジャーバンドとRSIとフィボナッチリトレースメントを使用したわたくしまさやんオリジナルのスキャルの手法を採用しています。

ドル円のスキャルピング系サインインジケーターはとても需要があり、もし分スキャのEAインジが開発できたなら、きっと大きな利益をもたらしてくれるであろうことは、容易に想像できます。

インジケーター版と同じロジックを採用したEAが、なんと今回特別に無料で入手できるわけです。

完成したEAは、このページの最後にソースコードをまるごとコピーできますので、EAをカスタマイズできる方は、ぜひオリジナルのEAを作っていただければと思います。

それでは今回の動画のタイトルにもあります、勝率90%以上のロジックにする手順を解説します。

今回追加するロジックは以下の2つになります。

1、利確モードの追加

2、覚醒モードの追加

まず、2つのモードを実装するにあたり、プロパティ設定でのそれぞれのモードのオンオフを切り替えできるようにします。

//ここからver1.02
extern bool Rikaku = true;//利確モード追加=ストップ逆指値を無効にするtrue ストップロスを設定するfalse
extern bool Kakusei = true;//覚醒モード追加=損切りを行わず必ず利益確定でポジションを決済true 損切りするfalse
//ここまでver1.02

Rikaku(利確モード)は、ストップ逆指値を無効にするモードになります。
利確モードがtrueの時、注文時のStopLossは発注されず、TakeProfitのみが発注されます。

つまり、逆指値の注文が行われないので、ストップロスによる損切が発生しないことを意味します。

次に、Kakusei(覚醒モード)についてです。
損切りを行わず必ず利益確定でポジションを決済とあるように、ポジションが含み損の時は決済を行わないモードになります。
覚醒モードがtrueの時は、含み益が発生したタイミングでしかポジションを切らないということになり、利食いのみを行うトレードが可能となります。

つまり、利確モードと覚醒モードの2つのモードをtrueにすることで、勝率90%以上の常勝トレードが実現できるという仕組みです。

ただし、このロジックにはひとつ、大きな落とし穴が潜んでいます。

そうです、損切を行わないということは、含み損を抱えている間は株でいう塩漬けとなり、プラスに転じるまで永遠とポジションを保有し続けるという問題です。


ここの部分では2015年の6月に保有したポジションが2022年の4月まで保有し続けています。

実に7年もの間、塩漬けに耐えて生還したことを意味します。

このトレードは現実的ではありません。

長期間の塩漬け問題に関しては、手動で損切を行えば解決します。

何か月も塩漬けするようなら、その前に手動で決済すればいいのです。

ちなみにバックテストをする際は全ティックでバックテストを行ってください。

始値のみだと正確なバックテストを行うことができません。

以下がデイトレードのイメージです。

条件としてテイクプロフィットを0.2つまり20pipsとしたと仮定します。

一回の勝ちの平均が20pips勝ちで9連勝した後に1敗。負けの損切は100pipsとします。

そうすると、20pips勝ちが9回なので利益は180pipsです。

10回目のトレードは100pipsの損切となるので、180-100で80pipsの勝ち。

1回のトレードでは平均8pipsの勝ちとなります。

もう少し長い時間軸で考えてみましょう。

スイングトレードを想定してみます。

一回の勝ちの平均が20pips勝ちで99連勝した後に1敗。負けの損切は1000pipsとします。

先ほどの計算式に当てはめると、99連勝で1980pipsの勝ちで、1回の負けで1000pipsの損失となります。

1回あたりのトレードでは平均で9.8pipsの勝ちとなります。

もちろん、いつもこの計算通りにいくとは限りません。

また、利益幅はテイクプロフィットで指定することもできますし、テイクプロフィットを広めに設定してロジックによる決済に任せるといったやり方も有効です。

ユーロドルでテイクプロフィットを0.1つまり10pipsで利食いという設定での2007年からのバックテスト結果がこちらです。

そしてテイクプロフィットを5.0つまり500pipsで利食いという設定での2007年からのバックテスト結果がこちらです。

比べてみるとテイクプロフィットによる差がほとんどないことがわかります。

これはつまり、利益が出ている状態、含み益が発生しているタイミングでは、指値による利食いを行わずとも、ロジックによる決済が行われ、ポジションがクローズされることを意味します。

資産チャートの最後の部分が唯一の負けトレードです。

コツコツ勝ってドカンと負ける、損大利小のトレードとなることから、大きめのロットを入れるのにはあまりにもリスクが大きすぎます。

含み損が増加する前に、手動で損切を行うか、動画の最後に紹介するバージョン1.03、何分後にポジションをクローズするか指定できるバージョンをご利用ください。

無料版は単ポジのEAとして動きます。

逆張り手法ということで、ナンピンの方が勝てるので、ナンピントレードをご希望の方は、有料版を購入していただければと思います。

特に、サインインジケーター版のグリッドラッシュはスプレッドの狭い国内のFX会社での裁量トレードで利益の出せるサインインジケーターとなります。

https://www.gogojungle.co.jp/tools/indicators/55251

それでは、このEAのプログラムソースコードの解説に移ります。


コードの最後の方にあるオーダー処理関数のところを修正します。

Rikaku が true の場合ストップロスを 0 に設定する処理ですね。

// ロングオーダー処理
void CheckForOpenLong()
{
int res;
double entrylot;
entrylot = NormalizeDouble(Lots, 2);
//ここからver1.02
double stopLoss = Rikaku ? 0 : Ask - (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
double takeProfit = Ask + (Pips * TakeProfitRequest);
//ここまでver1.02
res = OrderSend(
Symbol(),
OP_BUY,
entrylot,
Ask,
Adjusted_Slippage,
stopLoss, // ストップロス設定
takeProfit, // リミット設定
CommentPositions,
Magic,
0,
clrRed);
return;
}

// ショートオーダー処理
void CheckForOpenShort()
{
int res;
double entrylot;
entrylot = NormalizeDouble(Lots, 2);
//ここからver1.02
double stopLoss = Rikaku ? 0 : Bid + (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
double takeProfit = Bid - (Pips * TakeProfitRequest);
//ここまでver1.02
res = OrderSend(
Symbol(),
OP_SELL,
entrylot,
Bid,
Adjusted_Slippage,
stopLoss, // ストップロス設定
takeProfit, // リミット設定
CommentPositions,
Magic,
0,
clrBlue);
return;
}

//ここからver1.02から//ここまでver1.02のところに Rikaku が true の場合ストップロスを 0 に設定とする処理を追加しました。

もう一か所、プログラムソースコードの真ん中くらいのところに、以下のコードを追加します。

//ここからver1.02
// ■□■□■□■□■ Kakusei 覚醒モードの判定 ■□■□■□■□■
if (Kakusei == true) {
double totalProfit = 0;
for (int i = 0; i < OrdersTotal(); i++) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
totalProfit += OrderProfit();
}
}
}
if (totalProfit < 0) { // 保有ポジションがマイナスの場合
LongSign = false;
ShortSign = false;
}
}
//ここまでver1.02

この処理で保有ポジションがマイナスの場合は売買サインが出なくなります。

以前なら、こうしたプログラムはすべて手動でコーディングしていたのですが、ChatGPTなどの生成AIの登場により、手動でプログラミングすることが減りました。

今回の修正は、ChatGPTのコードを組み込むことで、わずか10分で完了しました。

このように、MQL4のようなマイナーなプログラミング言語すらAIによるコーディングが可能となったことからもわかるように、今後は人間の手によるプログラミングは確実に減ることでしょう。

完成したEA(バージョン1.02)でのバックテストでは、含み損発生時は損切を行わない設定となるため、ところどころで塩漬けの期間が存在します。

バージョン1.02のEAのソースコードはこちらです。

//+------------------------------------------------------------------+
//|                                BinaryOption_USDJPY_EURUSD_M5.mq4 |
//|   ポジションを保有してから何分後に決済するか指定できるロジックを追加                   |
//|   バージョン1.02で利確モードと覚醒モード追加                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Masayan."
#property version   "1.02"
#property strict
#property description "https://fx.reform-network.net"

extern int Magic = 20241126;// Magic number
extern double Lots = 0.1;//1.0=100000 0.1=10000 0.01=1000
extern double StopLossRequest = 1.0;// StopLoss 0.1=10pips 0.5=50pips 1=100pips
extern double TakeProfitRequest = 5.0;// TakeProfit 0.1=10pips 0.5=50pips 1=100pips
extern int PositionHoldMinutes = 45; // ポジション保有後の決済時間(分)※覚醒モードがtrueの時は無効
//ここからFibonacci Retracement USDJPY
extern int BollingerBandsPeriod = 30; // ボリンジャーバンドの期間「USDJPY」
extern int BollingerBandsDeviation = 2; // ボリンジャーバンドのシグマ値「USDJPY」
extern int FibonacciLookBack = 500; // フィボナッチリトレースメント計算のための過去の期間500か1000「USDJPY」
extern double FibonacciLevel = 0.5; // フィボナッチリトレースメントのレベル (例: 0.5 = 50%)「USDJPY」
int RsiPeriod = 14; // RSIの期間
//ここからGrid Rash EURUSD
extern double GridSize = 0.05;  // カギ足のサイズ(最小値0.01=1pips 推奨値0.05=5pips 最大値0.5=50pips)「EURUSD」
extern int ADXPeriod = 40;// ADXの計算期間(範囲10~150)「EURUSD」
extern double ADXThreshold = 15.0;// トレンドの強さを判断するための基準値(範囲5~50)(数字が小さいほどトレード回数が増える)「EURUSD」
double lastBrickHigh = 0;  // 前回のカギ足高値「EURUSD」
double lastBrickLow = 0;   // 前回のカギ足安値「EURUSD」
//ここまでGrid Rash EURUSD

//ここからver1.02
extern bool Rikaku = true;//利確モード追加=ストップ逆指値を無効にするtrue ストップロスを設定するfalse
extern bool Kakusei = true;//覚醒モード追加=損切りを行わず必ず利益確定でポジションを決済true 損切りするfalse
//ここまでver1.02
 
extern int MaxSpread = 50;// Max spread (50=5pips)
extern int MaxError = 100;// Continuous order count limit (Max=100)
extern string CommentPositions = "BinaryOption";

string tmpstr;
string error_msg;
string spread_msg;
string position_msg;
bool LongSign = false;
bool ShortSign = false;
double Pips = 0.01;
int e = 0;
int Adjusted_Slippage = 0;
datetime LongPositionOpenTime = 0; // ロングポジションのオープン時刻
datetime ShortPositionOpenTime = 0; // ショートポジションのオープン時刻

// フィボナッチリトレースメントを計算する関数
double CalculateFibonacciLevel(double high, double low, double level)
{
   return high - (high - low) * level;
}
// グリッドラッシュで使用
double currentPrice = iClose(NULL, 0, 0);
// ティックが動くごとに処理
void OnTick()
{
   if (Bars < FibonacciLookBack)
   {
      return;
   }

   if (StopLossRequest <= 0.01)
   {
      StopLossRequest = 0.01;
   }
   if (TakeProfitRequest <= 0.01)
   {
      TakeProfitRequest = 0.01;
   }
   if (MaxError >= 100)
   {
      MaxError = 100;
   }

   double Info_Spread = MarketInfo(Symbol(), MODE_SPREAD);
   string value = Symbol();
   string target = "JPY";
   int pos = StringFind(value, target);
   double Symbol_RATE = Close[1];
   if (pos > 0)
   {
      Pips = 1.00;// ドルストレートは0.010(100pips)、クロス円は1.0(100pips)で判定
   }
   else if (Symbol_RATE > 10 && Symbol_RATE <= 100)
   {
      Pips = 0.1;
   }
   else if (Symbol_RATE > 100 && Symbol_RATE <= 1000)
   {
      Pips = 1.0;
   }
   else if (Symbol_RATE > 1000 && Symbol_RATE <= 10000)
   {
      Pips = 10.0;
   }
   else if (Symbol_RATE > 10000 && Symbol_RATE <= 100000)
   {
      Pips = 100.0;
   }
   else if (Symbol_RATE > 100000 && Symbol_RATE <= 1000000)
   {
      Pips = 1000.0;
   }
   else if (Symbol_RATE > 1000000 && Symbol_RATE <= 10000000)
   {
      Pips = 10000.0;
   }
   else if (Symbol_RATE > 10000000 && Symbol_RATE <= 100000000)
   {
      Pips = 100000.0;
   }
   else if (Symbol_RATE > 100000000)
   {
      Pips = 1000000.0;
   }

 //■□■□■□■□■ 以下フィボナッチのロジック ■□■□■□■□■
   // 過去の高値と安値を取得
   double highestHigh = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, FibonacciLookBack, 0));
   double lowestLow = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, FibonacciLookBack, 0));
   
   // フィボナッチレベルを計算
   double fibonacciLevel = CalculateFibonacciLevel(highestHigh, lowestLow, FibonacciLevel);

   // RSIとボリンジャーバンドを計算
   double rsi = iRSI(NULL, 0, RsiPeriod, PRICE_CLOSE, 1);
   double upperBand = iBands(NULL, 0, BollingerBandsPeriod, BollingerBandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
   double lowerBand = iBands(NULL, 0, BollingerBandsPeriod, BollingerBandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
   currentPrice = Close[0];
if (pos > 0){//JPYを含む=USDJPY
 LongSign = false;
 ShortSign = false;
   // ロングサインの条件
   if (rsi <= 30 && currentPrice <= lowerBand && currentPrice >= fibonacciLevel)
   {
      LongSign = true;
      ShortSign = false;
   }
   // ショートサインの条件
   else if (rsi >= 70 && currentPrice >= upperBand && currentPrice <= fibonacciLevel)
   {
      ShortSign = true;
      LongSign = false;
   }
   else
   {
      LongSign = false;
      ShortSign = false;
   }

    //決済ロジックを有効
    if (CalculateCurrentOrders() == 1 && Kakusei == false) { // ロングポジション保有
        if (TimeCurrent() - LongPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseLongPosition(); // ロングポジションを決済
        }
    } else if (CalculateCurrentOrders() == -1 && Kakusei == false) { // ショートポジション保有
        if (TimeCurrent() - ShortPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseShortPosition(); // ショートポジションを決済
        }
    }
}

 //■□■□■□■□■ 以下グリッドラッシュのロジック ■□■□■□■□■
bool FilterCondition = true;  // フィルター条件の初期値をtrueに設定

        double adx = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
        if (adx > ADXThreshold) {
            FilterCondition = true; // 強いトレンド
        } else {
            FilterCondition = false; // トレンドが弱い
        }

// カギ足ロジックを生成する
    // 初回は基準の高値・安値を設定
if (lastBrickHigh == 0 && lastBrickLow == 0) {
    lastBrickHigh = currentPrice;
    lastBrickLow = currentPrice;
    return;  // 計算済みのバー数が0の場合に0を返す
}

 //■□■□■□■□■ サイン点灯レート判定 ■□■□■□■□■
 if ( pos <= 0 ) {// JPYを含まないドルストレート=EURUSD
 LongSign = false;
 ShortSign = false;
    // カギ足の生成条件チェック
    if (currentPrice >= lastBrickHigh + (GridSize * Pips) && Seconds() < 3 && FilterCondition == true) { 
        ShortSign = true;
        LongSign = false;
        lastBrickHigh = currentPrice;
        lastBrickLow = currentPrice - (GridSize * Pips);
    } else if (currentPrice <= lastBrickLow - (GridSize * Pips) && Seconds() < 3 && FilterCondition == true) {
        LongSign = true;
        ShortSign = false;
        lastBrickLow = currentPrice;
        lastBrickHigh = currentPrice + (GridSize * Pips);
    } else {
        LongSign = false;
        ShortSign = false;
    }
    //決済ロジックを有効
    if (CalculateCurrentOrders() == 1 && Kakusei == false) { // ロングポジション保有
        if (TimeCurrent() - LongPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseLongPosition(); // ロングポジションを決済
        }
    } else if (CalculateCurrentOrders() == -1 && Kakusei == false) { // ショートポジション保有
        if (TimeCurrent() - ShortPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseShortPosition(); // ショートポジションを決済
        }
    }
 }
//ここからver1.02
    // ■□■□■□■□■ Kakusei 覚醒モードの判定 ■□■□■□■□■
    if (Kakusei == true) {
        double totalProfit = 0;
        for (int i = 0; i < OrdersTotal(); i++) {
            if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
                if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
                    totalProfit += OrderProfit();
                }
            }
        }
        if (totalProfit < 0) { // 保有ポジションがマイナスの場合
            LongSign = false;
            ShortSign = false;
        }
    }
//ここまでver1.02

   if (MaxSpread < Info_Spread)
   {
      LongSign = false;
      ShortSign = false;
      spread_msg = "Max spread Orber\n";
   }
   else
   {
      spread_msg = "";
   }

   if (Hour() == 4 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (Hour() == 11 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (Hour() == 18 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (e > MaxError)
   {
      LongSign = false;
      ShortSign = false;
      error_msg = "Continuous order count limit\n";
   }
   else
   {
      error_msg = "";
   }
   if (LongSign == true)
   {
      position_msg = "LongSign = true\n";
   }
   else if (ShortSign == true)
   {
      position_msg = "ShortSign = true\n";
   }
   else if (LongSign == false && ShortSign == false)
   {
      position_msg = "No Sign\n";
   }


   // 売買指示
   if (LongSign == true)
   {
      if (CalculateCurrentOrders() == 0)
      {
         // ポジション保有していない場合
         CheckForOpenLong();// 新規ロングオーダー処理を行う
         LongPositionOpenTime = TimeCurrent(); // オープン時間を記録
         e++;
      }
      else
      {
         // ポジション保有している場合
         CloseShortPosition();// ショートポジションがある場合のみ決済ロング処理
      }
   }
   if (ShortSign == true)
   {
      if (CalculateCurrentOrders() == 0)
      {
         // ポジション保有していない場合
         CheckForOpenShort();// 新規ショートオーダー処理を行う
         ShortPositionOpenTime = TimeCurrent(); // オープン時間を記録
         e++;
      }
      else
      {
         // ポジション保有している場合
         CloseLongPosition();// ロングポジションがある場合のみ決済ショート処理
      }
   }
   if(pos>0){
   tmpstr = StringConcatenate("クロス円で判定\n",error_msg, spread_msg, position_msg);
   }else{
   tmpstr = StringConcatenate("ドルストレートで判定\n",error_msg, spread_msg, position_msg);
   }
   Comment(tmpstr);
}

// 保有中のポジションを計算
int CalculateCurrentOrders(void)
{
   int buys = 0;
   int sells = 0;
   int icount;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)
      {
         if (OrderType() == OP_BUY)
         {
            buys++;
         }
         if (OrderType() == OP_SELL)
         {
            sells++;
         }
      }
   }
   if (buys > 0)
   {
      return (buys);
   }
   else
   {
      return (-sells);
   }
}

// ショートポジション⇒ロングクローズ処理
void CloseShortPosition()
{
   int icount;
   bool ret;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol())
      {
         continue;
      }
      // ショートポジションの場合⇒ロングエントリー
      if (OrderType() == OP_SELL)
      {
         ret = OrderClose(
            OrderTicket(),
            OrderLots(),
            Ask,
            Adjusted_Slippage,
            clrBlue);
         if (ret == false)
         {
            Print("オーダークローズエラー:エラーコード=", GetLastError());
         }
         break;
      }
   }
}

// ロングポジション⇒ショートクローズ処理
void CloseLongPosition()
{
   int icount;
   bool ret;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol())
      {
         continue;
      }
      // ロングポジションの場合⇒ショートエントリー
      if (OrderType() == OP_BUY)
      {
         ret = OrderClose(
            OrderTicket(),
            OrderLots(),
            Bid,
            Adjusted_Slippage,
            clrRed);
         if (ret == false)
         {
            Print("オーダークローズエラー:エラーコード=", GetLastError());
         }
         break;
      }
   }
}

// ロングオーダー処理
void CheckForOpenLong()
{
   int res;
   double entrylot;
   entrylot = NormalizeDouble(Lots, 2);
    //ここからver1.02
    double stopLoss = Rikaku ? 0 : Ask - (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
    double takeProfit = Ask + (Pips * TakeProfitRequest);
    //ここまでver1.02
   res = OrderSend(
      Symbol(),
      OP_BUY,
      entrylot,
      Ask,
      Adjusted_Slippage,
      stopLoss,       // ストップロス設定
      takeProfit,     // リミット設定
      CommentPositions,
      Magic,
      0,
      clrRed);
   return;
}

// ショートオーダー処理
void CheckForOpenShort()
{
   int res;
   double entrylot;
   entrylot = NormalizeDouble(Lots, 2);
    //ここからver1.02
    double stopLoss = Rikaku ? 0 : Bid + (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
    double takeProfit = Bid - (Pips * TakeProfitRequest);
    //ここまでver1.02
   res = OrderSend(
      Symbol(),
      OP_SELL,
      entrylot,
      Bid,
      Adjusted_Slippage,
      stopLoss,        // ストップロス設定
      takeProfit,      // リミット設定
      CommentPositions,
      Magic,
      0,
      clrBlue);
   return;
}

このEAは含み損を抱えると塩漬け期間に突入します。
このまま不完全なEAを公開していたのでは、わたくしまさやんの名が汚れます。

本日は12月24日です。

皆様にクリスマスプレゼントとして、今回無料配布するEAに特別なカスタマイズを施したバージョン1.03も無料プレゼントします。

バージョン1.03でポジションを保有してから何分後に決済するか指定できるロジックを有効にしました。

やり方は簡単です。
EAのソースコードの
if (CalculateCurrentOrders() == 1 && Kakusei == false) { // ロングポジション保有
の部分の&& Kakusei == falseを削除するだけです。

全部で4か所あります。

この部分&& Kakusei == falseの部分を消すことで、ポジションの保有時間をコントロールできるようになります。

塩漬けになった時に、いちいち手動で決済するのではなく、最初から何分経過でポジションを決済するか設定できるという機能ですね。

実は、適当に時間を指定してポジションを決済するやり方は負けるやり方になります。

バージョン1.03でのバックテストでは、このように普通のEAになってしまいます。
分設定を1440分とした場合。※1日は1440分

どうですか?
負けるEAになってしまいました。
バージョン1.03は勝てないEAだと思います。

ちなみにドル円での注意事項です。
・利確モードをtrue
・覚醒モードをtrue

ドル円だと優位性が弱くなってしまい勝てません。
・利確モードをfalseにする
・覚醒モードをfalseにする
もしくはバージョン1.01をご利用ください。

ドル円5分足でのバックテスト(利確モードfalse 覚醒モードfalse)

ドル円でEAを動かす場合、パラメーターを調整するなどしていただければと思います。

【注意事項】
バージョン1.03の何分経過でポジションを決済する機能はMT4の再起動やEAの設定し直しでカウントがリセットされます。
10日後に決済するなどした場合、MT4を再起動すると、決済はされませんのでご注意ください。

バージョン1.03のEAのソースコードはこちら


//+------------------------------------------------------------------+
//|                                BinaryOption_USDJPY_EURUSD_M5.mq4 |
//|   ポジションを保有してから何分後に決済するか指定できるロジックを追加                   |
//|   バージョン1.02で利確モードと覚醒モード追加                                  |
//|   バージョン1.03でポジションを保有してから何分後に決済するか指定できるロジックを有効にしました  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Masayan."
#property version   "1.03"
#property strict
#property description "https://fx.reform-network.net"

extern int Magic = 20241126;// Magic number
extern double Lots = 0.1;//1.0=100000 0.1=10000 0.01=1000
extern double StopLossRequest = 1.0;// StopLoss 0.1=10pips 0.5=50pips 1=100pips
extern double TakeProfitRequest = 5.0;// TakeProfit 0.1=10pips 0.5=50pips 1=100pips
extern int PositionHoldMinutes = 1440; // ポジション保有後の決済時間(分)※1日は1440分
//ここからFibonacci Retracement USDJPY
extern int BollingerBandsPeriod = 30; // ボリンジャーバンドの期間「USDJPY」
extern int BollingerBandsDeviation = 2; // ボリンジャーバンドのシグマ値「USDJPY」
extern int FibonacciLookBack = 500; // フィボナッチリトレースメント計算のための過去の期間500か1000「USDJPY」
extern double FibonacciLevel = 0.5; // フィボナッチリトレースメントのレベル (例: 0.5 = 50%)「USDJPY」
int RsiPeriod = 14; // RSIの期間
//ここからGrid Rash EURUSD
extern double GridSize = 0.05;  // カギ足のサイズ(最小値0.01=1pips 推奨値0.05=5pips 最大値0.5=50pips)「EURUSD」
extern int ADXPeriod = 40;// ADXの計算期間(範囲10~150)「EURUSD」
extern double ADXThreshold = 15.0;// トレンドの強さを判断するための基準値(範囲5~50)(数字が小さいほどトレード回数が増える)「EURUSD」
double lastBrickHigh = 0;  // 前回のカギ足高値「EURUSD」
double lastBrickLow = 0;   // 前回のカギ足安値「EURUSD」
//ここまでGrid Rash EURUSD

//ここからver1.02
extern bool Rikaku = true;//利確モード追加=ストップ逆指値を無効にするtrue ストップロスを設定するfalse
extern bool Kakusei = true;//覚醒モード追加=損切りを行わず必ず利益確定でポジションを決済true 損切りするfalse
//ここまでver1.02
 
extern int MaxSpread = 50;// Max spread (50=5pips)
extern int MaxError = 100;// Continuous order count limit (Max=100)
extern string CommentPositions = "BinaryOption";

string tmpstr;
string error_msg;
string spread_msg;
string position_msg;
bool LongSign = false;
bool ShortSign = false;
double Pips = 0.01;
int e = 0;
int Adjusted_Slippage = 0;
datetime LongPositionOpenTime = 0; // ロングポジションのオープン時刻
datetime ShortPositionOpenTime = 0; // ショートポジションのオープン時刻

// フィボナッチリトレースメントを計算する関数
double CalculateFibonacciLevel(double high, double low, double level)
{
   return high - (high - low) * level;
}
// グリッドラッシュで使用
double currentPrice = iClose(NULL, 0, 0);
// ティックが動くごとに処理
void OnTick()
{
   if (Bars < FibonacciLookBack)
   {
      return;
   }

   if (StopLossRequest <= 0.01)
   {
      StopLossRequest = 0.01;
   }
   if (TakeProfitRequest <= 0.01)
   {
      TakeProfitRequest = 0.01;
   }
   if (MaxError >= 100)
   {
      MaxError = 100;
   }

   double Info_Spread = MarketInfo(Symbol(), MODE_SPREAD);
   string value = Symbol();
   string target = "JPY";
   int pos = StringFind(value, target);
   double Symbol_RATE = Close[1];
   if (pos > 0)
   {
      Pips = 1.00;// ドルストレートは0.010(100pips)、クロス円は1.0(100pips)で判定
   }
   else if (Symbol_RATE > 10 && Symbol_RATE <= 100)
   {
      Pips = 0.1;
   }
   else if (Symbol_RATE > 100 && Symbol_RATE <= 1000)
   {
      Pips = 1.0;
   }
   else if (Symbol_RATE > 1000 && Symbol_RATE <= 10000)
   {
      Pips = 10.0;
   }
   else if (Symbol_RATE > 10000 && Symbol_RATE <= 100000)
   {
      Pips = 100.0;
   }
   else if (Symbol_RATE > 100000 && Symbol_RATE <= 1000000)
   {
      Pips = 1000.0;
   }
   else if (Symbol_RATE > 1000000 && Symbol_RATE <= 10000000)
   {
      Pips = 10000.0;
   }
   else if (Symbol_RATE > 10000000 && Symbol_RATE <= 100000000)
   {
      Pips = 100000.0;
   }
   else if (Symbol_RATE > 100000000)
   {
      Pips = 1000000.0;
   }

 //■□■□■□■□■ 以下フィボナッチのロジック ■□■□■□■□■
   // 過去の高値と安値を取得
   double highestHigh = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, FibonacciLookBack, 0));
   double lowestLow = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, FibonacciLookBack, 0));
   
   // フィボナッチレベルを計算
   double fibonacciLevel = CalculateFibonacciLevel(highestHigh, lowestLow, FibonacciLevel);

   // RSIとボリンジャーバンドを計算
   double rsi = iRSI(NULL, 0, RsiPeriod, PRICE_CLOSE, 1);
   double upperBand = iBands(NULL, 0, BollingerBandsPeriod, BollingerBandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
   double lowerBand = iBands(NULL, 0, BollingerBandsPeriod, BollingerBandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
   currentPrice = Close[0];
if (pos > 0){//JPYを含む=USDJPY
 LongSign = false;
 ShortSign = false;
   // ロングサインの条件
   if (rsi <= 30 && currentPrice <= lowerBand && currentPrice >= fibonacciLevel)
   {
      LongSign = true;
      ShortSign = false;
   }
   // ショートサインの条件
   else if (rsi >= 70 && currentPrice >= upperBand && currentPrice <= fibonacciLevel)
   {
      ShortSign = true;
      LongSign = false;
   }
   else
   {
      LongSign = false;
      ShortSign = false;
   }

    //決済ロジックを有効
    if (CalculateCurrentOrders() == 1) { // ロングポジション保有
        if (TimeCurrent() - LongPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseLongPosition(); // ロングポジションを決済
        }
    } else if (CalculateCurrentOrders() == -1) { // ショートポジション保有
        if (TimeCurrent() - ShortPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseShortPosition(); // ショートポジションを決済
        }
    }
}

 //■□■□■□■□■ 以下グリッドラッシュのロジック ■□■□■□■□■
bool FilterCondition = true;  // フィルター条件の初期値をtrueに設定

        double adx = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
        if (adx > ADXThreshold) {
            FilterCondition = true; // 強いトレンド
        } else {
            FilterCondition = false; // トレンドが弱い
        }

// カギ足ロジックを生成する
    // 初回は基準の高値・安値を設定
if (lastBrickHigh == 0 && lastBrickLow == 0) {
    lastBrickHigh = currentPrice;
    lastBrickLow = currentPrice;
    return;  // 計算済みのバー数が0の場合に0を返す
}

 //■□■□■□■□■ サイン点灯レート判定 ■□■□■□■□■
 if ( pos <= 0 ) {// JPYを含まないドルストレート=EURUSD
 LongSign = false;
 ShortSign = false;
    // カギ足の生成条件チェック
    if (currentPrice >= lastBrickHigh + (GridSize * Pips) && Seconds() < 3 && FilterCondition == true) { 
        ShortSign = true;
        LongSign = false;
        lastBrickHigh = currentPrice;
        lastBrickLow = currentPrice - (GridSize * Pips);
    } else if (currentPrice <= lastBrickLow - (GridSize * Pips) && Seconds() < 3 && FilterCondition == true) {
        LongSign = true;
        ShortSign = false;
        lastBrickLow = currentPrice;
        lastBrickHigh = currentPrice + (GridSize * Pips);
    } else {
        LongSign = false;
        ShortSign = false;
    }
    //決済ロジックを有効
    if (CalculateCurrentOrders() == 1) { // ロングポジション保有
        if (TimeCurrent() - LongPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseLongPosition(); // ロングポジションを決済
        }
    } else if (CalculateCurrentOrders() == -1) { // ショートポジション保有
        if (TimeCurrent() - ShortPositionOpenTime >= PositionHoldMinutes * 60) {
            CloseShortPosition(); // ショートポジションを決済
        }
    }
 }
//ここからver1.02
    // ■□■□■□■□■ Kakusei 覚醒モードの判定 ■□■□■□■□■
    if (Kakusei == true) {
        double totalProfit = 0;
        for (int i = 0; i < OrdersTotal(); i++) {
            if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
                if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
                    totalProfit += OrderProfit();
                }
            }
        }
        if (totalProfit < 0) { // 保有ポジションがマイナスの場合
            LongSign = false;
            ShortSign = false;
        }
    }
//ここまでver1.02

   if (MaxSpread < Info_Spread)
   {
      LongSign = false;
      ShortSign = false;
      spread_msg = "Max spread Orber\n";
   }
   else
   {
      spread_msg = "";
   }

   if (Hour() == 4 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (Hour() == 11 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (Hour() == 18 && Minute() == 0 && Seconds() < 6)
   {
      e = 0;
   }
   if (e > MaxError)
   {
      LongSign = false;
      ShortSign = false;
      error_msg = "Continuous order count limit\n";
   }
   else
   {
      error_msg = "";
   }
   if (LongSign == true)
   {
      position_msg = "LongSign = true\n";
   }
   else if (ShortSign == true)
   {
      position_msg = "ShortSign = true\n";
   }
   else if (LongSign == false && ShortSign == false)
   {
      position_msg = "No Sign\n";
   }


   // 売買指示
   if (LongSign == true)
   {
      if (CalculateCurrentOrders() == 0)
      {
         // ポジション保有していない場合
         CheckForOpenLong();// 新規ロングオーダー処理を行う
         LongPositionOpenTime = TimeCurrent(); // オープン時間を記録
         e++;
      }
      else
      {
         // ポジション保有している場合
         CloseShortPosition();// ショートポジションがある場合のみ決済ロング処理
      }
   }
   if (ShortSign == true)
   {
      if (CalculateCurrentOrders() == 0)
      {
         // ポジション保有していない場合
         CheckForOpenShort();// 新規ショートオーダー処理を行う
         ShortPositionOpenTime = TimeCurrent(); // オープン時間を記録
         e++;
      }
      else
      {
         // ポジション保有している場合
         CloseLongPosition();// ロングポジションがある場合のみ決済ショート処理
      }
   }
   if(pos>0){
   tmpstr = StringConcatenate("クロス円で判定\n",error_msg, spread_msg, position_msg);
   }else{
   tmpstr = StringConcatenate("ドルストレートで判定\n",error_msg, spread_msg, position_msg);
   }
   Comment(tmpstr);
}

// 保有中のポジションを計算
int CalculateCurrentOrders(void)
{
   int buys = 0;
   int sells = 0;
   int icount;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)
      {
         if (OrderType() == OP_BUY)
         {
            buys++;
         }
         if (OrderType() == OP_SELL)
         {
            sells++;
         }
      }
   }
   if (buys > 0)
   {
      return (buys);
   }
   else
   {
      return (-sells);
   }
}

// ショートポジション⇒ロングクローズ処理
void CloseShortPosition()
{
   int icount;
   bool ret;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol())
      {
         continue;
      }
      // ショートポジションの場合⇒ロングエントリー
      if (OrderType() == OP_SELL)
      {
         ret = OrderClose(
            OrderTicket(),
            OrderLots(),
            Ask,
            Adjusted_Slippage,
            clrBlue);
         if (ret == false)
         {
            Print("オーダークローズエラー:エラーコード=", GetLastError());
         }
         break;
      }
   }
}

// ロングポジション⇒ショートクローズ処理
void CloseLongPosition()
{
   int icount;
   bool ret;
   for (icount = 0; icount < OrdersTotal(); icount++)
   {
      if (OrderSelect(icount, SELECT_BY_POS, MODE_TRADES) == false)
      {
         break;
      }
      if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol())
      {
         continue;
      }
      // ロングポジションの場合⇒ショートエントリー
      if (OrderType() == OP_BUY)
      {
         ret = OrderClose(
            OrderTicket(),
            OrderLots(),
            Bid,
            Adjusted_Slippage,
            clrRed);
         if (ret == false)
         {
            Print("オーダークローズエラー:エラーコード=", GetLastError());
         }
         break;
      }
   }
}

// ロングオーダー処理
void CheckForOpenLong()
{
   int res;
   double entrylot;
   entrylot = NormalizeDouble(Lots, 2);
    //ここからver1.02
    double stopLoss = Rikaku ? 0 : Ask - (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
    double takeProfit = Ask + (Pips * TakeProfitRequest);
    //ここまでver1.02
   res = OrderSend(
      Symbol(),
      OP_BUY,
      entrylot,
      Ask,
      Adjusted_Slippage,
      stopLoss,       // ストップロス設定
      takeProfit,     // リミット設定
      CommentPositions,
      Magic,
      0,
      clrRed);
   return;
}

// ショートオーダー処理
void CheckForOpenShort()
{
   int res;
   double entrylot;
   entrylot = NormalizeDouble(Lots, 2);
    //ここからver1.02
    double stopLoss = Rikaku ? 0 : Bid + (Pips * StopLossRequest); // Rikaku が true の場合ストップロスを 0 に設定
    double takeProfit = Bid - (Pips * TakeProfitRequest);
    //ここまでver1.02
   res = OrderSend(
      Symbol(),
      OP_SELL,
      entrylot,
      Bid,
      Adjusted_Slippage,
      stopLoss,        // ストップロス設定
      takeProfit,      // リミット設定
      CommentPositions,
      Magic,
      0,
      clrBlue);
   return;
}

【免責事項】
・本EAインジケーターについて、正当性を保証するものではありません。
・本EAインジケーターを利用して損失を被った場合でも一切の責任を負いません。
・投資の決定は、自己判断 自己責任でお願いします。


いいなと思ったら応援しよう!