ナンピンでトレードするEAの記事や、ナンピンマーチンEAの記事では、

「意図してナンピンする」EAの作り方を解説しました。

ですがナンピンで危険なのは、こうした計画的なEAよりもむしろ、

裁量トレードで含み損を抱えたときに、「ちょっとだけ」

「今度こそ戻るはず」と手動で買い増してしまう、無計画なナンピンの方です。

含み損を2段階でLINE通知するEAの記事は、まさにこの状況を検知して知らせる設計でしたが、

通知は所詮「知らせるだけ」であり、感情的になっている本人が通知を無視してしまえば、

ポジションはそのまま増え続けます。

この記事では、通知の一歩先に踏み込み、

同じ方向のポジション数が自分で決めた上限を超えた瞬間、

直近に追加した1本を機械的に強制決済する「ナンピン抑止EA」

のアイデアを解説します。

設計思想: なぜ”通知”ではなく”強制決済”にしたのか

floating-loss-line-alert-ea.mdのEAは、

含み損が警告・危険ラインを超えたことを知らせるだけで、

その後どう行動するかは完全にトレーダー本人に委ねられていました。

これは「維持率や含み損の状況を把握したい」という用途では十分ですが、

「ナンピンをやめる」という行動そのものを守る用途では力不足です。

なぜなら、ナンピンをしている最中の人ほど、通知を見ても「あと1回だけ」

と考えてしまいがちだからです。

この記事のEAは、通知ではなく、同方向のポジション数という客観的な事実だけを基準に、

トレーダーの判断を待たずに機械的に介入します。

「今回は特別」という言い訳が入り込む余地を、

そもそもEA側の判断ルールから排除する設計です。

設計思想: なぜ”直近の1本”だけを閉じるのか

上限を超えた分をまとめて全決済する設計も考えられますが、

この記事のEAは上限を1本超えるたびに、

最も新しく開いたポジションだけを閉じ、上限本数までポジションが減ったところで止めます。

理由は2つあります。

1つ目は、最初のエントリーまで巻き込んで全決済すると、

本来の戦略に基づく最初のポジションまで強制的に手仕舞いさせてしまい、

「ナンピンを止める」という目的を超えて過剰な介入になるためです。

2つ目は、「直近に追加した分だけが機械的に消える」という一貫した挙動の方が、

トレーダー自身が「このEAが動いている間はナンピンできない」

という前提を学習しやすいためです。

パラメーターの説明

input int MaxPositionsPerDirection = 2;//同方向で許可する最大ポジション数
input int TargetMagicNumber        = 0;//監視対象のマジックナンバー(0=裁量トレード)
input bool MonitorAllMagicNumbers  = false;//trueにするとマジックナンバーを問わず全ポジションを監視
input int  Slippage                = 3;//強制決済時のスリッページ

`TargetMagicNumber`を`0`(初期値)のままにすると、

裁量トレード(EAを使わない手動注文)のポジションだけを監視対象にします。

複数のEAを同じ口座で並行稼働させている場合、

他のEAの正当な複数ポジション戦略まで誤って強制決済しないよう、

`MonitorAllMagicNumbers`は、

初期値`false`のままにしておいてください。

実際に動くコード全体

同方向のポジション数を数え、上限を超えるたびに直近の1本を強制決済する、

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

//+------------------------------------------------------------------+
//|                                          NampinStopper-EA.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  MaxPositionsPerDirection = 2;//同方向で許可する最大ポジション数
input int  TargetMagicNumber        = 0;//監視対象のマジックナンバー(0=裁量トレード)
input bool MonitorAllMagicNumbers   = false;//trueにするとマジックナンバーを問わず全ポジションを監視
input int  Slippage                 = 3;//強制決済時のスリッページ

//+------------------------------------------------------------------+
//| このポジションが監視対象かどうかを判定する                        |
//+------------------------------------------------------------------+
bool IsTargetPosition()
  {
   if(OrderSymbol() != Symbol())
      return(false);
   if(MonitorAllMagicNumbers)
      return(true);
   return(OrderMagicNumber() == TargetMagicNumber);
  }

