MT4でMACDのEAを改良する方法|決済条件をカスタマイズ【サンプルコード付】

MACD2
EAサンプル・ノウハウ
記事内に商品プロモーションを含む場合があります
スポンサーリンク

はじめに

前回の記事では「MACDを使った基本的なEA」を紹介しました。
その際は、利確20pips/損切り20pips(パラメータ設定)のルールで実装していましたが、
「もっと自分のトレードスタイルに合った決済条件にしたい」
と考える方も多いのではないでしょうか。

そこで今回は、決済処理をカスタマイズする方法をテーマに解説します。

👉 前回の基本版EAはこちら
MT4でMACD EAを作成|無料MQL4サンプルコード解説

前回からどこに修正を加えたら利益が出るMACDのEAになったのかを分かる形にしているので参考にして頂ければと思います。


カスタマイズできる決済処理の例

MACD EAで、以下のようなカスタマイズ方法を考えました。

  • MACDクロスを決済トリガーにする
  • 直近の高値・安値を基準に損切りする
  • 他インジケーターを併用する(RSIやATRなど)

今回は、一旦他のインジケーターには頼らずMACDのみ、つまり「エントリー、決済共にMACDクロスを利用する」方向で改良します。

実装例①:MACDクロスで決済

固定利確ではなく、MACDのクロスを決済条件に組み込む例です。

  • 買いポジション中:MACDがデッドクロスしたら決済
  • 売りポジション中:MACDがゴールデンクロスしたら決済

これにより、トレンドの転換を判断して決済することができます。


実装例②:直近の高値・安値を利用した損切り

固定pipsではなく、チャートの形状に応じた損切りを設定する方法です。

  • 買いエントリー時 → 直近N本の最安値を損切りラインに設定
  • 売りエントリー時 → 直近N本の最高値を損切りラインに設定

これにより、トレンドフォロー型の損切りが可能になります。


決済条件をカスタマイズする

実装例①:MACDクロスで決済についてです。以下のようにクロスで決済する処理を追加しています。

//***【決済注文判断↓】***//
      bool isBullMACD_C = false;
      bool isBearMACD_C = false;

      bool kekka = OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
      
      // BUYポジション → 上から下にMACDがクロスしたら決済する
      if(OrderType() == OP_BUY){
         if(getMACDSign(2,1,0)==true){
            isBullMACD_C = true;
         }
      }
      
      // SELLポジション → 下から上にMACDがクロスしたら決済する   
      else if(OrderType() == OP_SELL){
         if(getMACDSign(1,1,0)==true){
            isBearMACD_C = true;
         }
      }

//***【決済注文判断↑】***//

次に、実装例②:直近の高値・安値を利用した損切りについてです。

//***【TP/SL判断↓】***//
      if(openBuy){
         if(MACD_UseSwingSL){
            int index = iLowest(NULL, 0, MODE_LOW, MACD_SwingBars, 1);
            ea_order_stop_price = iLow(NULL, 0, index) - MACD_SL_Buffer * PipValue; // 安値より下に余裕を持たせる
         } else {
            ea_order_stop_price = Ask - SL * PipValue;
         }
         ea_order_good_price = Ask + TP * PipValue;
      
      }else if(openSell){
         if(MACD_UseSwingSL){
            int index = iHighest(NULL, 0, MODE_HIGH, MACD_SwingBars, 1);
            ea_order_stop_price = iHigh(NULL, 0, index) + MACD_SL_Buffer * PipValue; // 高値より上に余裕を持たせる
         } else {
            ea_order_stop_price = Bid + SL * PipValue;
         }
         ea_order_good_price = Bid - TP * PipValue;
      }
//***【TP/SL判断↑】***//

パラメータ設定で調整できるようにしたので少し複雑になりましたが、基本はTP/SLを設定しているのみです。


サンプルコード(決済処理カスタマイズ版)

以下は、決済処理部分をカスタマイズしたサンプルです。

//+------------------------------------------------------------------+
//|                                                 07_MACD_kai1.mq4 |
//|                                    Copyright © 2020-2025 ぷろぐらむFX |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020-2025 ぷろぐらむFX"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

