見出し画像

ジョルノ式トレードをドル円1分足チャートに最適化してみた【勝てるロジックのEA化】


ChatGPT担当のナナミです。

前回の動画では、ジョルノ式トレードを使用したゴールドEAを開発しました。

GPTsのリンクはこちら(GPT Store)
https://chatgpt.com/g/g-VYNEupgws-masayan-ea-generator-for-mt4-ver1-01

■ブログURL
https://fx.reform-network.net/2024/07/23/【新連載】fx手法をchatgptでea化する【勝てるロジックの/

■前回記事
https://note.com/aimjey/n/n13cd7a15af8c

本日は、前回作成したジョルノ式トレードで使用したCCIというテクニカル指標を使い、ドル円1分足チャートで勝てるEAを作成してみたいと思います。

ジョルノ式トレードとは、カリスマ投資家のジョルノ氏が開発した手法で、CCIというテクニカル指標を用いて2020年にGOLDで16億円稼いだとされる手法です。

今回、テクニカル指標のCCIを使用し、ドル円の1分足チャートで動くスキャルEAを作成したいと思います。

果たしてCCIで勝てるEAは作れるのでしょうか?

まずはじめに、CCIで使用するパラメータ値を決めたいと思います。

ジョルノ式トレードでは、CCIを2本使用していましたが、最初は1本だけ使うやり方で試してみます。

CCIの期間ですが、最適な値をバックテストから探しました。

エントリー条件となるCCIの値も、バックテストから最適な値を探します。

次に、CCI単独では売買判断が出来ないので、レンジブレイクの手法を採用した「Fast Scalping EA」という有料のEAのロジックに組み込んでみたいと思います。

Fast Scalping EA

https://www.gogojungle.co.jp/systemtrade/fx/48825
Fast Scalping EAは、マルチタイムフレーム分析を用いたEAで、ゴゴジャンで販売中のEAになります。

さすがに有料で販売しているEAのソースコードを公開するわけにはいきませんので、そのかわりに、無料版のパーフェクトオーダーのロジックに組み込みしたコードをnotoの記事リンクに載せました。

まず、Fast Scalping EAのプロパティ項目にCCIのパラメーターを追加します。


EAにCCIのロジックを組み込む

次に、ショートの発動条件のところに、CCI1 > CCIShort 、ロングの発動条件のところに、CCI1 < CCILongとします。

ShortSignMh == trueとか、LongSignMh == trueとかは、マルチタイムフレーム分析のトレンド判定になります。

長期のトレンドの方向に逆らわずにエントリーしたいので、この様なロジックにしました。

Fast Scalping EAは、マルチタイムフレーム分析により、日足週足のトレンドを判断し、トレードする方向性を決めています。


CCIについて少し説明をします。

Commodity Channel Index


CCIとは、コモディティー・チャネル・インデックス(Commodity Channel Index)の略で、「売られ過ぎ」や「買われ過ぎ」を判断するオシレーター系のテクニカル指標です。

ゴールドや原油などのコモディティ相場で使用するテクニカル指標ということですね。

次に、MT4の最適化設定を用いて、一番成績の良いパラメータ値を探してみましょう。

一番成績の良い設定は、
CCIの期間が10。
ロングの条件は-50以下、
ショートの条件は50以上でした。

完成したEAでバックテストをまわしたところ、プロフィットファクターは
1.20で、
利益は12451ドルでした。

CCIが役に立っていない感じがします。
CCIによる判定の部分を消してみましょう。
プロフィットファクターは
1.18で、
利益は13587ドルでした。
プロフィットファクターは下がりましたが、トレード回数は増えたので、利益は増えました。

CCIを使用しても、パフォーマンスは改善していないことが分かります。

ちなみに、
Fast Scalping EAのプロフィットファクターは
1.26で、
利益は13720ドルでした。

Fast Scalping EA TDSによる全ティックバックテスト

さすがに有料だけあって安定した成績ですね。

CCI単独での成績も気になりますよね。
というわけで、CCI単独でのバックテストをまわしてみることにします。

最適なパラメータ値は以下の通りです。
CCIPeriod1 = 14;
CCIPeriod2 = 12;
CCILong = -150;
CCIShort = 150;

トレードする時間帯は、サーバー時間の7:00から17:59までです。
始値のみのバックテストでスプレッドが2ポイント、つまり0.2pipsだと勝てているように思えます。


始値のみのバックテスト

ですが、TDSによる全ティックバックテストで、実際のトレードに近い条件でバックテストすると、このように勝てないEAになります。


TDSによる全ティックバックテスト

CCIは単独で使用しても勝てないことが分かりました。

最後に、Masayan EA Generator for MT4で作成したパーフェクトオーダーのEAにCCIを組み込んでみましょう。

送信するプロンプトは以下の通りです。

パーフェクトオーダーのロジックにCCIによる逆張りのロジックを追加して。

パーフェクトオーダーで大まかなトレンドを判断し、CCIで逆張りエントリーします。

CCIの値は以下の通りです。

