見出し画像

【ZigZagとダウ理論編】FXテクニカル手法をChatGPTでEA化する【ノーコードEA開発】

この記事の内容をYouTube動画で視聴する

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/06/11/gpts「masayan-ea-generator-for-mt4-」条件を指定するだけで高性能なeaを生/

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

本日使用するテクニカル指標は、ZigZagとダウ理論です。

ZigZagとダウ理論は似ているテクニカル指標であることから、セットで使われることがあります。
ZigZagを用いたインジケーターやEAはネットで簡単に拾えるので、EA化は簡単です。
しかしながら、ダウ理論を用いたEAは数が少なくEA化が難しいとされます。

本日のEA開発の手順は以下の通りです。

最初にZigZag単体のEAを作ります。

ZigZag

次に、ダウ理論単体でEAを作ります。

ダウ理論

最後に、この2つをあわせたマルチロジックのEAを作ります。

EAを作る前に、ZigZagとダウ理論の関係性について説明します。

ZigZagは、短期的なトレンドの動きを分析したり、エントリーポイントや利食いポイントを探すのに適しています。

ダウ理論は長期的なトレンド方向を把握するのに適しています。

ダウ理論とZigZagを組み合わせたトレード手法としては、ダウ理論で長期的なトレンド方向を判断し、ZigZagでエントリーポイントを見極めます。

こうすることで、長期トレンドでは順張り方向にトレードすることができるので、トレンドに逆らわない王道ともいえるトレードが可能になります。
果たしてこれらの手法で長期的に勝つEAを作ることは可能なのでしょうか?

まず、Masayan EA Generator for MT4にZigZagのEAを作成してとプロンプトを送信します。

実は、ChatGPTには学習機能というのがあり、皆さんが打ち込んだプロンプトを元に回答の精度が向上するような仕様になっています。
つまり、毎回必ず同じコードが生成されるということはなく、同じプロンプトでもたまに違った回答が表示されることがあります。

今回のテーマ、ZigZagやダウ理論に関しては、十分に学習がされていないせいか、かなり不安定な回答となりました。

まず、最初に生成されたコードをコンパイルすると、
'CopyBuffer' - function not defined
というエラーが出たのでChatGPTに修正を依頼しました。

ChatGPTから、以下のような回答がありました。

CopyBufferはMQL5の関数であり、MQL4では使用できません。MQL4でZigZagインディケーターを使用する場合は、iCustom関数を使用してバッファからデータを取得します。
iCustom関数を使用してZigZagインディケーターを取得し、CopyBufferを使用せずに直接バッファを読み取ります。これにより、MQL4で適切に動作するようになります。

修正プログラムをコンパイルしたところ、今後は
'CopyBuffer' - function not defined
というエラーが出たので、再度修正を依頼します。

すると今度は2つの警告が出ました。
possible loss of data due to type conversion
declaration of 'value' hides local variable

警告の場合、エラーと違ってEAは動くので、このままバックテストを取ることにします。

バックテストの期間は2013年1月から2024年6月とします。

始値のみの1時間足チャートではそれなりの結果が出たので、全ティックバックテストをまわしてみます。

全ティックバックテスト


ダメです、負けるEAです。

今度は、MT4に標準で備わっているZigZagインジケーターをEAにしてとChatGPTに依頼してみます。

やり方は簡単です。ZigZagのインジケーターのソースコードをそのままコピペで貼り付けします。

ZigZagのインジケーターのソースコード

インジケーターをEA化するプロンプトは初めての試みですが、果たしてうまくいくのでしょうか?

生成されたコードをコンパイルしたところ、エラーは出ませんでした。

しかしながら、バックテストをまわしてみたところ、やはり勝てないEAに仕上がりました。

実は、ZigZag手法は勝てないと多くのEAトレーダーが証明しています。
勝てるロジックはEA化され、ゴゴジャンなどで販売されます。
ZigZag手法を使用したEAでフォワード成績が良く、売れているEAは確認できません。

