見出し画像

【GMMA移動平均線編】FXテクニカル手法をChatGPTでEA化する【ノーコードEA開発】

本記事のYouTube動画を視聴する

https://youtu.be/QuLHvz7AzXQ


ChatGPT担当のナナミです。

新連載「テクニカル指標を使ってEA開発してみた」というタイトルで、連載企画を行っていきます。

本日使用するテクニカル指標は、移動平均線です。
ノーコードEA開発は、ChatGPTを使用します。

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

■ブログURL
https://fx.reform-network.net/2024/06/11/gpts「masayan-ea-generator-for-mt4-」条件を指定するだけで高性能なeaを生/

わたくしまさやんは、移動平均線を用いたEAでは無料EAが1個と有料EAが2個の開発経験があります。

Trail Master Free(無料EA)
https://note.com/aimjey/n/n1b26042fb1e6

GoldenCross USDJPY(有料EA)
https://www.gogojungle.co.jp/systemtrade/fx/43098

PerfectOrder GBPJPY(有料EA)
https://www.gogojungle.co.jp/systemtrade/fx/30753

Trail Master Freeは移動平均線1本とローソク足で売買判断し、GoldenCrossは移動平均線2本、PerfectOrderは移動平均線を3本使用します。

成績は、PerfectOrderが一番良く、移動平均線を1本だけ使用するTrail Master Freeが一番成績が悪いです。

移動平均線の数を増やせば成績が良くなるのでは?との疑問から、今回12本の移動平均線を使用するテクニカル指標、GMMA(複合型移動平均線)のEAを開発してみたいと思います。


GMMA(複合型移動平均線)

GMMAとは、指数平滑移動平均線(EMA)を一度に12本チャートに表示して、トレンドの方向性を判断するテクニカル指標です。
指数平滑移動平均線(EMA)と単純移動平均線(SMA)の違いは、直近の価格に対する比重の大きさで、EMAは直近の価格に比重を置いて計算されます。

つまり、単純移動平均線(SMA)は指定した期間の値を単純に平均化した値となり、指数平滑移動平均線(EMA)は過去のレートよりも最近のレートに重点を置く移動平均線になります。

皆さんはSMAとEMA、どっちが勝てると思いますか?

じつはこの答え、わたしは知っています。
過去のEA開発の経験から、SMAの方が優れていると知っています。
今回、SMAとEMAそれぞれ12本の移動平均線を使用してEAを作成、成績を比べてみたいと思います。
果たして、どちらが好成績を叩き出すのでしょうか?楽しみですね。

まず、無料のGPTsのMasayan EA Generator for MT4に簡単なプロンプトを送信します。

1.短期線6本と長期線6本の合計12本の単純移動平均線(SMA)を使用してEAを作成してとプロンプトを送信


生成されたEAでのバックテスト結果は以下の通りです。
2013年~2023年始値のみ プロフィットファクター1.18
2007年~2023年全ティック プロフィットファクター1.19
パラメータ値は以下の通りです。

ShortMovingPeriod1=10
ShortMovingPeriod2=15
ShortMovingPeriod3=20
ShortMovingPeriod4=25
ShortMovingPeriod5=30
ShortMovingPeriod6=40
LongMovingPeriod1=45
LongMovingPeriod2=45
LongMovingPeriod3=50
LongMovingPeriod4=55
LongMovingPeriod5=60
LongMovingPeriod6=95
■noteでソースコードをコピー