//+------------------------------------------------------------------+
//| 指定した方向(OP_BUY/OP_SELL)のポジション数が上限を超えている間、  |
//| 最も新しく開いたポジションを1本ずつ強制決済する                    |
//+------------------------------------------------------------------+
void EnforceLimit(int orderType)
  {
   while(true)
     {
      int      count      = 0;
      int      newestIndex = -1;
      datetime newestTime  = 0;

      for(int i = 0; i < OrdersTotal(); i++)
        {
         if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
            continue;
         if(!IsTargetPosition())
            continue;
         if(OrderType() != orderType)
            continue;

         count++;
         if(OrderOpenTime() > newestTime)
           {
            newestTime  = OrderOpenTime();
            newestIndex = i;
           }
        }

      if(count <= MaxPositionsPerDirection)
         break;//上限以下になったので終了
      if(newestIndex < 0)
         break;//念のための安全策(通常は到達しない)

      if(!OrderSelect(newestIndex, SELECT_BY_POS, MODE_TRADES))
         break;

      int    ticket     = OrderTicket();
      double lots       = OrderLots();
      double closePrice = (orderType == OP_BUY) ? Bid : Ask;

      if(OrderClose(ticket, lots, closePrice, Slippage, clrRed))
        {
         Alert("ナンピン抑止EA: 同方向ポジションが上限(", MaxPositionsPerDirection,
               "本)を超えたため、直近のポジション(#", ticket, ")を強制決済しました。");
        }
      else
        {
         Print("強制決済に失敗しました。チケット=", ticket, " エラーコード=", GetLastError());
         break;//無限ループを避けるため、失敗時はこのティックでの処理を打ち切る
        }
     }
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   EnforceLimit(OP_BUY);
   EnforceLimit(OP_SELL);
  }
//+------------------------------------------------------------------+

MetaEditorで実際に動かす手順

  1. MT4の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
  2. 「ファイル」→「新規作成」→「Expert Advisor(テンプレートを使用)」を選び、名前を「NampinStopper-EA」にして作成する
  3. テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
  4. F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  5. デモ口座のチャートへドラッグ&ドロップし、まず`MaxPositionsPerDirection=1`のような厳しい設定で、手動で同方向のポジションを2本以上建てて意図通りに1本だけ強制決済されるか確認する

この設計の限界

このEAには、通知型のEAにはない、いくつかの構造的な限界があります。

1つ目は、このEAがチャートに読み込まれて動いている間しか機能しないことです。

EAを外している間、あるいはMT4自体を起動していない間に手動で追加したポジションは、

次にEAが動き出した時点で初めて検知され、その場で強制決済されます。

「今だけEAを外してナンピンする」という回避策自体は技術的に防げません。

2つ目は、強制決済のたびにスプレッドや多少のスリッページというコストが発生することです。

上限をぎりぎりの本数に設定していると、

相場の小さな上下動だけで決済と再エントリーを繰り返し、

意図せずコストがかさむ可能性があります。

`MaxPositionsPerDirection`は、

自分が許容できる本数より少し余裕を持たせた値から始めることを推奨します。

コピペしてコンパイルが通らない・意図通りに決済されないときに確認すること

  • 強制決済が一切発生しない: `TargetMagicNumber`が実際の裁量トレードのマジックナンバー(通常は0)と一致しているか確認する。他のEAのマジックナンバーを誤って指定していないか
  • 他のEAのポジションまで決済されてしまう: `MonitorAllMagicNumbers`が誤って`true`になっていないか確認する
  • OrderClose()が失敗し続ける(エラーコード129・135等): デモ口座の通信遅延やスプレッド拡大時に発生しやすい。`Slippage`の値を大きくして再試行する
  • 決済されたはずのポジションがまだ残って見える: MT4の「口座履歴」タブでは決済済み注文として記録されるため、「取引」タブだけを見ていると反映が遅れて見えることがある

まとめ

含み損の通知だけでは、感情的になっているときには行動を止められないことがあります。

この記事では、同方向のポジション数という客観的な基準だけで、

トレーダーの判断を待たずに直近の1本を機械的に強制決済するEAのアイデアを解説しました。

ただしこのEAは、EAが動いている間しか機能しないという限界もあります。

floating-loss-line-alert-ea.mdの通知型EAと組み合わせ、

「まず知らせる、それでも増えたら強制的に止める」

という二段構えの仕組みにすることも検討してみてください。

関連記事