EAでZigZagを使う(サンプルソース)

EA
スポンサーリンク

FXで売買タイミングとして使うジグザグ(ZigZag)の、簡単なMT4のEAサンプルです。

概要

ZigZagは、MACD等のようにiMACD関数のような物がないのでiCustomで取得するかつ、とってくるだけでは若干使いづらいという感じで少しだけ面倒です。

今回、以下の記事では順張り目線で高値切り上げ、又は安値更新でエントリーしていく(ダウ理論系の)サンプルを載せています。

エントリータイミング

ロングエントリー

高値の切り上げ、安値の切り上げ中の、ZigZagの最新の底値が確定した後にロングしています。

ショートエントリー

高値切り下げ、安値切り下げ中の、ZigZagの最新の高値が確定した後にショートしています。

イメージ図

ZigZagの性質上、デメリットが発生する事があります。

決済タイミング

指値、逆指値共に20pipsに設定しています。

その他の仕様

設定値は以下の通りです。

  1. E_Depth = 12 ⇒ ZigZagの「Depth」設定です。
  2. E_Deviation = 5 ⇒ ZigZagの「Deviation」設定です。
  3. E_Backstep = 3 ⇒ ZigZagの「Backstep」設定です。
  4. A_SPREAD = 20 ⇒ エントリー時に許容するスプレッドの値です(20 = 2pips)
  5. Lots = 0.01 ⇒ ロット数です(0.01=1000通貨)
  6. STOP_LOSS = 200 ⇒ 損切り幅
  7. TP = 200 ⇒ 利確幅

既にポジションがある場合は追加でエントリーしません。

新しい足(バー)が出来た際に1度だけ処理を行います。※1時間足の場合だと1時間に1回処理する

ZigZagの設定値及び、エントリー時の指値、逆指値はパラメータ設定できます。

EAレポート結果

ZigZag結果
※サンプルEAの作り上、始値のみの確認となっています

2005年~2020年の期間の15分足でバックテスト確認してみました。ZigZagのDepth値がデフォルトの12だとそこまで若干のプラスにしかならなかったので、16に変えるといい感じのプラスになりました。結構粗削りなEAなので調整すればもっと良くなりそうです。

ダウンロード

上記のEAファイルになります。

“ZIGZAG-EA” をダウンロード

11_ZigZag.ex4 – 3208 回のダウンロード – 14.41 KB

以下サンプルソースコードになります。

ソースコード

//+------------------------------------------------------------------+
//|                                                ZigZag_Sample.mq4 |
//|                                    Copyright 2020, mef Software. |
//|                                             https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, mef Software."
#property link      "https://fx-prog.com/"
#property version   "1.00"
         
input int E_Depth = 12;
input int E_Deviation = 5;
input int E_Backstep = 3;
  
input int A_SPREAD = 120;
input double Lots = 0.01;
      
input int STOP_LOSS = 200;
input int TP = 200;
      
      
double ZigTop[5];     //ジグザグの山保存用
double ZigBottom[5];  //ジグザグの谷保存用
int TopPoint;
int BottomPoint;
      
  
datetime prevtime;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//---
             
//---
   return(INIT_SUCCEEDED);
  }
          
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
int start()
{
int orderPtn=0; //0:何もしない 1:買い 2:売り
int total=0;
          
double ea_order_stop_price=0,ea_order_good_price=0; //ストップロスレート,利確レート,エントリーレート
bool OrderKekka;
         
//---
   //新しい足ができた時だけやる
   if(Time[0] != prevtime){
      prevtime = Time[0];
   }else{
      return(0);
   }
          
//***売買判断箇所***//
         
   //チェック用変数の初期化
   TopPoint=0;
   BottomPoint=0;   
      
   //ZigZagの高値安値を構造体に再セット
   getZigZag(1);
      
      
   //高値切り上げ安値切り上げでロング
   if(ZigTop[0] > ZigTop[1] && ZigTop[1] > ZigTop[2] && 
      ZigBottom[0] > ZigBottom[1] && ZigBottom[1] > ZigBottom[2] && BottomPoint==1)
   {
      orderPtn=1;
   }
   //高値切り下げ安値切り下げでショート 
   else if(ZigTop[0] < ZigTop[1] && ZigTop[1] < ZigTop[2] &&
      ZigBottom[0] < ZigBottom[1] && ZigBottom[1] < ZigBottom[2] && TopPoint==1)
   {
      orderPtn=2;
   }
   else
   {
      orderPtn=0;
   }
      
//***売買判断箇所***//
          
      
//***決済判断箇所***//
   total=OrdersTotal();
   if(total ==0 && orderPtn > 0)   
   {
      if(orderPtn == 1)
      {
         ea_order_stop_price = Ask - STOP_LOSS * Point;
         ea_order_good_price = Ask + TP * Point;          
      }
      else if(orderPtn == 2)
      {
         ea_order_stop_price = Bid + STOP_LOSS * Point;  
         ea_order_good_price = Bid - TP * Point;  
      }   
         
      //新規注文
      OrderKekka = funcOrder_Send(orderPtn - 1,ea_order_stop_price,ea_order_good_price,0,0);
         
   }
            
   return(0);
}
         
