EAでナンピン手法を使う(サンプルソース)

EA
スポンサーリンク

MT4のEAで、 ナンピンを用いた物がよくあります。

これまで、私が作ってきたサンプルソースはナンピンを一切しないタイプの物ばかりでしたので、今回はこのナンピン手法をFXのEAに取り入れていきたいと思います。

概要

ナンピンするとなった場合、実際プログラムでナンピンする方法はいたって簡単です。難しいのは、ナンピンする場所・タイミングだと思いますが、現在私が公開しているZigZagのサンプルEAはここでナンピンできたらなーというタイミングが結構あったのでZigZagのサンプルEAにナンピン手法を取り入れていきます。

※ナンピンしないタイプのZigZagサンプルEAの記事はこちら

今回の修正について

要は何がしたかったのかと言うと、修正前のZigZagEAはデメリットとして上図の事が発生していましたが、それを補う感じでデメリットが発生したら追加でエントリーするという感じの修正をしました。

この修正を加える前と後の違いを実際のエントリーポイントで確認してみるとこんな感じです。

※こちらは修正前
※こちらが修正後

黄色〇の部分を見て頂ければわかるように、エントリー後悪い方向に値が動くとナンピンして3つエントリーが増えている事がわかります。

EAレポート結果

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

修正前のZigZagのEAと同じ期間でバックテストを行いました。プロフィットファクターの値が1.09から1.15に改善されています。逆指値40pipsに対して指値を10pipsにしたので、勝率が52%から82%にまであがってますね。また、ここ近年の成績はかなり良い感じになってます。

ダウンロード

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

“ZigZagナンピンEA” をダウンロード

17_Nanpin.ex4 – 3333 回のダウンロード – 15.33 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 = 16;
input int E_Deviation = 5;
input int E_Backstep = 3;
   
input int A_SPREAD = 20;
input double Lots = 0.01;
        
input int STOP_LOSS = 400;
input int TP = 100;
        
        
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){ 
      OrderKekka = OrderSelect(total-1,SELECT_BY_POS,MODE_TRADES);
      if(OrderType()==OP_BUY && orderPtn == 2){
         orderPtn =0;
      }else if(OrderType()==OP_SELL && orderPtn == 1){
         orderPtn =0;
      }
      if(OrderType()==OP_BUY && (OrderOpenPrice() - 40 * Point < Ask)){
         orderPtn =0;
      }else if(OrderType()==OP_SELL && (OrderOpenPrice() + 40 * Point  > Bid)){
         orderPtn =0;
      } 
     
      //既にナンピンを4回している場合は追加ナンピンしない
      if(total>3){
         orderPtn =0;
      }
   }
     
   if(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("エラー");
            }
               
            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);   
          
}

一応前述したナンピン修正を加えたZigZagEAのサンプルソースコードになります。

あと設定で、ZigZagのDepth値、指値、逆指値を少し変えてます。

それ以外の処理はZigZagのサンプルEAから何も変えていません。

このナンピン型のZigZagロジックの調整例としては、ナンピン時に既に保持しているポジションの指値を変更してやったり、ナンピン時のロット数を変える等があると思います。ロット数を変える方法は、かなりマーチンゲール手法に近くなるので安定性はさらに増すと思います。(また別のタイミングでサンプルソースを作ってみようと思います)

主な構文

ナンピンはポジション管理になるので、こういう関数を使えばナンピンできるとかはありません。

プログラムでポジションを持っているかどうかを確認していく形になります。

ポジションを複数持たせたい

私が作るプログラムの場合、エントリー前にポジションを持っているかどうかを判断している場所があります。既にポジションがあればエントリーしない作りになっているためここを修正します。

修正前の状態


if(total ==0 && orderPtn > 0)   

修正後の状態

if(total > 0 && orderPtn > 0)
{ 
   OrderKekka = OrderSelect(total-1,SELECT_BY_POS,MODE_TRADES);
   if(OrderType()==OP_BUY && orderPtn == 2){
      orderPtn =0;
   }else if(OrderType()==OP_SELL && orderPtn == 1){
      orderPtn =0;
   }
   if(OrderType()==OP_BUY && (OrderOpenPrice() - 40 * Point < Ask)){
      orderPtn =0;
   }else if(OrderType()==OP_SELL && (OrderOpenPrice() + 40 * Point  > Bid)){
      orderPtn =0;
   } 
     
   //既にナンピンを4回している場合は追加ナンピンしない
   if(total>3){
      orderPtn =0;
   }
}
if(orderPtn > 0)   

こんな感じに修正すると、前回ポジションが4pips以上マイナスになっている場合に、同一方向に4ポジションまで持つようになります。5pips以上にしたい場合は2つの『40 * Point』の箇所を『50 * Point』にすればOKです。

また、ポジションを最大5つまで持たせたい場合は『if(total>3){』の箇所を『if(total>4){』にすればOKです。

さいごに


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

カーブフィッティングしてしまうようなナンピン手法の修正を加えてはいないと思うので、ZigZagEAに対して、ナンピンは結構有効なのかなという印象です。

※2021/04/03追記
このZigZagEA(ナンピン版)をメンテして、ロット数や変更注文をするZigZagEAのサンプルソースを公開しました。

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

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


コメント

  1. 佐藤さとし より:

    いつも読ませていただきとても参考になり感謝しかないです!
    今作っているのがMACDナンピンのロングのみEAなんですがやはり含み損回避の為にナンピンし一定の含み損になると損切りをしたいと思い、色々試したんですがコンパイルしてもエラーが出て全然上手くいきません。
    そこてナンピン+損切りのソースコードが分かりません。
    設定としてはシグナル線とMACD線クロスでロング、20%下落でナンピンですが100%下落すると損切りって可能ですか?

    • りょう りょう より:

      佐藤さとし さん
      ブログを読んで頂き有難うございます!

      少し質問させてください。
      一定の含み損になると損切りという事は、ストップロス(SL)ではなくOrderClose()関数で決済させるような作りにするという事ですか?

      20%下落でナンピンという事ですが、20%は何の数値を表しているでしょうか?(MACD値とか証拠金維持率でしょうか?)