input double Lots = 0.01;              //ロット
input int TP = 100;                    //利確(pips)
input int SL = 100;                    //損切り(pips)
//***【パラメータ設定↓】MACD***//
input int MACD_FE_PERIOD = 12;         //MACDファストEMA期間
input int MACD_SE_PERIOD = 26;         //MACDスローEMA期間
input int MACD_SS_PERIOD = 9;          //MACDシグナル期間


input bool MACD_UseSwingSL = true;   // 直近高値安値で損切りするか
input int MACD_SwingBars  = 24;      // 参照するバー本数
input int MACD_SL_Buffer  = 3;       // 損切りラインに加える余裕(pips)

//***【パラメータ設定↑】MACD***//

string Ea_Name = WindowExpertName();   //チャート上のEA名称を取得(オーダーコメントに使用)

double PipValue;                       //ブローカー桁数に対応した Point 補正
datetime prevtime;                     //ローソク足時間保持用
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //デジットチェック
   if (Digits == 3 || Digits == 5){
      PipValue = Point * 10;   // 例: EURUSD 1.23456 → 1pip = 0.00010
   }else{
      PipValue = Point;        // 例: USDJPY 123.45 → 1pip = 0.01
   }

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   int total = OrdersTotal();    //ポジショントータル数をセット  
   int ea_order_Type = -1; //0:OP_BUY  1:OP_SELL
   double ea_order_stop_price = 0; //ストップロスレート
   double ea_order_good_price = 0; //利確レート

   //新しい足ができた時だけやる
   if(Time[0] != prevtime){
      prevtime = Time[0];
   }else{
      return;
   }

   //ポジションがない場合はエントリー判定
   if(total == 0){

      bool openBuy  = false;    //買い新規注文判断
      bool openSell = false;    //売り新規注文判断
      
//***【新規注文判断↓】***//
      bool isBullMACD_S = false;
      bool isBearMACD_S = false;

      // MACDシグナル取得(3=下から上クロス(マイナス圏)、4=上から下クロス(プラス圏))
      // 直近の確定バーでクロス判定
      if(getMACDSign(3, 2, 1)){   // マイナス圏で下から上
         isBullMACD_S = true;
      }
      else if(getMACDSign(4, 2, 1)){ // プラス圏で上から下
         isBearMACD_S = true;
      }
            
//***【新規注文判断↑】***//

      //参照するサンプルEAの買いエントリーフラグをセットしてください
      if(isBullMACD_S){
         openBuy =true;
         ea_order_Type = OP_BUY;
      //参照するサンプルEAの売りエントリーフラグをセットしてください      
      }else if(isBearMACD_S){
         openSell =true;
         ea_order_Type = OP_SELL;
      }


//***【TP/SL判断↓】***//
      if(openBuy){
         if(MACD_UseSwingSL){
            int index = iLowest(NULL, 0, MODE_LOW, MACD_SwingBars, 1);
            ea_order_stop_price = iLow(NULL, 0, index) - MACD_SL_Buffer * PipValue; // 安値より下に余裕を持たせる
         } else {
            ea_order_stop_price = Ask - SL * PipValue;
         }
         ea_order_good_price = Ask + TP * PipValue;
      
      }else if(openSell){
         if(MACD_UseSwingSL){
            int index = iHighest(NULL, 0, MODE_HIGH, MACD_SwingBars, 1);
            ea_order_stop_price = iHigh(NULL, 0, index) + MACD_SL_Buffer * PipValue; // 高値より上に余裕を持たせる
         } else {
            ea_order_stop_price = Bid + SL * PipValue;
         }
         ea_order_good_price = Bid - TP * PipValue;
      }
//***【TP/SL判断↑】***//

      if(ea_order_Type > -1){
         funcOrder_Send(ea_order_Type,ea_order_stop_price,ea_order_good_price,Lots,Ea_Name,777,0);
      }
      
   //ポジションがある場合は決済判定   
   }else{
   
      bool closeBuy  = false;    //買いポジション決済判断
      bool closeSell = false;    //売りポジション決済判断
      
//***【決済注文判断↓】***//
      bool isBullMACD_C = false;
      bool isBearMACD_C = false;

      bool kekka = OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
      
      // BUYポジション → 上から下にMACDがクロスしたら決済する
      if(OrderType() == OP_BUY){
         if(getMACDSign(2,1,0)==true){
            isBullMACD_C = true;
         }
      }
      
      // SELLポジション → 下から上にMACDがクロスしたら決済する   
      else if(OrderType() == OP_SELL){
         if(getMACDSign(1,1,0)==true){
            isBearMACD_C = true;
         }
      }

//***【決済注文判断↑】***//
   
      //参照するサンプルEAの買いポジション決済フラグをセットしてください
      if(isBullMACD_C){
         closeBuy =true;
         ea_order_Type = OP_BUY;
      //参照するサンプルEAの売りポジション決済フラグをセットしてください
      }else if(isBearMACD_C){
         closeSell =true;
         ea_order_Type = OP_SELL;
      }
      
      if(ea_order_Type > -1){
         funcOrder_CloseAll(ea_order_Type, -1, 0);
      }
      
   }

   return;
}