//+------------------------------------------------------------------+
//|【関数】新規注文関数                                                 |
//|                                                                  |
//|【引数】 ea_order_entry_Type:売買(0:買 1:売)                         |
//|【引数】 ea_order_stop_price:損切値  ea_order_good_price:利確値      |
//|【引数】 orderComment:オーダーコメント    ea_order_MagicNo:マジックNo       |
//|                                                                  |
//|【戻値】True:成功                                                   |
//|                                                                  |
//| 
bool funcOrder_Send(int ea_order_entry_Type, double ea_order_stop_price, double ea_order_good_price,int orderComment,int ea_order_MagicNo)
{
           
   int order_resend_num;        // エントリー試行回数
   int ea_ticket_res;           // チケットNo
   int errorcode;               // エラーコード
   double ea_order_entry_price; // エントリーレート
   color order_Color;
   bool kekka;
              
   for( order_resend_num = 0; order_resend_num < 10; order_resend_num++ ) {    // エントリー試行回数上限:10回
           
      if(MarketInfo(NULL,MODE_SPREAD) < A_SPREAD ){
           
         if(ea_order_entry_Type == OP_BUY){   
            ea_order_entry_price = Ask;               // 現在の買値でエントリー
            order_Color = clrBlue;
            Print(Ask+"でロングするよ!");            
         }else if(ea_order_entry_Type == OP_SELL){        
            ea_order_entry_price = Bid;               // 現在の売値でエントリー
            order_Color = clrRed;
            Print(Bid+"でショートするよ!");                       
         }
           
         // FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
         ea_ticket_res = OrderSend(   // 新規エントリー注文
            NULL,                 // 通貨ペア
            ea_order_entry_Type,      // オーダータイプ[OP_BUY / OP_SELL]
            Lots ,                    // ロット[0.01単位](FXTFは1=10Lot)
            ea_order_entry_price,     // オーダープライスレート
            20,                       // スリップ上限    (int)[分解能 0.1pips]
            ea_order_stop_price,      // ストップレート
            ea_order_good_price,      // リミットレート
            orderComment,             // オーダーコメント
            ea_order_MagicNo,         // マジックナンバー(識別用)
            0,                        // オーダーリミット時間
            order_Color               // オーダーアイコンカラー
            );
  
         Print("結果:"+ea_ticket_res);
  
         if ( ea_ticket_res == -1) {            // オーダーエラー
            errorcode = GetLastError();      // エラーコード取得
              
            if( errorcode != ERR_NO_ERROR) { // エラー発生
               printf("エラー:"+ IntegerToString(errorcode));
            }
              
            Sleep(2000);                                           // 1000msec待ち
            RefreshRates();                                        // レート更新
              
            printf("再エントリー要求回数:%d, 更新エントリーレート:%g",order_resend_num+1 ,ea_order_entry_price);
              
         } else {    // 注文約定
            Print("新規注文約定。 チケットNo=",ea_ticket_res," レート:",ea_order_entry_price);
            Sleep(300);                                           // 300msec待ち(オーダー要求頻度が多過ぎるとエラーになる為)
                          
            break;
         }
  
              
              
      }else{
         Print("スプレッドNG 許容スプレッド:"+A_SPREAD+"pips未満 環境スプレッド:"+MarketInfo(NULL,MODE_SPREAD)+"pips");
         Sleep(2000);                                           // 2000msec待ち
         RefreshRates();     
      }
                       
  
   }
   return kekka;   
}
         
