EAでエンベロープを使う(サンプルソース)

EA
スポンサーリンク

FXで売買タイミングとして使うエンベロープ(Envelopes)の、簡単なMT4のEAサンプルです。

エンベロープは移動平均線のほぼ延長線のインディケータなので、とてもシンプルです。移動平均線からの離れ具合を確認できるので、初心者用にもオススメのインディケータとなっています。

今回、以下の記事では順張り目線でエントリーしていくサンプルを載せています。

主な構文

iEnvelopes()

【使用例】
double ENV_ATAI_L = iEnvelopes(NULL, 0, 21, 1, 1, PRICE_CLOSE, 0.2,MODE_LOWER, 0);

今回は、エンベロープの値を取得できるiEnvelopes()関数を使っています。

引数は以下の通りです。

  1. 引数1・・・通貨ペアです(NULLでチャートの通貨になります)
  2. 引数2・・・時間軸です(0でチャートの時間軸になります)
  3. 引数3・・・ベースとなる移動平均線の値です(20で20移動平均線、25で25移動平均線になります)
  4. 引数4・・・ベースとなる移動平均線の種別です(0 = sma, 1 = ema, 2 = smma, 3 = lwma)
  5. 引数5・・・ベースとなる移動平均線の種別の表示移動です
  6. 引数6・・・適用価格です(PRICE_CLOSEでクローズ値)
  7. 引数7・・・偏差です
  8. 引数8・・・モードです(MODE_MAIN:中心線, MODE_UPPER:上線, MODE_LOWER:下線)
  9. 引数9・・・バーシフトです(0で現在の値、1で1つ前ーのバーの時の値です)

基本的に、3~8を触るような設定ですね!3~8の設定はMT4のEnvelopes設定画面上で見るとイメージしやすいです。

4:種別(移動平均線)は、以下4種類です。

  • 単純移動平均線:MODE_SMA 0
  • 指数移動平均線:MODE_EMA 1
  • 平滑移動平均線:MODE_SMMA 2
  • 線形加重移動平均線:MODE_LWMA 3

6:適用価格は、9種類ありますが主に使うのは以下4種類だと思います。

  • 終値:PRICE_CLOSE 0
  • 始値:PRICE_OPEN 1
  • 高値:PRICE_HIGH 2
  • 安値:PRICE_LOW 3

8:バーシフトは過去のEnvelopes値をとりたい場合変更します(0:最新バーの位置、1:1つ前のバーの位置)

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

ソースコード


//+------------------------------------------------------------------+
//|                                               ENVELOPES_TEST.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 MA_Atai = 20;
input int MA_Syubetu = 1; // 0 = sma, 1 = ema, 2 = smma, 3 = lwma
input int MA_HIdou = 1;
input int Tekiyou = 0;  // 0 = Close, 1 = Open, 2 = High, 3 = Low
input double Hensa = 0.34;
input double Hensa_uri = 0.08;

input int A_SPREAD = 10;
input double Lots = 0.01;

input int SL = 2000;

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);
   }
        
//***売買判断箇所***//
       
   //----エンベロープの値を取得     
   double ENV_ATAI_U   = iEnvelopes(NULL,0,MA_Atai,MA_Syubetu,MA_HIdou,Tekiyou,Hensa,MODE_UPPER,MA_HIdou);
   double ENV_ATAI_M   = iEnvelopes(NULL,0,MA_Atai,MA_Syubetu,MA_HIdou,Tekiyou,Hensa,MODE_MAIN,MA_HIdou);
   double ENV_ATAI_L   = iEnvelopes(NULL,0,MA_Atai,MA_Syubetu,MA_HIdou,Tekiyou,Hensa,MODE_LOWER,MA_HIdou);

   //----エンベロープの決済判断値を取得
   double ENV_ATAI_UK   = iEnvelopes(NULL,0,MA_Atai,MA_Syubetu,MA_HIdou+1,Tekiyou,Hensa_uri,MODE_UPPER,MA_HIdou);
   double ENV_ATAI_LK   = iEnvelopes(NULL,0,MA_Atai,MA_Syubetu,MA_HIdou+1,Tekiyou,Hensa_uri,MODE_LOWER,MA_HIdou);

   //ローソク足のクローズ値情報を取得しておく
   double rosokuValueClose =  iClose(NULL, 0, MA_HIdou);

    
   //エンベロープの値よりローソク足の終値が上だった場合、ロング
   if(ENV_ATAI_U < rosokuValueClose)
   {
      orderPtn=1;
   }
   //エンベロープの値よりローソク足の終値が上だった場合、ショート
   else if(ENV_ATAI_L > rosokuValueClose)
   {
      orderPtn=2;
   }
   else
   {
      orderPtn=0;
   }
    
//***売買判断箇所***//
   OrderKekka = OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
   
   //エンベロープの決済判断値よりローソク足の終値が下だった場合、決済(ロング時)
   if(OrderType() == OP_BUY && ENV_ATAI_UK > rosokuValueClose){
      OrderKekka = funcOrder_Close();
   }
   //エンベロープの決済判断値よりローソク足の終値が上だった場合、決済(ショート時)
   else if(OrderType() == OP_SELL && ENV_ATAI_LK  < rosokuValueClose){
      OrderKekka = funcOrder_Close();
   }