//***【関数(MACD用)↓】***//
bool getMACDSign(int type, int limit, int i)
{
   bool sign = false;
   double MACD_1, Signal_1, MACD_2, Signal_2;

   int start = i + 1;
   int end   = i + limit;

   for(int n = start; n < end; n++) // n+1があるので "< end"
   {
      // iMACDは戻り値がMACD - Signal(ヒストグラム値)
      // mode=MODE_MAIN → ヒストグラム, mode=MODE_SIGNAL → シグナル線
      MACD_1   = iMACD(NULL, 0, MACD_FE_PERIOD, MACD_SE_PERIOD, MACD_SS_PERIOD, PRICE_CLOSE, MODE_MAIN,   n);
      Signal_1 = iMACD(NULL, 0, MACD_FE_PERIOD, MACD_SE_PERIOD, MACD_SS_PERIOD, PRICE_CLOSE, MODE_SIGNAL, n);

      MACD_2   = iMACD(NULL, 0, MACD_FE_PERIOD, MACD_SE_PERIOD, MACD_SS_PERIOD, PRICE_CLOSE, MODE_MAIN,   n+1);
      Signal_2 = iMACD(NULL, 0, MACD_FE_PERIOD, MACD_SE_PERIOD, MACD_SS_PERIOD, PRICE_CLOSE, MODE_SIGNAL, n+1);

      // 誤差許容
      double eps = Point * 0.1;

      if(type==1 || type==3){ // 下から上
         if(MACD_2 < Signal_2 - eps && MACD_1 >= Signal_1 - eps){
            if(type==3 && MACD_1 > -eps) continue; // マイナス域限定
            sign = true;
            break;
         }
      }
      else if(type==2 || type==4){ // 上から下
         if(MACD_2 > Signal_2 + eps && MACD_1 <= Signal_1 + eps){
            if(type==4 && MACD_1 < eps) continue; // プラス域限定
            sign = true;
            break;
         }
      }
   }

   return sign;
}
//***【関数(MACD用)↑】***//

//★★★★★★★★★★★★★★★★★★★★ ここから下は共通関数 ★★★★★★★★★★★★★★★★★★★★
//+------------------------------------------------------------------+
//|【関数】新規注文関数
//|
//|【引数】 orderType:売買(0=BUY, 1=SELL)
//|【引数】 sl:損切り価格  tp:利確価格
//|【引数】 lots:取引ロット数
//|【引数】 orderComment:オーダーコメント
//|【引数】 magic:マジックNo
//|【引数】 maxSpreadPips: 許容スプレッド[Point] (0=制限なし)
//|
//|【戻値】true=成功 false=失敗
//+------------------------------------------------------------------+
bool funcOrder_Send(int orderType, double sl, double tp, double lots,
                    string orderComment, int magic, int maxSpreadPoints){
   int    ticket = -1;
   double price  = 0;
   color  clr    = clrNONE;
   double spread = 0;

   // 最大10回リトライ
   for(int retry=0; retry<10; retry++)
   {
      RefreshRates();
      
      // スプレッド取得(MT4表示と同じポイント単位)
      spread = MarketInfo(Symbol(), MODE_SPREAD);

      // スプレッドチェック(maxSpreadPoints=0 の場合はスキップ)
      if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
         Print("スプレッド拡大中(", spread,
               "ポイント) → 待機中 (リトライ=", retry+1, ")");
         Sleep(2000);
         continue;
      }

      // エントリー価格と色を決定
      if(orderType == OP_BUY){
         price = Ask;
         clr   = clrBlue;
      }else if(orderType == OP_SELL){
         price = Bid;
         clr   = clrRed;
      }

      ticket = OrderSend(Symbol(), orderType, lots, price,
                         20, sl, tp, orderComment, magic, 0, clr);

      if(ticket > 0){
         Print("新規注文成功! チケットNo=", ticket,
               " レート=", price, " Lots=", lots,
               " スプレッド=", spread, "ポイント");
         return true;
      }else{
         int err = GetLastError();
         Print("新規注文失敗 エラーNo=", err,
               " リトライ回数=", retry+1);
         Sleep(2000);
      }
   }

   return false;
}
 