CCIPeriod1 = 14;
CCIPeriod2 = 12;
CCILong = -150;
CCIShort = 150;
if (CCI1 > CCIShort && CCI2 > CCIShort){ ShortSign = true; //trueの時にショートサイン発動 }else if (CCI1 < CCILong && CCI2 < CCILong){ LongSign = true; //trueの時にロングサイン発動 }

完成したEAのコードはこちらです。

//+------------------------------------------------------------------+
//|                                    Masayan EA Generator_1.01.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Masayan."
#property version   "1.01"
#property strict
#property description "https://fx.reform-network.net"

extern int Magic = 20240610;// Magic number
extern double Lots = 0.1;//1.0=100000 0.1=10000 0.01=1000
extern double StopLossRequest = 4.0;// StopLoss 0.5=50pips 1.0=100pips 10=1000pips
extern double TakeProfitRequest = 5.0;// TakeProfit 0.5=50pips 1.0=100pips 10=1000pips
extern int MaxSpread = 50;// Max spread (50=5pips)
extern int MaxError = 100;// Continuous order count limit (Max=100)
extern string CommentPositions = "Masayan EA Generator";

//ここから改変可能
extern int ShortMovingPeriod = 300;
extern int MiddleMovingPeriod = 1125;
extern int LongMovingPeriod = 1500;

extern int CCIPeriod1 = 14;
extern int CCIPeriod2 = 12;
extern double CCILong = -150;
extern double CCIShort = 150;
//ここまで改変可能

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;

// ティックが動くごとに処理
void OnTick()
  {
   if(Bars < 10)
     {
      return;
     }

   if(StopLossRequest <= 0.1)
     {
      StopLossRequest = 0.1;
     }
   if(TakeProfitRequest <= 0.1)
     {
      TakeProfitRequest = 0.1;
     }
   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 shortMA = iMA(NULL, 0, ShortMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
   double middleMA = iMA(NULL, 0, MiddleMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
   double longMA = iMA(NULL, 0, LongMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);

   double CCI1 = iCCI(NULL, 0, CCIPeriod1, PRICE_CLOSE, 0);
   double CCI2 = iCCI(NULL, 0, CCIPeriod2, PRICE_CLOSE, 0);

   // パーフェクトオーダーの条件を満たしているか確認
   bool isPerfectOrderUp = shortMA > middleMA && middleMA > longMA;
   bool isPerfectOrderDown = shortMA < middleMA && middleMA < longMA;

   // CCI逆張りロジックを適用
   if(isPerfectOrderUp && CCI1 < CCILong && CCI2 < CCILong)
     {
      LongSign = true;
      ShortSign = false;
     }
   else if(isPerfectOrderDown && CCI1 > CCIShort && CCI2 > CCIShort)
     {
      ShortSign = true;
      LongSign = false;
     }
//ここまで改変可能

   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();// 新規ロングオーダー処理を行う
         e ++;
        }
      else
        {
         // ポジション保有している場合
         CloseShortPosition();// ショートポジションがある場合のみ決済ロング処理
        }
     }
   if(ShortSign == true)
     {
      if(CalculateCurrentOrders() == 0)
        {
         // ポジション保有していない場合
         CheckForOpenShort();// 新規ショートオーダー処理を行う
         e ++;
        }
      else
        {
         // ポジション保有している場合
         CloseLongPosition();// ロングポジションがある場合のみ決済ショート処理
        }
     }

   tmpstr = StringConcatenate(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);
   res = OrderSend(
            Symbol(),
            OP_BUY,
            entrylot,
            Ask,
            Adjusted_Slippage,
            Ask - (Pips * StopLossRequest),
            Ask + (Pips * TakeProfitRequest),
            CommentPositions,
            Magic,
            0,
            clrRed);
   return;
  }

//ショートオーダー処理
void CheckForOpenShort()
  {
   int    res;
   double entrylot;
   entrylot = NormalizeDouble(Lots, 2);
   res = OrderSend(
            Symbol(),
            OP_SELL,
            entrylot,
            Bid,
            Adjusted_Slippage,
            Bid + (Pips * StopLossRequest),
            Bid - (Pips * TakeProfitRequest),
            CommentPositions,
            Magic,
            0,
            clrBlue);
   return;
  }

パーフェクトオーダーとCCIのマルチロジックEAの成績です。

パーフェクトオーダーとCCIのマルチロジックEA


プロフィットファクターは
1.16です。
利益は11584ドルでした。

次に、パーフェクトオーダーのみのバックテスト結果です


パーフェクトオーダーのみ


パーフェクトオーダーのみのプロフィットファクターは
1.16です。
利益は11708ドルでした。


ほとんど同じですね。
パーフェクトオーダーのロジックにCCIによる逆張りのスキャルピング手法を追加し、マルチロジック化してはみたものの、
スキャルのロジックはスイング系のロジックと組み合わせても、意味が無いことがわかりました。

本日のまとめです。
今回作成したCCIによるスキャルピングEAは、トレード回数が非常に多く、1時間に数回エントリーします。
トレード回数が多く分スキャとしては申し分ないのですが、リアルトレードでは、スプレットやスリッページが発生することから、勝てないことが分かりました。

ですが、今回作成したCCIによるスキャルピング手法は、他のスキャルピング手法と組み合わせることで、勝てる分スキャEAに大化けする可能性があります。

わたしの経験上、年間のトレード回数が1000回を超えるあたりから、スプレッド負けしやすくなります。

仮に1日に10回以上トレードするEAの場合、年間のトレード回数は2500回になります。

年間2500回トレードするEAは、年間で250回トレードするEAの10倍もスプレッドコストを支払うことになります。

仮に、1回のトレードで1pipのスプレッドコストを支払ったとすれば、年250回トレードで250pipsの負担、年2500回のトレードだと、実に2500pipsもスプレッドコストを支払っていることになります。

どうですか?

高頻度トレードで勝つことがいかに難しいかおわかりいただけたでしょうか?

次回の動画では、「スキャルピング手法にCCIを組み合わせて分スキャEAを作成してみた」というタイトルで動画を撮っていこうと思います。

他にも、こんな手法EAにしてほしいみたいなリクエストがあれば、コメントお願いします。


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

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