見出し画像

【第2回】MQL4入門講座:ChatGPTでEAを作ろう!EAのロジックにテクニカル指標の売買フィルターを追加


ChatGPT担当のナナミです。

前回の動画では、MQL4入門講座としてEAのロジックの構築部分について解説しました。

本日は、前回作成したEA「Grid Rash」にテクニカル指標を用いた手法を追加して、成績が改善できるかやってみたいと思います。

この動画を見ることで、EA開発未経験の人でも簡単にEA開発できるようになりますので、最後まで動画のご視聴よろしくお願いします。

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

■ブログURL
https://fx.reform-network.net/2024/10/16/mt4初心者向け!gptsのmasayan-ea-generatorを使った自動売買講座/

■前回記事 MQL4入門講座:EAのロジックの構築部分について解説
https://note.com/aimjey/n/naff58e582299

それでは、EAのロジック部分にテクニカル指標の売買フィルターを追加してみようと思います。

私が開発したChatGPTのカスタムGPT「Masayan EA Generator for MT4」を使用すれば、テンプレートを使用した高性能なEAを作ることができます。

ロジックを日本語でChatGPTに伝えるだけで、ChatGPTがプログラミングしてくれるわけです。

すでに完成したEAが手元にあるならば、ChatGPTの新機能「ChatGPT 4o with canvas」を使用することで、部分的な修正を簡単に行うことが出来ます。

2024年10月現在、ChatGPTの無料アカウントでは、「ChatGPT 4o with canvas」を使用することができません。

https://chatgpt.com/?model=gpt-4o-canmore

上記のURLにアクセスして、このようなメッセージが表示された場合、有料にアップグレードしないと利用できません。

それでは、前回完成したEA「Grid Rash」に、売買フィルターを追加してみようと思います。

通常のEA開発では、手動でロジックを追加していくわけですが、ChatGPTを使えば何個でもロジックを追加することができます。

1つ作成して検証、そして次のEAを作成して検証というやり方でもいいのですが、そこは生成AI。

5個のロジックを追加して、プロパティ設定画面でフィルターを切り替えできるようにしたいと思います。

売買フィルターのロジックもChatGPTに考えてもらいましょう。

手法のアイデアをお持ちの方は、箇条書きにしてプロンプトを送信するといいです。

それでは、プロンプトを送信して、EAのカスタマイズを行いたいと思います。

以下のMT4のEAのコードに、売買フィルターを5つ追加してください。

追加するロジックは、トレンドフォローのロジック5つとします。

ロジックの切り替えができるように、プロパティ項目にどのフィルターを追加するか選べるようにしてください。

選べるフィルターは1個だけです。

同時に複数のフィルターを選択することはできません。

ChatGPT 4o with canvasで生成されたコードを見ると、5つの売買フィルターがサブルーチンとして作成されていることが分かります。

ソースコードをコピーしてコンパイルします。

エラーが出ました。

ダメです。

前回の動画でもお伝えした通り、ロジックの部分をサブルーチンとして関数にまとめるやり方は個人的に推奨していません。

インライン化(関数を使わない)するやり方でコーディングした方がいいです。

また、ChatGPT 4o with canvasは、「Masayan EA Generator for MT4」などのGPTsと違い、特別にチューニングされているわけではないので、特殊な処理を行う場合は、今のところGPTsを使用したほうがいいみたいです。

ブログ記事の作成や、Pythonなどのメジャーなプログラミング言語ならChatGPT 4o with canvasの方がいいと思います。

いずれMQL4のようなマイナー言語もChatGPTで完璧に処理できるようになるでしょう。

現在は思惑と異なる結果が出力されることがあっても、時間が解決してくれると思います。

というわけで、ChatGPT 4o with canvasは止めて「Masayan EA Generator for MT4」を使用して開発を続けます。

先ほどと同じプロンプトを送信します。

EAを完成させたら、フィルター番号1の移動平均から順番にテストします。

1は移動平均、2はボリンジャーバンド、3はマックディー、 4はRSI、5はADXです。

