FXで売買タイミングとして使うエンベロープ(Envelopes)の、簡単なMT4のEAサンプルです。
エンベロープは移動平均線のほぼ延長線のインディケータなので、とてもシンプルです。移動平均線からの離れ具合を確認できるので、初心者用にもオススメのインディケータとなっています。
今回、以下の記事では順張り目線でエントリーしていくサンプルを載せています。
主な構文
iEnvelopes()
【使用例】 double ENV_ATAI_L = iEnvelopes(NULL, 0, 21, 1, 1, PRICE_CLOSE, 0.2,MODE_LOWER, 0);
今回は、エンベロープの値を取得できるiEnvelopes()関数を使っています。
引数は以下の通りです。
- 引数1・・・通貨ペアです(NULLでチャートの通貨になります)
- 引数2・・・時間軸です(0でチャートの時間軸になります)
- 引数3・・・ベースとなる移動平均線の値です(20で20移動平均線、25で25移動平均線になります)
- 引数4・・・ベースとなる移動平均線の種別です(0 = sma, 1 = ema, 2 = smma, 3 = lwma)
- 引数5・・・ベースとなる移動平均線の種別の表示移動です
- 引数6・・・適用価格です(PRICE_CLOSEでクローズ値)
- 引数7・・・偏差です
- 引数8・・・モードです(MODE_MAIN:中心線, MODE_UPPER:上線, MODE_LOWER:下線)
- 引数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; }
エントリータイミング
ロングエントリー
エンベロープ(上線)の値よりローソク足の終値が上だった場合、ロングエントリーします。
今回は、シンプルにこの条件のみで判断しています。
ショートエントリー
エンベロープ(下線)の値よりローソク足の終値が下だった場合、ショートエントリーします。
今回は、シンプルにこの条件のみで判断しています。
エントリー例

青赤の実線(エントリー用エンベロープ)の上抜けでロングエントリー、下抜けでショートエントリーしています。
あと、後述しますが点線(決済用エンベロープ)を超えて戻ると決済する感じです。
決済タイミング
今回は、エントリー用エンベロープの値の他に、決済用エンベロープの値を設けています。エントリー用エンベロープの値よりも、決済用エンベロープの値の方を小さくしています。
ロング中
決済用エンベロープ(上線)の値よりローソク足の終値が下だった場合、ロングポジションを決済します。
ショート中
決済用エンベロープ(下線)の値よりローソク足の終値が上だった場合、ショートポジションを決済します。
その他の仕様
設定値は以下の通りです。
- MA_Atai = 20 ⇒ ベースとなる移動平均線の値です
- MA_Syubetu = 1 ⇒ ベースとなる移動平均線の種別です(1でEMA)
- MA_HIdou = 1 ⇒ ベースとなる移動平均線の種別の表示移動です
- Tekiyou = 0 ⇒ 適用価格です(0でクローズ値)
- Hensa = 0.34 ⇒ エントリー用エンベロープ値の偏差です
- Hensa_uri = 0.08 ⇒ 決済用エンベロープ値の偏差です
- A_SPREAD = 10 ⇒ エントリー及び決済時に許容するスプレッドの値です(10 = 10pips)
- Lots = 0.01 ⇒ ロット数です(0.01=1000通貨)
- SL = 2000 ⇒ ストップロスまでのポイントです(1000=100pips)
既にポジションがある場合は追加でエントリーしません。
新しい足(バー)が出来た際に1度だけ処理を行います。※1時間足の場合だと1時間に1回処理する
EAレポート結果

2012年~2021年の期間の1時間足でバックテスト確認してみました。エンベロープ等の値は最適化で良い値を選んだのですが、いつものように2005年からで確認すると中々良いプロフィットファクターになりませんでした。
約9年間で総取引数が1200近くなので、年間130ちょっとの取引です。単純にエントリー時のみエンベロープ値を使うだけだと中々良い感じにならなかったので、決済時にもエンベロープ値を使う感じにしましたが、体感的にはめちゃくちゃ有効っていう感じでもないです。
今回は順張りEAとなりましたが、逆張りでもまた試してみたいなーと思います。
以上、エンベロープのEAサンプルソースでした。
※ EAのサンプルソースを一覧表にまとめました
※ オススメ記事(EAが使える国内FX業者の一覧)
※ 1からEAの作り方を学びたい人はこちら
コメント