含み益が伸びているとき、

「もう少しロットを増やしておけば」

と思ったことはないでしょうか。

増し玉(ピラミッディング)は、

うまくいけば利益を大きく伸ばせる手法ですが、

価格間隔だけを条件にして機械的に増やし続けると、

証拠金が足りなくなっていることに気づかないまま、

発注を続けてしまう危険があります。

この記事では、価格が一定幅動いたことに加えて、

その瞬間の証拠金維持率が安全な水域にあることも、

条件にする二重の安全装置付き増し玉EAの作り方を解説します。

この記事で分かること
・価格間隔だけの増し玉が危険な理由
・証拠金維持率を増し玉の「許可条件」として使う設計
・自分の注文だけを対象にした緊急決済ロジック
・既刊の増し玉EA・証拠金維持率EAとの違い

設計思想: なぜ価格間隔だけの増し玉は危険なのか

まず、このEAが解決する問題を整理します。

既刊のデルタ段階調整ピラミッディングEAとの違い

既刊のMQL5版ピラミッディングEAは、

価格が一定幅動くことだけを条件に増減させる設計でした。

この記事の設計方針: 価格条件と資金条件のAND判定

メリット
・価格が有利に動いているという「勢いの条件」
・証拠金維持率が十分高いという「資金の条件」
・両方を満たしたときだけ増し玉を許可する

この記事のEAは、価格条件(InpStepPoints分動いたか)と、

資金条件(証拠金維持率がInpMinMarginLevelToAdd以上か)の、

両方を満たした場合だけ増し玉を実行します。

既刊の証拠金維持率ストップEAとの違い

既刊の証拠金維持率ストップEAは、

危険水域で「口座内の全ポジションを無差別に決済」する設計でした。

注意
・既刊EAは自分のEA以外のポジションも区別せず決済する弱点があった
・本記事のEAは、決済対象を自分のマジックナンバーの注文だけに限定する
・同じ口座で他のEAや手動トレードを行っていても誤って巻き込まない

証拠金維持率の取得とタイミング

既刊の証拠金維持率インジケーター・EAと同じ関数で、

維持率を取得します。

AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)で取得する

double marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);

この値は「有効証拠金÷必要証拠金×100」を、

MQL4側があらかじめ計算した値です。

ポジションが無いときは判定しない

必要証拠金が0のとき、この値は意味を持たなくなるため、

自分の注文が1件も無い状態では維持率判定を行わず、

最初の1件目の発注だけを行います。

増し玉の段階(レベル)を数える設計

MQL4には口座を1本のポジションにまとめる仕組み(ネッティング)がないため、

増し玉のたびに新しい注文が並存します。

自分のマジックナンバーの注文だけを数える

int CountMyOrders()
  {
   int count = 0;
   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
            count++;
        }
     }
   return(count);
  }

同じ口座で他のEAや手動注文が動いていても、

マジックナンバーで自分の注文だけを区別します。

最後に増し玉した価格を取得する

double GetLatestOpenPrice()
  {
   datetime latest = 0;
   double   price  = 0;

   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
           {
            if(OrderOpenTime() > latest)
              {
               latest = OrderOpenTime();
               price  = OrderOpenPrice();
              }
           }
        }
     }
   return(price);
  }

最後に増し玉した注文の始値を基準に、

次の増し玉タイミングを判定します。

注文が無くなったら段階もリセットされる

自分の注文を1件も持たない状態になれば、

CountMyOrdersは自動的に0を返すため、

次のティックでは最初の1件目として新たに増し玉を開始できます。

緊急決済: 自分の注文だけを対象にする

危険水域に達したときの、安全な決済処理を組み立てます。

自分のマジックナンバーの注文だけ決済する

void CloseMyOrders()
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol() != _Symbol || OrderMagicNumber() != InpMagicNumber) continue;

      double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
      bool ok = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrYellow);

      if(!ok)
         Print("緊急決済に失敗しました。チケット=", OrderTicket(), " エラーコード=", GetLastError());
     }
  }

既刊の全決済EAと同じく、

添字の大きい方からループを回します。

緊急水域は増し玉を許可する水域より低く設定する

InpEmergencyMarginLevelは、

InpMinMarginLevelToAddより必ず低い値に設定します。

増し玉の判定が先に止まり、それでも維持率が下がり続けた場合だけ、

緊急決済が実行される二段構えです。

実際に動くコード全体

価格条件・資金条件・緊急決済まで組み込んだ、

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

先に注意
・このコードは買い方向のみの実装です
・実運用では自分のエントリーシグナルと組み合わせてください
・デモ口座で十分に検証してから使ってください
//+------------------------------------------------------------------+
//|                              MarginLevelIntervalPyramidingEA.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 double InpLots                  = 0.01;  //1段階あたりの発注ロット数
input int    InpStepPoints            = 150;   //増し玉を判定する価格の刻み幅(ポイント)
input int    InpMaxLevels             = 4;     //最大の増し玉段階数
input double InpMinMarginLevelToAdd   = 300.0; //この維持率(%)以上でのみ増し玉を許可する
input double InpEmergencyMarginLevel  = 150.0; //この維持率(%)を割ったら自分の注文だけ緊急決済する
input int    InpStopLossPoints        = 300;   //各注文の損切り幅(ポイント)
input int    InpMagicNumber           = 20261027;

int CountMyOrders()
  {
   int count = 0;
   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
            count++;
        }
     }
   return(count);
  }

double GetLatestOpenPrice()
  {
   datetime latest = 0;
   double   price  = 0;

   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
           {
            if(OrderOpenTime() > latest)
              {
               latest = OrderOpenTime();
               price  = OrderOpenPrice();
              }
           }
        }
     }
   return(price);
  }