//+------------------------------------------------------------------+
//|【関数】ジグザグの値をセット
//|
//|
//|【備考】なし
//+------------------------------------------------------------------+
bool getZigZag(int i)
{
      
int n,m,t;
      
bool kekka;
      
   m=0;
   t=0;
      
         
   kekka=false;
      
   for(n=i;n<=i+200;n++)
   {
      //ZigZagの値を取得
      double Zg=NormalizeDouble(iCustom(NULL,0,"ZigZag",E_Depth,E_Deviation,E_Backstep,0,n),5);
      
      //ZigZagの値と最高値が同じ場合、頂点なのでZigTopにセット      
      if(Zg!=0 && Zg==NormalizeDouble(High[n],5))
      {
         if(n==1){
            TopPoint=1;
         }
               
         ZigTop[m++]=Zg;
         if(m>=4)break;
      }
            
      //ZigZagの値と最安値が同じ場合、底なのでZigBottomにセット            
      if(Zg!=0 && Zg==NormalizeDouble(Low[n],5))
      {
         if(n==1){
            BottomPoint=1;
         }
                     
         ZigBottom[t++]=Zg;
         if(t>=4)break;
      }
   }
      
   kekka=true;
         
      
   //目視確認用コメント
   Comment(
          "│ ZigTOP0=", ZigTop[0], "│ ZigBTM0=", ZigBottom[0], "|\n",
          "│ ZigTOP1=", ZigTop[1], "│ ZigBTM1=", ZigBottom[1], "|\n",
          "│ ZigTOP2=", ZigTop[2], "│ ZigBTM2=", ZigBottom[2], "|\n",
          "│ ZigTOP3=", ZigTop[3], "│ ZigBTM3=", ZigBottom[3], "|\n",
          "│ TopP=", TopPoint, "│ BottomP=", BottomPoint, "|\n"
   );
            
         
   return(kekka);   
        
}

自作のgetZigZag関数で、ZigTop[]構造体にZigZagの高値側(頂点)をセットしています。

ZigTop[0]は最新の高値、ZigTop[1]は1つ前の高値・・・といったような感じです。

ZigBottom[]構造体にはZigZagの安値側(底)をセットしています。

アレンジ方法(切り上げ、切り下げ最中のエントリー)

高値切り上げ中にロングエントリーしたいという場合は、
「・・・&& ZigBottom[1] > ZigBottom[2] && BottomPoint==1」の所を
「・・・&& ZigBottom[1] > ZigBottom[2] 」に変えればOKです。

安値切り下げ中にショートエントリーしたいという場合は、
「・・・&& ZigBottom[1] < ZigBottom[2] && TopPoint==1」の所を
「・・・&& ZigBottom[1] < ZigBottom[2] 」に変えればOKです。

アレンジ方法(切り上げ、切り下げ上限の緩和)

3セット分の高値安値を見る場合、
「if(ZigTop[0] > ZigTop[1] && ZigTop[1] > ZigTop[2] && ZigTop[2] > ZigTop[3] &&ZigBottom[0] > ZigBottom[1] && ZigBottom[1] > ZigBottom[2] && ZigBottom[2] > ZigBottom[3]&& TopPoint==1)」

2セット分の高値安値を見る場合(サンプルソースの内容)
「if(ZigTop[0] > ZigTop[1] && ZigTop[1] > ZigTop[2] &&ZigBottom[0] > ZigBottom[1] && ZigBottom[1] > ZigBottom[2] && TopPoint==1)」

1セット分の高値安値を見る場合、
「if(ZigTop[0] > ZigTop[1] &&ZigBottom[0] > ZigBottom[1]&& TopPoint==1)」

主な構文

iCustom()

【使用例】
iCustom(NULL,0,"ZigZag",12,5,3,0,0)

iCustom()関数でZigZagの値を取得します。

引数は以下の通りです。

  1. 通貨ペア(NULLで当該通貨)
  2. 時間軸(0で当該時間軸)
  3. インジケータ名称(ZigZagを使う場合はそのまま”ZigZag”です)
  4. Depthの値(デフォルト設定の12を使用しています)
  5. Deviationの値(デフォルト設定の5を使用しています)
  6. Backstepの値(デフォルト設定の3を使用しています)
  7. 取得する値(ZigZagの頂点を取得する場合0でOKです)
  8. バーシフト
※サブウインドウにZigZagの値を表示するインジケータを作成して表示しています
【ZigZagの確認】
◎値がセットされている箇所
①iCustom()関数でZigZagの値を取得する際に気を付けたいのが、上の図の①を見てほしいのですがサブウインドウ側の縦棒が伸びていない部分は0が返ってくるという点です。なので単純にiCustom()関数でZigZagの値を取得してきて使おうとしても、大体0が返ってきてしまうので現在時間から後ろに結構さかのぼって確認していく必要があります。
※縦棒が伸びている部分にはちゃんと頂点の値段がセットされています

②奇麗な安値切り下げが発生しています。これを見ようと思ったら矢印のように過去へさかのぼり、(頂点と底は分けて)値を保持しておくのが一番てっとりばやいと思います。

上記を踏まえ以下サンプルソースでは、for文で現在時間から後ろに200バー分さかのぼり、ZigZagの頂点と底をそれぞれ構造体にセットしていき、それを見てエントリーしていくような感じにしています。

さいごに

以上、ZigZagを使ったEAのサンプルソースでした。