//+------------------------------------------------------------------+
//|                                    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 ShortMovingPeriod1 = 10;
extern int ShortMovingPeriod2 = 15;
extern int ShortMovingPeriod3 = 20;
extern int ShortMovingPeriod4 = 25;
extern int ShortMovingPeriod5 = 30;
extern int ShortMovingPeriod6 = 40;
extern int LongMovingPeriod1 = 45;
extern int LongMovingPeriod2 = 45;
extern int LongMovingPeriod3 = 50;
extern int LongMovingPeriod4 = 55;
extern int LongMovingPeriod5 = 60;
extern int LongMovingPeriod6 = 95;
//ここまで改変可能

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 shortMAs[6];
   shortMAs[0] = iMA(NULL, 0, ShortMovingPeriod1, 0, MODE_SMA, PRICE_CLOSE, 0);
   shortMAs[1] = iMA(NULL, 0, ShortMovingPeriod2, 0, MODE_SMA, PRICE_CLOSE, 0);
   shortMAs[2] = iMA(NULL, 0, ShortMovingPeriod3, 0, MODE_SMA, PRICE_CLOSE, 0);
   shortMAs[3] = iMA(NULL, 0, ShortMovingPeriod4, 0, MODE_SMA, PRICE_CLOSE, 0);
   shortMAs[4] = iMA(NULL, 0, ShortMovingPeriod5, 0, MODE_SMA, PRICE_CLOSE, 0);
   shortMAs[5] = iMA(NULL, 0, ShortMovingPeriod6, 0, MODE_SMA, PRICE_CLOSE, 0);

   double longMAs[6];
   longMAs[0] = iMA(NULL, 0, LongMovingPeriod1, 0, MODE_SMA, PRICE_CLOSE, 0);
   longMAs[1] = iMA(NULL, 0, LongMovingPeriod2, 0, MODE_SMA, PRICE_CLOSE, 0);
   longMAs[2] = iMA(NULL, 0, LongMovingPeriod3, 0, MODE_SMA, PRICE_CLOSE, 0);
   longMAs[3] = iMA(NULL, 0, LongMovingPeriod4, 0, MODE_SMA, PRICE_CLOSE, 0);
   longMAs[4] = iMA(NULL, 0, LongMovingPeriod5, 0, MODE_SMA, PRICE_CLOSE, 0);
   longMAs[5] = iMA(NULL, 0, LongMovingPeriod6, 0, MODE_SMA, PRICE_CLOSE, 0);

   bool longCondition = true;
   bool shortCondition = true;

   for(int i = 0; i < 6; i++)
     {
      if(shortMAs[i] <= longMAs[i])
        {
         longCondition = false;
        }
      if(shortMAs[i] >= longMAs[i])
        {
         shortCondition = false;
        }
     }

   if(longCondition)
     {
      LongSign = true;
      ShortSign = false;
     }
   else if(shortCondition)
     {
      ShortSign = true;
      LongSign = false;
     }
   else
     {
      LongSign = false;
      ShortSign = 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;
  }
単純移動平均線SMAのバックテスト

2.短期線6本と長期線6本の合計12本の指数平滑移動平均線(EMA)を使用してEAを作成してとプロンプトを送信。

生成されたEAでのバックテスト結果は以下の通りです。
2013年~2023年始値のみ プロフィットファクター1.19
2007年~2023年全ティック プロフィットファクター1.13
パラメータ値は以下の通りです。

ShortEMAPeriods1=5
ShortEMAPeriods2=10
ShortEMAPeriods3=15
ShortEMAPeriods4=20
ShortEMAPeriods5=25
ShortEMAPeriods6=30
LongEMAPeriods1=50
LongEMAPeriods2=55
LongEMAPeriods3=60
LongEMAPeriods4=65
LongEMAPeriods5=70
LongEMAPeriods6=115


指数平滑移動平均線EMAのバックテスト

そして今回開発したEAのパフォーマンスはPerfectOrder GBPJPYのドル円バージョンに匹敵するパフォーマンスを叩き出すことに成功しました。

有料版パーフェクトオーダーのドル円バージョン

流石に本家のGBPJPYのパフォーマンスには達していませんが、パラメータ値を変えることで本家のGBPJPYと同等の成績が得られるかもしれません。
次回の動画では、一目均衡表を用いたEA開発を行います。

また、連載企画として、以下のテクニカル指標のEA開発を予定しております。

  1. 一目均衡表

  2. ボリンジャーバンド

  3. MACD

  4. RSI

  5. ストキャスティクス

  6. フィボナッチリトレースメント

  7. ZigZag


MT4のEA開発に役に立つ記事を配信しています。
他にも、こんな手法EAにしてほしいみたいなリクエストがあれば、Xにコメントお願いします。


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

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