見出し画像

Williams%Rを使用したスキャルピングEAを作成してみた【あなたの考えたFX手法をEAにする】


ChatGPT担当のナナミです。

前回の動画では、Williams%Rを使用したEAの開発を行いました。

完成したEAのプロフィットファクターは1.10と、リアル運用するには少し物足りない気がします。

前回作成したEAのバックテスト結果

そこで、前回完成したEAのロジックのうち、Williams%RとRSIはそのままに、以下のテクニカル指標を追加して、スキャルのEAを作成してみたいと思います。

1、ボリンジャーバンド
2、パラボリック
3、ストキャスティクス
4、MACD
5、一目均衡表
6、移動平均線
7、ZigZag

もちろん、完成したEAは無料で配布するので、チャンネル登録とグッドボタンの評価忘れずにお願いしますね。

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

■ブログURL
https://fx.reform-network.net/2024/08/29/新シリーズ「あなたの考えたfx手法をeaにする」/

■前回記事(Williams%Rにどのテクニカル指標を追加したら勝てるのか検証してみた)
https://note.com/aimjey/n/n7acc5a9c5576

まず、ベースとなるボリンジャーバンドを追加したEAのコードをテンプレートとして使用し、Masayan EA Generator for MT4に変更する内容を送信します。

面倒なプログラミングをChatGPTにやってもらうことで、EA開発時間を大幅に短縮できます。

ただし、生成されたコードにはバグ・不具合が含まれることがあります。

コードを解析するのに時間がかかるので細かな修正は行わず、手当たり次第にバックテストを行い、成績が良かったものだけをカスタマイズするようにします。

完成したEAはこのページの下の方にありますので、ダウンロードしてご利用ください。

■ボリンジャーバンドフィルターの箇所をパラボリックを用いた手法に書き変えてとプロンプトを送信したものになります。
ロングサインの条件:
SARが現在の価格の下に位置している場合ロングサイン。

ショートサインの条件:
SARが現在の価格の上に位置している場合ショートサイン。

■ストキャスティクス
ロングサインの条件:
%Kが20以下のときに、%Kが%Dを上抜けた場合にロングサイン。

ショートサインの条件:
%Kが80以上のときに、%Kが%Dを下抜けた場合にショートサイン。

■MACD(マックディー)
ロングサインの条件:
メインラインがシグナルラインを上抜けた場合にロング。

ショートサインの条件:
メインラインがシグナルラインを下抜けた場合にショート。

■一目均衡表
ロングサインの条件:
転換線が基準線を上抜け、かつ現在の価格が先行スパンAおよび先行スパンBの上に位置している場合、ロングサイン。

ショートサインの条件:
転換線が基準線を下抜け、かつ現在の価格が先行スパンAおよび先行スパンBの下に位置している場合、ショートサイン。

■移動平均線はゴールデンクロスでロング、デッドクロスでショート。

■ZigZag手法
ZigZagのピークより価格が低い時はロング、ZigZagのボトムより価格が高い時はショートです。

■ボリンジャーバンド
ロジックはボリバンにタッチで逆張りエントリーですね。
ロングとショートを入れ替えれば簡単に順張りに変更できます。

それでは順番にバックテストを取っていこうと思います。

スプレッドを5ポイント(0.5pips)でのバックテストのプロフィットファクターをまとめたものです。

1分足チャートではトレード回数が多すぎてスプレッド負けする傾向にあります。

かろうじてボリンジャーバンドだけが1分足と5分足でプラスになっています。

成績の良さそうなEAをMT4の最適化機能を使いベストなパラメータ値を探していきます。

作業をすること2時間、結局ボリンジャーバンドを用いた手法が一番良い成績になりました。

スキャルピングEAとして動かしたいので、1分足チャートにカーブフィッティングさせました。

と、ここで、RSIの買われ過ぎ判定をデフォルトの70と85でバックテストした時に、ある奇妙な現象に気付きました。

RSIの値を85にした時に、始値のみでバックテストすると高いプロフィットファクターだったのに、全ティックでバックテストをまわすと、勝てないEAになりました。

EAを作っていると始値のみのバックテストだと成績が良くて、全ティックでバックテストをまわすと成績が悪化することがあります。

この場合、ローソク足が確定した最初のテックだけ売買するとか、Seconds()という秒を取得する関数を使って発注のタイミングを制御します。

今回は、始値のみの発注のイメージに近付ける為、秒で管理するように修正しました。

//バーが確定してから最初の3秒だけトレードする。
if (Seconds() > 3){
LongSign = false;
ShortSign = false;
}

以上のコードを追加することで、Secondsが4秒~59秒の時は強制的にサインをニュートラルにすることで発注を行わずに済みます。

本日完成したEAの詳細はこちらです。

・Williams%Rが-50以下の場合はロングシグナルで-50以上の時はショートシグナル。
・ボリンジャーバンド-4シグマ以下の時は逆張りでロング、+4シグマ以上の時は逆張りでショート。
・RSIが40以下で売られすぎの時はロングサイン、買われ過ぎの時は逆張りでショート。

