見出し画像

スキャルピング手法にCCIを組み込み⇒分スキャEAを作成してみた【勝てるロジックのEA化】


ChatGPT担当のナナミです。

前回の動画では、テクニカル指標のCCIを使用してドル円1分足チャートで動作する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/nd2340c0fa7b5

本日は、前回作成したCCIのロジックを使い、ドル円5分足チャートで動くスキャルのEAを作成してみたいと思います。

CCIオシレーター系テクニカル指標

果たしてCCIで勝てるスキャルピングEAは作れるのでしょうか?

はじめに、CCIで使用するパラメータ値を見てみましょう。

ジョルノ式トレードでは、CCIを2本使用していました。

なのでわたしもCCIを2本使うやり方でEAを作ってみます。

前回の動画で見つけた、最適なパラメータ値は以下の通りです。

CCIPeriod1 = 14;
CCIPeriod2 = 12;
CCILong = -150;
CCIShort = 150;

次に、CCIを組み込みする、元になるEAのロジックを考えてみましょう。

デイトレEAのロジックが候補になりますが、まずは移動平均線を3本使用したパーフェクトオーダーのロジックにCCIを組み込んでみたいと思います。

まずは、移動平均線の値を決めないといけません。
最初に他のEAで使用していた移動平均線の期間でバックテストをまわしてみます。

MAPeriod1 = 10;
MAPeriod2 = 30;
MAPeriod3 = 75;

5分足チャートで2007年1月2日から2024年6月30日で、TDSによる全ティックバックテストの結果はこうなりました。

2007年1月2日から2024年6月30日

結果は、イマイチですね。

MT4の最適化機能を使用して理想的な移動平均線の期間を探してみました。


MT4の最適化機能

一番利益の出てた設定はこちらです。

MAPeriod1 = 20;
MAPeriod2 = 40;
MAPeriod3 = 80;

TDSによる全ティックバックテストをまわしてみます。


TDSによる全ティックバックテスト


ダメです。
これは、使い物になりません。

次に相性の良さそうなロジックはZigZagになります。
ZigZagのEAは、過去動画で紹介しております。


ZigZagのEA

noteの過去記事リンクよりZigZagのEAのソースコードがダウンロードできます。
https://note.com/aimjey/n/na1b686739f9c

ダウ理論とZigZagを組み合わせたトレード手法のEAになりますが、ダウ理論のところをCCIに置き換えれば良さそうです。

ちなみに、ZigZagで使用するパラメータは、以下の通りです。

Depth→高値と安値を拾う期間で数字を上げるとトレード回数が減る。
Deviation→転換率で、数字を上げるとトレード回数が減る。
Backstep→現在と過去のレートを比較する期間で、数字を上げるとトレード回数が減る。

Depthの値を大きくすると、バックテストの時間が大幅に増えるので、Depthは12で固定とします。
また、DeviationやBackstepも、初期値をそのまま使用します。

完成したコードで5分足チャートでバックテストをまわしてみましたが、勝てないEAになってしまいました。

そこで、ZigZagにプラスしてパーフェクトオーダーのロジックを追加してみました。

上昇トレンドの時は、ロングのポジションを、下落トレンドの時はショートのポジションを取ります。
これでトレンド方向にのみエントリーするようになりましたが、これではパーフェクトオーダーのロジックの成績とほとんど同じになってしまいます。
トレード回数も少なく、通常のスイング系のEAになってしまいました。

試しに、1分足チャートでバックテストをまわしてみます。
トレード回数は増えましたが、ロジックに優位性がありません。
負けるEAに仕上がってしまいました。

最後に、一目均衡表を使用したロジックにCCIを組み込んでみたいと思います。
実は、この動画を撮るにあたり、10時間くらい試行錯誤を繰り返しました。
その中で、一番うまくいったテクニカル指標が一目均衡表です。

ロジックとしては、現在レートが雲の上にある時はロングのポジションを持って、雲の下にある時はショートのポジションを持ちます。
雲の上と下を頻繁に行ったり来たりすると、トレード回数は増える傾向にあります。

IchimokuTenkan = 9; // 転換線の期間
IchimokuKijun = 26; // 基準線の期間
IchimokuSenkou = 52; // 先行スパンの期間

上記の設定でバックテストをまわしてみます。

始値のみ、5分足チャートはまずまずの成績です。

次に、TDSによる全ティックバックテストをまわしてみます。

今までで一番成績は良いのですが、もう少し改善できそうです。


TDSによる全ティックバックテスト

基準線の期間を26から36に変更してみます。

IchimokuTenkan = 9; // 転換線の期間
IchimokuKijun = 26→36; // 基準線の期間
IchimokuSenkou = 52; // 先行スパンの期間

この設定でTDSによる全ティックバックテストをまわしてみます。


全ティックバックテスト

どうでしょう?
先ほどよりも成績が改善されましたね。

トレード回数もそこそこ多いので、スキャルの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 IchimokuTenkan = 9;  // 転換線の期間
extern int IchimokuKijun = 36;  // 基準線の期間
extern int IchimokuSenkou = 52; // 先行スパンの期間
extern int CCIPeriod1 = 14;
extern int CCIPeriod2 = 12;
extern double CCILong = -150;
extern double CCIShort = 150;
//ここまで改変可能

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;
    }

//ここから改変可能
bool ShortSignMh = false;
bool LongSignMh = false;
    double SenkouSpanA = iIchimoku(NULL, 0, IchimokuTenkan, IchimokuKijun, IchimokuSenkou, MODE_SENKOUSPANA, 0);
    double SenkouSpanB = iIchimoku(NULL, 0, IchimokuTenkan, IchimokuKijun, IchimokuSenkou, MODE_SENKOUSPANB, 0);
    double ClosePrice = Close[0];
   double CCI1 = iCCI(NULL, 0, CCIPeriod1, PRICE_CLOSE, 0);
   double CCI2 = iCCI(NULL, 0, CCIPeriod2, PRICE_CLOSE, 0);
    if (ClosePrice > SenkouSpanA && ClosePrice > SenkouSpanB)
    {
        LongSignMh = true;
        ShortSignMh = false;
    }
    else if (ClosePrice < SenkouSpanA && ClosePrice < SenkouSpanB)
    {
        ShortSignMh = true;
        LongSignMh = false;
    }
    else
    {
        LongSign = false;
        ShortSign = false;
    }
    if (CCI1 < CCILong && CCI2 < CCILong && LongSignMh == true )
    {
        LongSign = true;
        ShortSign = false;
    }
    else if (CCI1 > CCIShort && CCI2 > CCIShort && ShortSignMh == true)
    {
        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ではこの程度が限界のようです。

みなさんも是非、Masayan EA Generator for MT4を使って優秀なEAを作成してくださいね。

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


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

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