このZigZagロジックの調整例としては、先ほど「ZigZagの性質上、デメリットが発生する」と記述していたデメリット部分が連続して発生している所が結構あったので、そこはデメリットが1回発生したら同一方向へのエントリーはしないようにしてあげたり、トレール等を追加すればさらによい成績になると思います。

あと、指値、逆指値も20pips固定なので、ZigTopとZigBottomという高値安値を使っていけばもっといい場所で指値、逆指値を設定できると思います。

※2021/02/18追記 
このZigZagロジックをベースに開発したEAをリアル口座にて稼働しました。

※2021/03/19追記 
このZigZagロジックをメンテして、ナンピンを行うZigZagEAのサンプルソースを公開しました。

※ MT4・EAが使えるFX会社のおすすめ

※ EAのサンプルソースを一覧表にまとめました


コメント

  1. よね より:

    はじめまして、よねと申します。

    EAの作成にあたって、本サイトに行き着きました。
    本記事のサンプルソースがとても参考になっています。
    自分も裁量トレードから勝てなくて、EAに行き着きました。
    自分のブログにも本サイトのリンクを貼らせて頂きました。
    問題があれば削除させて頂きますので、ご連絡ください。
    サイトの更新楽しみにしています。
    また遊びにこさせていただきます。
    よろしくお願いします。

    • りょう りょう より:

      はじめまして、よねさん。サイトを見て頂き有難うございます。
      裁量トレード難しいですよね・・・。EA運用ともに頑張りましょう!
      サイトにリンクを貼って頂くのはむしろ歓迎です、ありがとうございます!

  2. キクチワタル より:

    はじめまして、ジグザクの説明勉強になりました。例えば条件が4時間足、一時間足切り上げ。15分も切り上げたときエントリーすることなど可能でしょうか?他の足と連動させることは可能でしょうか?

    • りょう りょう より:

      はじめまして、キクチワタルさん。有難うございます!他の足と連動させる方法は難しいんですが、色んな方から結構ご質問頂いているので1度作ってみようと思います。また、参考に出来そうなソースコードが完成したら掲載しますね。

  3. ぷりんらぶ より:

    バックテストのデータですが、どちらを使われましたか?
    このコードを使用してみたのですが、
    結果が一致しないので、、、

  4. プリン より:

    掲載のコードを参考に、谷が確定した後の任意の位置でエントリーするようにコードを書き換えようとしていますが、なかなか上手くいきません。どうかご教授いただきたくコメント申し上げます。

    谷確定後で任意の位置でエントリーするという場合、TopPoint>=2を入れて考えています。例えば、次のような感じです。

    ZigBottom[0] MA2 && MA2 =2
     ※MA1:最新の足の1つ前の足の移動平均。
     MA2:最新の足の2つ前の足の移動平均。
     MA3:最新の足の3つ前の足の移動平均。

    最新の2つ前の足からZigBottom[0]の足の間に、ZigTop[0]があるという条件下のもと、谷確定後で「MA3 > MA2 && MA2 < MA1」を満足するような箇所でエントリーとなりそうだと思っていますが、どうもそうじゃないようです。

    何故上手くいかないのか分からなくて途方に暮れています。コメント頂ければ幸いです。

    • りょう りょう より:

      コメントありがとうございます。

      すこし、プリンさんが実現したい事を整理させてください。
      まず、ZigZagと移動平均線を判断材料にエントリーするという感じで合ってますでしょうか?

      その場合、『ロングエントリーする条件として、ZigZagの谷が確定した後にMA3 > MA2 && MA2 < MA1となっている事』という感じでしょうか? あと、この『MA3 > MA2 && MA2 < MA1となっている事』という判定は、移動平均線が下向いている事とかレンジで有る事とか上向いている事といった事を判断されるための条件でしょうか?

  5. プリン より:

    早速の返信ありがとうございます。
    仰るとおり、「ZigZagと移動平均線を判断材料にエントリーする」です。
    また、『ロングエントリーする条件として、ZigZagの谷が確定した後にMA3 > MA2 && MA2 < MA1となっている事』です。移動平均が上向いた時にエントリーしたいと考えています。
    どうぞよろしくお願いいたします。

    • りょう りょう より:

      わかりました。

      ちょうどZigZagを使ったEAで、新たに記事を書こうと思っていましたので「ZigZagと移動平均線を判断材料にエントリーする」EAのサンプルソース記事を書きます。よかったら参考にして頂ければと思います。
      ※明日明後日には書けると思いますので、もうしばらくお待ちください

      • プリン より:

        返信ありがとうございます。
        新しい記事作成して頂けるのですね、楽しみしています。また、参考にさせて頂きます。