void CloseMyOrders()
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol() != _Symbol || OrderMagicNumber() != InpMagicNumber) continue;

      double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
      bool ok = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrYellow);

      if(!ok)
         Print("緊急決済に失敗しました。チケット=", OrderTicket(), " エラーコード=", GetLastError());
     }
  }

void OnTick()
  {
   int level = CountMyOrders();
   double marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);

   if(level > 0 && marginLevel > 0 && marginLevel <= InpEmergencyMarginLevel)
     {
      Comment("証拠金維持率が緊急水域(", DoubleToString(marginLevel, 1),
              "%)のため自分の注文のみ決済します");
      CloseMyOrders();
      return;
     }

   if(level == 0)
     {
      double sl = Ask - InpStopLossPoints * Point;
      int ticket = OrderSend(_Symbol, OP_BUY, InpLots, Ask, 3, sl, 0,
                              "MarginPyramidEA", InpMagicNumber, 0, clrBlue);
      if(ticket >= 0)
         Comment("1段階目を発注しました");
      return;
     }

   if(level >= InpMaxLevels)
     {
      Comment("最大段階数(", InpMaxLevels, ")に達しました。増し玉を停止します");
      return;
     }

   if(marginLevel < InpMinMarginLevelToAdd)
     {
      Comment("証拠金維持率が", DoubleToString(marginLevel, 1),
              "%のため増し玉を見送ります(基準:", InpMinMarginLevelToAdd, "%)");
      return;
     }

   double lastPrice = GetLatestOpenPrice();
   double stepPrice = InpStepPoints * Point;

   if(Bid >= lastPrice + stepPrice)
     {
      double sl = Ask - InpStopLossPoints * Point;
      int ticket = OrderSend(_Symbol, OP_BUY, InpLots, Ask, 3, sl, 0,
                              "MarginPyramidEA", InpMagicNumber, 0, clrBlue);
      if(ticket >= 0)
         Comment("増し玉を実行しました(", level + 1, "段階目)");
     }
   else
     {
      Comment("現在", level, "段階目。次の増し玉まで",
              DoubleToString((lastPrice + stepPrice - Bid) / Point, 0), "ポイント");
     }
  }

MetaEditorでのコンパイル・実行手順

実際にMT4で動かすまでの手順です。

  1. MetaEditorで新規EA「MarginLevelIntervalPyramidingEA」を作成し、上のコードを貼り付けてコンパイルする
  2. エラー・警告が0件であることを確認する
  3. デモ口座のチャートに適用し、コメント欄に段階数と次の増し玉までの距離が表示されることを確認する
  4. InpMinMarginLevelToAddを一時的に高い値(例: 100000)にして、増し玉が見送られることを確認する
  5. InpEmergencyMarginLevelを一時的に高い値にして、自分の注文だけが決済されることを確認する
  6. 確認後は想定する運用値に戻す

よくあるエラーと注意点

実装・運用でつまずきやすいポイントをまとめます。

InpMinMarginLevelToAddはInpEmergencyMarginLevelより高くする

注意
・InpMinMarginLevelToAddが緊急水域より低いと
・増し玉を許可する基準が緊急決済の基準を下回ってしまい
・安全装置として機能しなくなる

増し玉を重ねるほど1段階分の損益額が大きくなる

InpLotsは段階が増えても一定のため、

合計ロットは段階数に比例して増えます。

想定する最大合計ロット(InpLots×InpMaxLevels)に、

必要な証拠金を事前に試算してください。

端末再起動で段階カウントは失われない

このEAは注文自体をOrdersTotalループで数え直すため、

MT4を再起動しても、保有中の注文から段階数を正しく復元できます。

既刊EAとの使い分け

似た目的の記事が複数あるため、使い分けを整理します。

記事 方向 増し玉の安全条件 決済対象
本記事 増やす 価格間隔+証拠金維持率のAND判定 自分のマジックナンバーのみ
デルタ段階調整EA(既刊、MQL5) 増やす/縮める 価格間隔のみ 自分のポジションのみ
証拠金維持率ストップEA(既刊) 決済のみ (該当なし) 口座内の全注文

よくある質問

証拠金維持率×増し玉EAについて、よくある疑問に回答します。

売り方向にも対応させられますか?

対応できます。OP_BUYをOP_SELLに、AskをBidに、

価格条件の不等号(>=を<=に)を反転させれば、

同じ考え方で売り方向を作れます。

InpMinMarginLevelToAddはいくつに設定すればいいですか?

増し玉を続けても証拠金に十分な余裕が残る水準が目安です。

最大合計ロットに必要な証拠金を試算し、

その2〜3倍程度の維持率を確保できる値から調整することをおすすめします。

GlobalVariableで段階数を保存する必要はありますか?

このEAは注文自体を毎回数え直す設計のため、

GlobalVariableは不要です。

ただし「最後に増し玉した時刻」など、

注文に残らない情報を保存したい場合は、

既刊のGlobalVariableSet/GlobalVariableGetの、

記事を参考にしてください。

【MQL4】証拠金維持率と価格の値動きを両方の条件にした安全な増し玉(ピラミッディング)EAの作り方:まとめ

価格間隔だけを条件にした増し玉は、

証拠金が圧迫されていることに気づかないまま発注を続ける危険があります。

価格条件と証拠金維持率の条件をAND判定にすることで、

資金に余裕がないときは自動的に増し玉を見送る設計にできます。

さらに緊急水域では、他のEAや手動注文を巻き込まず、

自分の注文だけを安全に決済します。

関連記事