1の移動平均から5のADXまでテストしましたが、どれも成績はイマイチですね。

ちなみに5のADX(平均方向性指数)は、トレンドの強さを測定するためのテクニカル指標です。
トレンドの強さを判断するのに優れた指標であり、トレンドフォローのEAで使用します。

この結果を見て、皆さんはどのように思いますか?

実は、「Grid Rash」のように年間のトレード回数が数千回と極端にエントリー回数の多いEAに売買フィルターを追加すると、今回の様な結果が起こります。

ロジックの構築はEA開発において最も重要な部分となりますので、経験がものを言います。

ChatGPTは手法のアイデアは出してくれますが、その手法が相場で通用するとは限りません。

「Grid Rash」のようなフンスキャEAは、テクニカル指標でフィルターをかけるよりも、ローソク足の値動きによるプライスアクション手法を取り入れた方が、好成績を叩き出せるかもしれません。

というわけで、次回の動画では今回カスタマイズしたGrid Rashを、MT4のバックテストの機能にある最適化機能を使い、最適なパラメータ値を探してみたいと思います。

その後の作業として、ローソク足によるプライスアクション手法をロジックに組み込んでみます。

最後に決済ロジックの追加ですね。

いずれの作業もEA開発未経験の人には難しい作業となりますが、ChatGPTをフル活用して付いてきていただければと思います。

今回完成したEAのソースコードです。


//---START--------
#property copyright "Copyright 2024, Masayan."
#property version   "1.01"
#property strict
#property description "https://fx.reform-network.net"

extern int Magic = 20240615;  // Magic number
extern double Lots = 0.1;     // ロットサイズ
extern double StopLossRequest = 4.0;   // ストップロス幅
extern double TakeProfitRequest = 5.0; // テイクプロフィット幅
extern int MaxSpread = 50;     // 最大スプレッド
extern int MaxError = 100;     // 最大エラーカウント
extern double GridSize = 0.05;  // カギ足のサイズ(最小値0.01=1pips 推奨値0.05=5pips)
extern string CommentPositions = "Grid Rash Ver2";

extern int FilterType = 0; // 0:フィルターなし, 1:移動平均, 2:ボリンジャーバンド, 3:MACD, 4:RSI, 5:ADX
extern int ShortMAPeriod = 20;
extern int LongMAPeriod = 50;
extern int BBPeriod = 20;
extern double BBDeviation = 2.0;
extern int MACDFastPeriod = 12;
extern int MACDSlowPeriod = 26;
extern int MACDSignalPeriod = 9;
extern int RSIPeriod = 14;
extern double RSIUpper = 70.0;
extern double RSILower = 30.0;
extern int ADXPeriod = 14;
extern double ADXThreshold = 25.0;

//ここから改変可能
double lastBrickHigh = 0;  // 前回のカギ足高値
double lastBrickLow = 0;   // 前回のカギ足安値
//ここまで改変可能

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;

    double currentPrice = iClose(NULL, 0, 0);
    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){
Pips = 1000.0;
}

bool FilterCondition = true;  // フィルター条件の初期値をtrueに設定

