移動平均のゴールデンクロス・デッドクロスでエントリーするEAは、

シンプルで分かりやすい反面、「トレンドがもう伸び切った位置」

でクロスが出た場合でも、条件さえ満たせば機械的にエントリーしてしまいます。

ゴールデンクロス・デッドクロスEAの記事でも触れたとおり、クロス自体は「トレンドが変わったかもしれない」

というだけの情報で、「今エントリーして伸びしろがあるか」までは教えてくれません。

この記事では、iDeMarkerが示す「過熱度」を使い、すでに価格が伸び切っている局面ではクロスが出ても新規エントリーを止める、

「エントリーを絞る」設計のEAを作ります。

設計思想: DeMarkerを『逆張りシグナル』ではなく『順張りのブレーキ』に使う

DeMarkerは0〜1の範囲で動く指標で、0.7以上は「買われすぎ」

、0.3以下は「売られすぎ」の目安とされます。

iDeMarkerの記事では、この閾値を0.7→0.3のクロスとして「逆張りの合図」

に使う例を紹介しました。

この記事では逆の使い方をします。

DeMarkerを逆張りのエントリー根拠にするのではなく、

順張り(移動平均クロス)のエントリーに対して、

「今は過熱しているので新規で追いかけるのは危険」と判断させる、

ブレーキ役として使います。

具体的には、ゴールデンクロスが出ても、

その時点のDeMarkerがすでに0.7以上(買われすぎ)なら、

買いエントリーを見送り、デッドクロスが出ても、

DeMarkerがすでに0.3以下(売られすぎ)なら、

売りエントリーを見送ります。

この設計にした理由は、

クロスが出るタイミングと相場が過熱するタイミングは、

トレンドの終盤ほど重なりやすいためです。

移動平均が長めの期間だと、

クロスの確定自体が価格の動きに遅れて出るため、

「クロスが出た頃には既に一段伸びた後」という状況が起きやすく、

そこへDeMarkerの過熱フィルターを重ねることで、

質の低いエントリーを機械的に間引きます。

ベースのエントリー条件: 移動平均のゴールデンクロス・デッドクロス

エントリーの土台は、

確定足(1本前)で短期移動平均が長期移動平均を上抜け/下抜けしたかどうかで判定します。

bool IsGoldenCross(int shift)
  {
   double fastNow  = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double fastPrev = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);
   double slowNow  = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double slowPrev = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);

   return(fastPrev <= slowPrev && fastNow > slowNow);
  }

bool IsDeadCross(int shift)
  {
   double fastNow  = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double fastPrev = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);
   double slowNow  = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double slowPrev = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);

   return(fastPrev >= slowPrev && fastNow < slowNow);
  }

フィルター関数: DeMarkerが過熱域にあるかを判定する

こちらも確定足のDeMarker値で判定します。

形成中の足の値は計算途中で変動するため、

フィルターの判定には使いません(この考え方も既存のiDeMarker記事と同じです)。

bool IsOverheatedForBuy(int shift)
  {
   double dm = iDeMarker(NULL,0,DeMarkerPeriod,shift);
   return(dm >= DeMarkerUpperLimit);//0.7以上=買われすぎ、新規買いを見送る
  }

bool IsOverheatedForSell(int shift)
  {
   double dm = iDeMarker(NULL,0,DeMarkerPeriod,shift);
   return(dm <= DeMarkerLowerLimit);//0.3以下=売られすぎ、新規売りを見送る
  }

実際に動くコード全体

移動平均クロスでエントリー方向を判定し、

DeMarkerが過熱域にある場合だけそのエントリーを見送る、

実際にMetaEditorでコンパイルできるEAです。

//+------------------------------------------------------------------+
//|                                    MaCrossDeMarkerFilterEA.mq4    |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link      "https://creator.fx-ea-system-project.com/"
#property version   "1.00"
#property strict

input int    MagicNumber      = 56789;//マジックナンバー
input double Lots             = 0.01;//ロット数
input int    FastMaPeriod     = 5;//短期移動平均の期間
input int    SlowMaPeriod     = 20;//長期移動平均の期間
input int    DeMarkerPeriod   = 14;//DeMarkerの期間
input double DeMarkerUpperLimit = 0.7;//これ以上なら買われすぎ(買い見送り)
input double DeMarkerLowerLimit = 0.3;//これ以下なら売られすぎ(売り見送り)
input int    StopLossPips     = 30;//損切り(pips)
input int    TakeProfitPips   = 60;//利確(pips)
input int    Slippage         = 3;//スリッページ

//+------------------------------------------------------------------+
//| このEA(マジックナンバー)の保有ポジション数を返す                   |
//+------------------------------------------------------------------+
int CountMyOrders()
  {
   int count = 0;
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
         count++;
     }
   return(count);
  }

//+------------------------------------------------------------------+
//| 確定足(shift)で短期MAが長期MAを上抜けしたか                       |
//+------------------------------------------------------------------+
bool IsGoldenCross(int shift)
  {
   double fastNow  = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double fastPrev = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);
   double slowNow  = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double slowPrev = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);

   return(fastPrev <= slowPrev && fastNow > slowNow);
  }

