見出し画像

【エリオット波動編】FX手法をChatGPTでEA化する【勝てるロジックのEA化】

https://youtu.be/Z0mH6amrFFg

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/nb9f5ae13c1cf

本日は、「エリオット波動」を使用したシングルロジックのEAを作成します。


エリオット波動

また、エリオット波動の弱点を補うべく、フィボナッチ・リトレースメントと、ZigZagのロジックを追加したマルチロジックEAも開発します。

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


ZigZag

「エリオット波動」と「フィボナッチ・リトレースメント」の両方を使用することで、互いの弱点を補完し合うことが出来ます。

これらの2つの手法を使って勝てるEAが作れるのでしょうか?

まず、エリオット波動の基本形についてお話しします。

エリオット波動の基本形は「推進5波と修正3波」の形です。

例えば上昇トレンドの時は、上昇が5波で形成され、その後の下降が3波で形成されます。

上下に押し目や戻りをつけながら上昇トレンドを作ります。

また、エリオット波動には以下の3つの基本原則があります。

  1. 推進波の第1、3、5波の中で第3波が最も短くなることはない。

  2. 推進波の第2波が第1波を超えて安値をつけることはない。

  3. 推進波の第4波が第1波の高値を下回ることはない。

このルールに沿ったトレードを行うことで、勝てると言われます。

しかしながら、一見万能に思えるエリオット波動ですが、EA化に際し致命的な弱点があります。

それは、理論通りに波が形成されるとは限らないことです。

波動の基本ルールが崩れた時はどうするのか?

このルールを確立させる目的で併用するテクニカル指標がフィボナッチ・リトレースメントです。

エリオット波動単体ではうまく分析できない相場でも、フィボナッチ・リトレースメントを併用することでスムーズなトレードが可能となります。

ちなみにフィボナッチ・リトレースメントは、高値と安値に線を引き何%くらいで押し目や戻りをつけるのかを把握するテクニカル指標です。

エリオット波動の基本ルールが崩れた時は、フィボナッチ・リトレースメントのトレード条件に応じてトレードを継続することが可能となります。

つまり、この2つのテクニカル指標をセットで使用することで、あらゆる相場に対応できるEAが作れるのです。

それではエリオット波動のEAを作りましょう。

最初にエリオット波動のEAを作成してとシンプルなプロンプトを送信してみます。

次に、以下のように、エリオット波動の詳細な情報を送信してみます。

エリオット波動の基本形は「推進5波と修正3波」の形です。

上昇トレンドの時は、上昇が5波で形成され、その後の下降が3波で形成されます。

また、エリオット波動には以下の3つの基本原則があります。

推進波の第1、3、5波の中で第3波が最も短くなることはない。
推進波の第2波が第1波を超えて安値をつけることはない。
推進波の第4波が第1波の高値を下回ることはない。

条件を細かく指定することで、より細かな制御を可能とします。

完成したコードでバックテストを回してみましたが、トレード回数が少ないようです。

どうやら、一部の波の時にしかトレードしていないみたいです。

全部の波でエントリーするロジックに変更してとChatGPTに修正を依頼します。

完成したコードでバックテストを回してみたところ、4時間足が一番成績が良いみたいです。


4時間足 エリオット波動単体

ここで注目すべき点は買いポジション勝率が62.50パーセントと非常に勝率が高いことです。

買いのみエントリーすれば勝てるのでは?と期待してしまいますね。

それでは、次に、フィボナッチ・リトレースメントとの融合によるマルチロジック化にチャレンジしたいと思います。

フィボナッチ・リトレースメントのロジックを追加して、マルチロジックのEAにしてください。とプロンプトを送信します。

完成したコードでバックテストを回してみます。

期間は2013年1月から2024年6月までです。


マルチロジックEA

成績はイマイチですね。

試しにポンド円やユーロドルなどの通貨ペアでもバックテストしましたが、成績はイマイチでした。

次に、最初に作成したエリオット波動単体のEAをロングのみエントリーするように修正を行いたいと思います。

やり方は簡単です。

先ほど作成したEAのソースコードの上部に、以下のEAをロングのみエントリーするようにしてくださいと書いてプロンプトを送信します。

バックテスト結果を見てみましょう。


ショートをエントリーしない(ロングのみエントリー)

なんということでしょう。

勝率は60%以上あるのに、勝てていません。

理由はリスクリワード比が悪化し、損大利小のEAになってしまったからです。

他に勝てない理由を考えてみましょう。

今回作成したEAは、4時間足チャートで上昇と下降を判断しましたが、本来ならZigZagのEAを使う方がいいと思います。

そこで、ZigZagのロジックを使用してエリオット波動のEAを完成させようと思います。

ZigZagのコードは以前作ったEAのコードを使用しました。

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

つまり、ZigZagの山と谷をエリオット波動の波としてとらえるのです。

これにより、15分足チャートなどできちんと波動の波をとらえることが出来るはずです。

それでは、2013年1月から2024年6月までの期間で、TDSによる全ティックバックテストを回してみましょう。


完成したEAのバックテスト結果

一応プラスにはなりましたが、このままでは使えないEAですね。

ですが、トレード頻度が高くスキャルEAのベースとして使えそうな気がします。

今度本格的にチューニングを施し、使えるEAに仕上げてみたいと思います。


今回作成したEAはかなりの高難易度でした。
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 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 zigzagCurrent = iCustom(NULL, 0, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, 0);
    double zigzagPrevious = iCustom(NULL, 0, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, 1);

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

エリオット波動の波のロジックの構築が難しく、ChatGPTをもってしてもプログラミングは容易ではありません。

以前作成したZigZagのロジックを使用することで、何とか完成することが出来ました。

今回のような複雑なロジックはEA化が難しく、きちんとプロンプトを送信しないとまったく違ったEAに仕上がってしまいます。

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

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

次回は「ジョルノ式トレード」を使用したEAの開発を行いたいと思います。

ジョルノ式トレードは高勝率のトレード手法として最近話題になっている手法です。

ジョルノ式トレードのような複雑なロジックでも、ChatGPTを使えばノーコードでEAを開発することができます。

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

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

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