移動平均を用いたトレンドフォロー型のEAや、ゴトー日EA、朝スキャEAなど、勝てるロジックはEA化され世に出回ります。
つまり、ZigZagのEAがゴゴジャンの売れ筋ランキングに載らないということは、EA開発者がZigZagを使用した勝てるEAが作れていないか、完成させたとしてもフォワード成績が悪く使い物にならないかのいずれかです。

というわけで、ZigZag手法を使用したEA開発は諦めます。

続けて、ダウ理論を用いたEAを作りたいと思います。

ダウ理論のEAを作成してとプロンプトを送信します。

完成したEAでバックテストをまわしてみましたが、強烈なエラーが発生し、EAが強制終了してしまいました。

ダウ理論単体でのEA開発は難航しそうな気配なので、諦めて次に進みます。

最後に、ダウ理論とZigZagを組み合わせたトレード手法のEAを作成します。

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

ダウ理論で長期的なトレンド方向を判断し、ZigZagでエントリーポイントを見極めます。
こうすることで、長期トレンドでは順張り方向にトレードすることができるので、トレンドに逆らわない王道ともいえるトレードが可能になります。

ダウ理論では、高値および安値が切り上がっている状態を上昇トレンドとし、反対に高値安値が下に切り下げる状態を「下落トレンド」とします。

完成したコードを見てみましょう。

なぜかダウ理論の部分が移動平均線に置き換わっています。

//+------------------------------------------------------------------+
//|                                    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 ZigZagDepth = 12;
extern int ZigZagDeviation = 5;
extern int ZigZagBackstep = 3;
extern int TrendPeriod = 100;
//ここまで改変可能

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 trendMA = iMA(NULL, 0, TrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
    double lastZigZag = iCustom(NULL, 0, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, 1);

    if (Close[0] > trendMA && lastZigZag < Close[0])
    {
        LongSign = true;
        ShortSign = false;
    }
    else if (Close[0] < trendMA && lastZigZag > Close[0])
    {
        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;
}

今回作成したEAでは、ダウ理論ではなく移動平均線によるトレンド判断となっていることから、ロジック的には移動平均線とZigZagを使用したEAが正確な表現になると思います。

ひとまず、完成したEAでバックテストをまわしてみましょう。
始値のみでスプレッドを0.2pipsでバックテストします。
5分足、15分足、1時間足、4時間足とバックテストしたところ、15分足が一番成績が良いようです。
スプレッドを10ポイントつまり、1pipsにしてバックテストをまわしたとことプラスになることを確認できたので、TDSによる変動スプレッドで全ティックバックテストをまわしてみます。

結果はご覧のように、微妙な成績になりました。

TDSによる変動スプレッドで全ティックバックテスト


上記は、2013年1月から2024年6月までのバックテスト結果です。

EA開発者の目線で言わせてもらえば、このEAは移動平均線を用いたトレンドフォローの優位性のみで勝っているEAになります。
ZigZagを使用したことで成績が上がったとは言えず、単純にゴールデンクロスでロングデッドクロスでショートのEAの方がシンプルで分かり易いです。
ZigZagを使用したEAで勝てるEAは少ないことからも分かるように、単純にトレンドフォローのEAを作成した方が勝てると思います。

残念なことに、ダウ理論のロジックをすべて取り入れたEAというのは、現在のChatGPTをもってしても開発は容易ではなく、また開発に成功したからといって、すごく勝てるとも言えないです。
ダウ理論自体がトレンド判断に重点を置いている手法であることから、トレンド判断という意味においては、やはり移動平均線を用いたトレンド判断の方が分かり易いと思います。

ダウ理論に精通しているトレーダー様は、ぜひ、ダウ理論の詳細をプロンプトに打ち込み、EAを完成して頂けると、このGPTsを作った甲斐があります。

素晴らしいEAが開発できたなら、Xのコメントでシェアして頂けると幸いです。

次回は新連載として「勝てるロジックのEA化」というテーマで動画を撮っていこうと思います。


勝てるロジックのEA化

「勝てるロジックのEA化」とは、ネットなどで公開されている勝てると言われる手法「グランビルの法則」「エリオット波動」「ジョルノ式トレード」などの手法をMasayan EA Generator for MT4を使ってEAにしていく。
そんな感じでやっていきますので、応援よろしくお願いします。

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

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