//+------------------------------------------------------------------+
//|【関数】変更注文関数                                               |
//|                                                                  |
//|【引数】 ticket: 修正対象のチケットNo                              |
//|【引数】 sl: 新しい損切り価格                                      |
//|【引数】 tp: 新しい利確価格                                        |
//|【引数】 maxSpreadPoints: 許容スプレッド[Point] (0=制限なし)        |
//|                                                                  |
//|【戻値】true=成功 false=失敗                                       |
//+------------------------------------------------------------------+
bool funcOrder_Modify(int ticket, double sl, double tp, int maxSpreadPoints){
   double spread = 0;
   bool   result = false;

   // 注文選択
   if(!OrderSelect(ticket, SELECT_BY_TICKET)){
      Print("funcOrder_Modify: OrderSelect失敗 ticket=", ticket,
            " エラー=", GetLastError());
      return false;
   }
   //通貨が違う場合は変更しない
   if(OrderSymbol() != Symbol()){
       Print("funcOrder_Modify: シンボル不一致 ", OrderSymbol(), "≠", Symbol());
       return false;
   }

   // 最大10回リトライ
   for(int retry=0; retry<10; retry++)
   {
      RefreshRates();

      // スプレッド取得(MT4表示と同じポイント単位)
      spread = MarketInfo(Symbol(), MODE_SPREAD);

      // スプレッドチェック(maxSpreadPoints=0 の場合はスキップ)
      if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
         Print("スプレッド拡大中(", spread,
               "ポイント) → 修正待機中 (リトライ=", retry+1, ")");
         Sleep(2000);
         continue;
      }

      // 注文修正
      result = OrderModify(ticket,
                           OrderOpenPrice(),  // 価格は変更しない
                           sl,                // 新しい損切り
                           tp,                // 新しい利確
                           0,                 // 有効期限(変更しない)
                           clrNONE);

      if(result){
         Print("変更注文成功! チケットNo=", ticket,
               " 新SL=", sl, " 新TP=", tp,
               " スプレッド=", spread, "ポイント");
         return true;
      }else{
         int err = GetLastError();
         Print("変更注文失敗 ticket=", ticket,
               " エラーNo=", err,
               " リトライ回数=", retry+1);
         Sleep(2000);
      }
   }

   return false;
}
    