//+------------------------------------------------------------------+
//| 確定足(shift)で短期MAが長期MAを下抜けしたか                       |
//+------------------------------------------------------------------+
bool IsDeadCross(int shift)
  {
   double fastNow  = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double fastPrev = iMA(NULL,0,FastMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);
   double slowNow  = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift);
   double slowPrev = iMA(NULL,0,SlowMaPeriod,0,MODE_SMA,PRICE_CLOSE,shift+1);

   return(fastPrev >= slowPrev && fastNow < slowNow);
  }

//+------------------------------------------------------------------+
//| 確定足(shift)のDeMarkerが買われすぎ域か                           |
//+------------------------------------------------------------------+
bool IsOverheatedForBuy(int shift)
  {
   double dm = iDeMarker(NULL,0,DeMarkerPeriod,shift);
   return(dm >= DeMarkerUpperLimit);
  }

//+------------------------------------------------------------------+
//| 確定足(shift)のDeMarkerが売られすぎ域か                           |
//+------------------------------------------------------------------+
bool IsOverheatedForSell(int shift)
  {
   double dm = iDeMarker(NULL,0,DeMarkerPeriod,shift);
   return(dm <= DeMarkerLowerLimit);
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CountMyOrders() > 0) return;//このEAの保有ポジションが既にあれば新規エントリーしない

   int shift = 1;//直近の確定足で判定する

   if(IsGoldenCross(shift))
     {
      if(IsOverheatedForBuy(shift))
        {
         Print("ゴールデンクロス検出も、DeMarker=",DoubleToString(iDeMarker(NULL,0,DeMarkerPeriod,shift),3),
               "が買われすぎ域のため買いエントリーを見送りました。");
        }
      else
        {
         double sl = Bid - StopLossPips*Point*10;
         double tp = Ask + TakeProfitPips*Point*10;
         int result = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,sl,tp,"MA Cross DM Filter Buy",MagicNumber,0,Blue);
         if(result < 0)
            Print("買い注文に失敗しました。エラーコード=",GetLastError());
        }
     }

   if(IsDeadCross(shift))
     {
      if(IsOverheatedForSell(shift))
        {
         Print("デッドクロス検出も、DeMarker=",DoubleToString(iDeMarker(NULL,0,DeMarkerPeriod,shift),3),
               "が売られすぎ域のため売りエントリーを見送りました。");
        }
      else
        {
         double sl = Ask + StopLossPips*Point*10;
         double tp = Bid - TakeProfitPips*Point*10;
         int result = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,sl,tp,"MA Cross DM Filter Sell",MagicNumber,0,Red);
         if(result < 0)
            Print("売り注文に失敗しました。エラーコード=",GetLastError());
        }
     }
  }
//+------------------------------------------------------------------+

MetaEditorで実際に動かす手順

  1. MT4のMetaEditorで「ファイル」→「新規作成」→「Expert Advisor(テンプレートを使用)」を選び、名前を「MaCrossDeMarkerFilterEA」にして作成する
  2. テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
  3. F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  4. デモ口座のチャートへドラッグ&ドロップし、ストラテジーテスターの「エキスパート」タブで、DeMarkerが過熱域にあるときクロスが出てもエントリーが見送られ、ログに理由が出力される様子を確認する

この設計の限界

DeMarkerフィルターは「今の水準が過熱しているかどうか」

しか見ていないため、

強いトレンドが続く相場では、DeMarkerが0.7以上に張り付いたまま、

価格がさらに伸び続けることがあります。

このEAはその局面での新規エントリーを一貫して見送るため、

強いトレンド相場での取りこぼし(機会損失)が、

レンジ相場での質の低いエントリー回避と引き換えに発生します。

また、このコードは移動平均クロスというシンプルな順張り条件のみを土台にしており、

複数の時間足や別の指標を組み合わせた環境認識は行っていません。

フィルターを厳しくしすぎる(閾値を0.6/0.4のように狭める)と、

エントリー自体がほとんど発生しなくなる点にも注意してください。

コピペしてコンパイルが通らない・想定と違う結果になるときに確認すること

  • エントリーが一切発生しない: `DeMarkerUpperLimit`/`DeMarkerLowerLimit`を極端な値(0.55/0.45等)に変更していないか確認する。デフォルトの0.7/0.3でもトレンドが弱い相場では両方の条件が重ならずエントリーが減ることがある
  • クロス自体は出ているのにエントリーされない: エキスパートタブのログに「買われすぎ域のため見送りました」等のメッセージが出ていないか確認する。これは事故ではなく設計通りの挙動
  • OrderSendがエラーコード130(Invalid stops)で失敗する: `StopLossPips`がブローカーの最小ストップ距離(MODE_STOPLEVEL)より小さくないか確認する(gc-dc.mdのエラー130解説を参照)
  • `iDeMarker`や`iMA`が0を返す: `DeMarkerPeriod`/`FastMaPeriod`/`SlowMaPeriod`にヒストリーデータが十分読み込まれていない可能性がある。チャートを開いて過去に十分スクロールしてから再実行する

まとめ

移動平均クロスは分かりやすい反面、

トレンドが伸び切った局面でも機械的にエントリーしてしまう弱点があります。

この記事では、iDeMarkerを逆張りシグナルとしてではなく、

「過熱しているときだけ新規エントリーを止める」ブレーキ役として使うことで、

エントリー回数を減らしてでも質を上げる設計のEAを作りました。

強いトレンド相場では取りこぼしが増える点を理解した上で、

デモ口座で閾値(0.7/0.3)を調整しながら、

自分の取引する通貨ペア・時間足に合う設定を探してみてください。

関連記事