//***決済判断箇所***//
   total=OrdersTotal();
   if(total == 0 && orderPtn > 0)   
   {
      if(orderPtn == 1)
      {
         ea_order_stop_price = Ask - SL * Point;
         ea_order_good_price = Ask + SL * Point;    
      }
      else if(orderPtn == 2)
      {
         ea_order_stop_price = Bid + SL * Point;  
         ea_order_good_price = Bid - SL * 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;
         }else if(ea_order_entry_Type == OP_SELL){        
            ea_order_entry_price = Bid;               // 現在の売値でエントリー
            order_Color = clrRed;            
         }
       
         // 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               // オーダーアイコンカラー
            );
      }
                   
      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;
      }
   }
   return kekka;   
}

//+------------------------------------------------------------------+
//|【関数】決済関数
//|
//|【引数】 なし
//|
//|【戻値】True:成功 False:失敗
//|
//|
bool funcOrder_Close()
{
   bool kekka,OrderKekka;
   int total,order_resend_num;
   double ea_order_entry_price; // エントリーレート
   color order_Color;
    
   kekka=false;
 
   for(order_resend_num = 0; order_resend_num < 100; order_resend_num++ ) {
      if(MarketInfo(NULL,MODE_SPREAD) < A_SPREAD){
 
         total=OrdersTotal();
          
         if(total >0 && OrderSelect(0,SELECT_BY_POS,MODE_TRADES)==true){
 
            if(OrderType() == OP_BUY){   
               ea_order_entry_price = Bid;               // 現在の売値で決済
               order_Color = clrLightBlue;
            }else if(OrderType() == OP_SELL){
               ea_order_entry_price = Ask;               // 現在の買値で決済
               order_Color = clrLightPink;            
            }
 
            OrderKekka = OrderClose(OrderTicket(),OrderLots(),ea_order_entry_price,10,order_Color);
 
            if(OrderKekka==false){
               Print("決済失敗 エラーNo=",GetLastError()," リトライ回数=",order_resend_num+1);
                
               RefreshRates();
               Sleep(1000);
            }else{
               Print("決済注文約定。 レート=",ea_order_entry_price);
             
               kekka=true;
               break;
            }
         }
      }else{
          Print("スプレッド拡大中(銭)=",MarketInfo(NULL,MODE_SPREAD) / 10," リトライ回数=",order_resend_num+1);
           
          Sleep(5000);                                           // msec待ち
          RefreshRates();                                        // レート更新
      }
   }
   return kekka;   
}

エントリータイミング

ロングエントリー

エンベロープ(上線)の値よりローソク足の終値が上だった場合、ロングエントリーします。

今回は、シンプルにこの条件のみで判断しています。

ショートエントリー

エンベロープ(下線)の値よりローソク足の終値が下だった場合、ショートエントリーします。

今回は、シンプルにこの条件のみで判断しています。

エントリー例

青赤の実線(エントリー用エンベロープ)の上抜けでロングエントリー、下抜けでショートエントリーしています。

あと、後述しますが点線(決済用エンベロープ)を超えて戻ると決済する感じです。

決済タイミング

今回は、エントリー用エンベロープの値の他に、決済用エンベロープの値を設けています。エントリー用エンベロープの値よりも、決済用エンベロープの値の方を小さくしています。

ロング中

決済用エンベロープ(上線)の値よりローソク足の終値が下だった場合、ロングポジションを決済します。

ショート中

決済用エンベロープ(下線)の値よりローソク足の終値が上だった場合、ショートポジションを決済します。

その他の仕様

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

  1. MA_Atai = 20 ⇒ ベースとなる移動平均線の値です
  2. MA_Syubetu = 1 ⇒ ベースとなる移動平均線の種別です(1でEMA)
  3. MA_HIdou = 1 ⇒ ベースとなる移動平均線の種別の表示移動です
  4. Tekiyou = 0 ⇒ 適用価格です(0でクローズ値)
  5. Hensa = 0.34 ⇒ エントリー用エンベロープ値の偏差です
  6. Hensa_uri = 0.08 ⇒ 決済用エンベロープ値の偏差です
  7. A_SPREAD = 10 ⇒ エントリー及び決済時に許容するスプレッドの値です(10 = 10pips)
  8. Lots = 0.01 ⇒ ロット数です(0.01=1000通貨)
  9. SL = 2000 ⇒ ストップロスまでのポイントです(1000=100pips)

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

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

EAレポート結果

2012年~2021年の期間の1時間足でバックテスト確認してみました。エンベロープ等の値は最適化で良い値を選んだのですが、いつものように2005年からで確認すると中々良いプロフィットファクターになりませんでした。

約9年間で総取引数が1200近くなので、年間130ちょっとの取引です。単純にエントリー時のみエンベロープ値を使うだけだと中々良い感じにならなかったので、決済時にもエンベロープ値を使う感じにしましたが、体感的にはめちゃくちゃ有効っていう感じでもないです。

今回は順張りEAとなりましたが、逆張りでもまた試してみたいなーと思います。

以上、エンベロープのEAサンプルソースでした。

 

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


※ オススメ記事(EAが使える国内FX業者の一覧)


※ 1からEAの作り方を学びたい人はこちら

コメント

タイトルとURLをコピーしました