RSIが70で買われ過ぎのスキャルピングモードのプロフィットファクターは1.05です。

RSIが85で買われ過ぎの通常モードのプロフィットファクターは1.07です。

こちらの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 = 20240911;// 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 10=1000pips
extern double TakeProfitRequest = 5.0;// TakeProfit 0.5=50pips 10=1000pips
extern int MaxSpread = 50;// Max spread (50=5pips)
extern int MaxError = 100;// Continuous order count limit (Max=100)
extern string CommentPositions = "BollingerFilter";
extern bool OnlyWilliams = false; // Williams%Rだけで売買判定 true 他のテクニカル指標を追加して判定 false
extern double OverboughtLevel = -50.0; // Williams%R -50以下の場合⇒ロングシグナル、それ以上⇒ショートシグナル
extern int WilliamsPeriod = 14;        // Williams%Rの期間(デフォルト14)

double OversoldLevel = -70.0;   // Williams%R 売られすぎの閾値(未使用)

extern bool UseBollingerFilter = true;//BollingerBandsフィルター
extern int BollingerBandsPeriod = 38; // ボリンジャーバンドの期間(変更可)
extern int BollingerBandsDeviation = 4; // ボリンジャーバンドのシグマ値(目安3~4)

extern bool UseRSIFilter = true;// RSIフィルター
extern int RSIPeriod = 28;;//RSIの期間 デフォルト14
extern double RSIOverbought = 85.0;// RSI 買われすぎの閾値スキャルピングは70推奨
extern double RSIOversold = 40.0;// RSI 売られすぎの閾値

string tmpstr;
string error_msg;
string spread_msg;
string position_msg;
bool LongSignMh = false;
bool ShortSignMh = false;
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;
     }

// フィルタの判定
   LongSign = false;
   ShortSign = false;
   LongSignMh = false;
   ShortSignMh = false;

   double WilliamsR = iWPR(NULL, 0, WilliamsPeriod, 1); // Williams%Rの値を取得

   if(WilliamsR < OverboughtLevel)  // Williams%Rが-50以下の場合、ロングシグナル
     {
      LongSignMh = true;
     }
   else  // Williams%Rが-50以上の場合、ショートシグナル
     {
      ShortSignMh = true;
     }

/*
   double WilliamsR = iWPR(NULL, 0, WilliamsPeriod, 1); // Williams%Rの値を取得
   if(WilliamsR < OverboughtLevel)  // Williams%Rが-10以下の場合、ロングシグナル
     {
      LongSignMh = true;
     }
   else if(WilliamsR > OversoldLevel)  // Williams%Rが-70以上の場合、ショートシグナル
     {
      ShortSignMh = true;
     }
*/
   // ボリンジャーバンドフィルター
if(UseBollingerFilter)
 {
   // ボリンジャーバンドを計算
   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);
   double currentPrice = Close[0];
   if (currentPrice <= lowerBand && LongSignMh == true)
   {
      LongSign = true;
      ShortSign = false;
   }
   // ショートサインの条件
   else if (currentPrice >= upperBand && ShortSignMh == true)
   {
      ShortSign = true;
      LongSign = false;
   }
   else
   {
      LongSign = false;
      ShortSign = false;
   }
 }

   // RSIフィルタ
         double rsi = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 1);
   if(UseRSIFilter){
      if(rsi <= RSIOversold && LongSignMh == true) // ロングシグナル逆張りロング
        {
         LongSign = true;
         ShortSign = false;
        }
      else if(rsi >= RSIOverbought && ShortSignMh == true) // ショートシグナル逆張りショート
        {
         ShortSign = true;
         LongSign = false;
        }
     }else{
         LongSign = false;
         ShortSign = false;
     }

// Williams%Rのみで判定
 if(OnlyWilliams == true){
 LongSign = false;
 ShortSign = false;
   if(LongSignMh == true)  // Williams%Rのみで判定 ロングシグナル
     {
      LongSign = true;
     }
   else if(ShortSignMh == true)  // Williams%Rのみで判定 ショートシグナル
     {
      ShortSign = true;
     }
 }

//バーが確定してから最初の3秒だけトレードする。(始値のみのイメージに近いトレード)
if (Seconds() > 3){
 LongSign = false;
 ShortSign = false;
}

// ここまでフィルタの判定
/*
//決済ロジックを追加する場合
if(CalculateCurrentOrders() == 1){// ロングポジション保有
    if(ShortSignMh = true){//Williams%Rが-30以上の場合
CloseLongPosition();// ロングポジションを決済
    }
} else if(CalculateCurrentOrders() == -1){// ショートポジション保有
    if(LongSignMh = true){//Williams%Rが-70以下の場合
CloseShortPosition();// ショートポジションを決済
    }
}
*/
   if(MaxSpread < Info_Spread)
     {
      LongSign = false;
      ShortSign = false;
      spread_msg = "Max spread exceeded\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
     {
      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;
  }

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


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

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