switch (FilterType) {
    case 1: // 移動平均線フィルター
    {
        double shortMA = iMA(NULL, 0, ShortMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
        double longMA = iMA(NULL, 0, LongMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
        if (shortMA > longMA) {
            FilterCondition = true; // 上昇トレンド
        } else if (shortMA < longMA) {
            FilterCondition = false; // 下降トレンド
        }
        break;
    }
    case 2: // ボリンジャーバンドフィルター
    {
        double upperBand = iBands(NULL, 0, BBPeriod, BBDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
        double lowerBand = iBands(NULL, 0, BBPeriod, BBDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
        if (currentPrice > upperBand) {
            FilterCondition = false; // 高値圏
        } else if (currentPrice < lowerBand) {
            FilterCondition = true; // 安値圏
        }
        break;
    }
    case 3: // MACDフィルター
    {
        double macd = iMACD(NULL, 0, MACDFastPeriod, MACDSlowPeriod, MACDSignalPeriod, PRICE_CLOSE, MODE_MAIN, 1);
        double signal = iMACD(NULL, 0, MACDFastPeriod, MACDSlowPeriod, MACDSignalPeriod, PRICE_CLOSE, MODE_SIGNAL, 1);
        if (macd > signal) {
            FilterCondition = true; // 上昇トレンド
        } else if (macd < signal) {
            FilterCondition = false; // 下降トレンド
        }
        break;
    }
    case 4: // RSIフィルター
    {
        double rsi = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 1);
        if (rsi > RSIUpper) {
            FilterCondition = false; // 過熱圏
        } else if (rsi < RSILower) {
            FilterCondition = true; // 買いシグナル
        }
        break;
    }
    case 5: // ADXフィルター
    {
        double adx = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
        if (adx > ADXThreshold) {
            FilterCondition = true; // 強いトレンド
        } else {
            FilterCondition = false; // トレンドが弱い
        }
        break;
    }
    default: // フィルターなし
        FilterCondition = true;
        break;
}

// カギ足ロジックを生成する

    // 初回は基準の高値・安値を設定
    if (lastBrickHigh == 0 && lastBrickLow == 0) {
        lastBrickHigh = currentPrice;
        lastBrickLow = currentPrice;
        return;
    }

    // カギ足の生成条件チェック
    if (currentPrice >= lastBrickHigh + (GridSize * Pips) && Seconds() < 3 && FilterCondition) { 
        ShortSign = true;
        LongSign = false;
        lastBrickHigh = currentPrice;
        lastBrickLow = currentPrice - (GridSize * Pips);
    } else if (currentPrice <= lastBrickLow - (GridSize * Pips) && Seconds() < 3 && FilterCondition) {
        LongSign = true;
        ShortSign = false;
        lastBrickLow = currentPrice;
        lastBrickHigh = currentPrice + (GridSize * Pips);
    } 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) position_msg = "LongSign = true\n";
    else if (ShortSign) position_msg = "ShortSign = true\n";
    else position_msg = "No Sign\n";

    // 売買指示
    if (LongSign) {
        if (CalculateCurrentOrders() == 0) {
            CheckForOpenLong();
            e++;
        } else {
            CloseShortPosition();
        }
    }

    if (ShortSign) {
        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;
    for (int icount = 0; icount < OrdersTotal(); icount++) {
        if (!OrderSelect(icount, SELECT_BY_POS, MODE_TRADES)) break;
        if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic) {
            if (OrderType() == OP_BUY) buys++;
            if (OrderType() == OP_SELL) sells++;
        }
    }
    return (buys > 0) ? buys : -sells;
}

//+------------------------------------------------------------------+
//| ロングオーダー処理                                               |
//+------------------------------------------------------------------+
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; // 関数処理終了
}

// ショートポジションをクローズ
void CloseShortPosition()
{
    for (int icount = 0; icount < OrdersTotal(); icount++) {
        if (!OrderSelect(icount, SELECT_BY_POS, MODE_TRADES)) break;
        if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol()) continue;
        if (OrderType() == OP_SELL) {
            if (!OrderClose(OrderTicket(), OrderLots(), Ask, Adjusted_Slippage, clrBlue)) 
                Print("エラーコード=", GetLastError());
            break;
        }
    }
}

// ロングポジションをクローズ
void CloseLongPosition()
{
    for (int icount = 0; icount < OrdersTotal(); icount++) {
        if (!OrderSelect(icount, SELECT_BY_POS, MODE_TRADES)) break;
        if (OrderMagicNumber() != Magic || OrderSymbol() != Symbol()) continue;
        if (OrderType() == OP_BUY) {
            if (!OrderClose(OrderTicket(), OrderLots(), Bid, Adjusted_Slippage, clrRed)) 
                Print("エラーコード=", GetLastError());
            break;
        }
    }
}
//---END---

EA開発に自信のある方は、ロジックのところを変更するなどしてカスタマイズしてみてください。

好成績のEAが完成した際には、コメント頂けると幸いです。

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

いいなと思ったら応援しよう!