//+------------------------------------------------------------------+
//|【関数】全決済関数                                                 |
//|                                                                  |
//|【引数】 orderType : -1=すべて  0=BUYのみ  1=SELLのみ             |
//|【引数】 magic: 対象マジック番号 (-1=全マジック対象)               |
//|【引数】 maxSpreadPoints: 許容スプレッド[Point] (0=制限なし)       |
//|                                                                  |
//|【戻値】true=全成功 false=一部失敗あり                             |
//+------------------------------------------------------------------+
bool funcOrder_CloseAll(int orderType, int magic, int maxSpreadPoints){
   bool allSuccess = true;
   int totalOrders = OrdersTotal();
   double spread, closePrice, lots;
   int type, ticket;
   color  clr    = clrNONE;

   for(int i = totalOrders-1; i >= 0; i--)
   {
      //オーダーセレクト失敗でスキップ
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      
      // 同一シンボル以外はスキップ
      if(OrderSymbol() != Symbol()) continue;

      // マジック番号指定がある場合は一致しないものをスキップ
      if(magic != -1 && OrderMagicNumber() != magic) continue;

      type   = OrderType();
      ticket = OrderTicket();
      lots   = OrderLots();

      // orderType指定でフィルタ
      if(orderType == 0 && type != OP_BUY) continue;
      if(orderType == 1 && type != OP_SELL) continue;

      // 最大10回リトライ
      bool result = false;
      for(int retry=0; retry<10; retry++)
      {
         RefreshRates();

         // スプレッド取得
         spread = MarketInfo(Symbol(), MODE_SPREAD);

         if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
            Print("スプレッド拡大中(", spread,
                  "ポイント) → クローズ待機中 ticket=", ticket,
                  " リトライ=", retry+1);
            Sleep(2000);
            continue;
         }

         // クローズ価格決定
         if(type == OP_BUY){
            closePrice = Bid;
            clr   = clrBlue;
         }else if(type == OP_SELL){
            closePrice = Ask;
            clr   = clrRed;
         }

         result = OrderClose(ticket, lots, closePrice, 20, clr);

         if(result){
            Print("クローズ成功! チケットNo=", ticket,
                  " ロット=", lots, " クローズ価格=", closePrice,
                  " スプレッド=", spread, "ポイント");
            break;
         }else{
            int err = GetLastError();
            Print("クローズ失敗 ticket=", ticket,
                  " エラーNo=", err,
                  " リトライ=", retry+1);
            Sleep(2000);
         }
      }

      if(!result) allSuccess = false;
   }

   return allSuccess;
}
スポンサーリンク

ダウンロード

EAファイルのダウンロードはこちら👇

📥 MACDのEA【改良版】 をダウンロード

🔧 パラメータとカスタマイズ

今回のパラメータ設定は以下の通りです:

  • 取引ロット数(例:0.01 = 1,000通貨)
  • 利確幅(pips)
  • 損切幅(pips)
  • MACDファストEMA期間(例:12)
  • MACDスローEMA期間(例:26)
  • MACDシグナル期間(例:9)
  • 直近高値安値で損切りするか(trueの場合はする)
  • 参照するバー本数(損切りする場合の、確認直近バー本数)
    ※「直近高値安値で損切りするか」がtrueの場合のみ有効
  • 損切りラインに加える余裕(損切り+アルファで持たせるpips)
    ※「直近高値安値で損切りするか」がtrueの場合のみ有効

👉 『直近高値安値で損切りするか』設定をtrueにすることで、損切りラインを柔軟に設定可能となる

MT4でMACDのEAを改良する方法|決済条件をカスタマイズ【サンプルコード付】

まとめ

今回は「決済処理をカスタマイズする方法」をテーマに解説しました。

  • MACDクロス決済でトレンド転換を狙う
  • 高値安値損切りで自然な損切りラインを設定

MACD EAはエントリー条件だけでなく、決済条件を工夫することで挙動が大きく変わるのが特徴です。
自分のスタイルに合うように組み替えて、検証を重ねてみてください。

🛠️ EAを効率的にカスタマイズしたい方へ
▶ 【MT4 EAベースソース】を無料公開中!初心者でもすぐに使えます。


✅ 他にも多数のEAサンプルを公開中!

今回紹介した内容以外にも、当サイトではさまざまな
FX自動売買EAのサンプルコードを提供しています。

自分に合った戦略のEAを見つけたい方は、ぜひチェックしてみてください。


📊 【2025年最新】FX自動売買EAランキングも公開中!

当サイトの「どのEA(インジ)が実際に勝っているのか?」を知りたい方はこちら👇
PF(プロフィットファクター)や勝率で徹底比較した最新ランキングから、あなたに最適なEA(インジ)を見つけましょう。


EA開発初心者向けに、今後も実践的なMQL4関数を紹介していきます。
気になる機能やロジックがあれば、ぜひ他の記事もあわせてご覧ください!

コメント

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