MQL5 Multi-Logic EA設計を実コードで解説|LogicSlot・Magic Number・Snapshotを分ける理由

EAファンクラブ

MQL5でEAを拡張していくと、1つのEA内に複数のロジックを入れたくなる場面があります。

たとえば、順張りロジック、逆張りロジック、時間足違いのロジック、買い専用・売り専用ロジック、検証中の追加ロジックなどです。しかし、複数ロジックを1本のEAへ入れる場合、単に条件式を増やすだけでは危険です。

Magic Numberが混ざる、どのロジックのポジションか分からなくなる、決済対象を間違える、同じポジションを複数ロジックが管理してしまう、検証OFFのロジックが実売買へつながる。このような問題を避けるには、LogicSlot・Magic Number・Snapshot・Close Scopeを分けて設計する必要があります。

この記事では、MQL5のMulti-Logic EA設計を、学習用に一般化したコード断片で解説します。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開しません。

この記事で扱う範囲

項目この記事で扱う内容扱わない内容
目的複数ロジックEAで、ロジックごとの状態・Magic・Snapshotを分ける設計利益を狙う売買ロジック、具体的なエントリー条件
主な構造LogicSlot、Magic Number、Position Snapshot、Close Scope独自優位性のある判定式、実運用set値
コード例学習用に簡略化した短いコード断片完成EAソース全文、実運用コード全文
確認対象logic_id、magic、trade_route、position_count、close_scope、audit log認証、外部制御、口座許可、外部シート制御
読者MQL5開発者、EA改修依頼前に複数ロジック化を整理したい人売買判断や推奨設定を知りたい人

Multi-Logic EAとは

Multi-Logic EAとは、1つのEA内で複数の売買ロジックや管理単位を扱う設計です。

ただし、複数の条件式を1つのOnTick内へ並べるだけでは、Multi-Logic EAとしては不十分です。ロジックごとに、設定、状態、Magic Number、ポジション集計、実行可否、決済対象を分ける必要があります。

分ける項目理由
Logic IDどのロジックの処理かログで追えるようにする
Magic Number注文・ポジションをロジック単位で識別する
Runtime Stateロジックごとの有効・無効、停止理由、実行可否を分ける
Position Snapshotロジックごとの保有数、ロット、損益、方向を集計する
Close Scope決済対象を他ロジックへ広げない
Audit Log実売買前に、どのロジックが何を判断したか確認する

複数ロジック化で最も避けたいのは、ロジック追加によって既存ロジックの発注・決済・リスク管理が混線することです。

LogicSlotでロジック単位を固定する

LogicSlotとは、1つのロジックを管理するための単位です。

LogicSlotには、少なくとも次の情報を持たせます。

  • logic_id
  • 表示名
  • 有効・無効
  • Magic Number
  • trade routeの有効・無効
  • 現在の停止理由
  • ポジション集計結果

このようにロジック単位を明示すると、Logic1は稼働中、Logic2は監査のみ、Logic3は未接続、というように段階を分けて検証できます。

Magic Numberをロジックごとに分ける理由

Magic Numberは、EAが発注した注文やポジションを識別するために使います。

複数ロジックEAで同じMagic Numberを使い回すと、次のような問題が起きます。

問題内容
ポジション集計が混ざるLogic1のポジションとLogic2のポジションを区別できない
誤決済が起きるLogic2がLogic1のポジションを閉じる可能性がある
リスク管理が混ざるロジック別の最大保有数や損益集計が崩れる
ログ追跡が難しくなるどのロジックが発注したものか分からなくなる
検証結果が曖昧になるロジック別の成績や失敗理由を切り分けにくい

Multi-Logic EAでは、原則としてロジックごとに一意のMagic Numberを持たせます。

Position Snapshotを分ける理由

Position Snapshotとは、現在のポジション状態を集計した一時的な状態情報です。

複数ロジックEAでは、チャート全体のポジションだけでなく、LogicSlotごとのポジション状態を作ることが重要です。

たとえば、Logic1はBUYを1本保有中、Logic2はノーポジション、Logic3はSELLを1本保有中、という状態を分けて確認できる必要があります。

Snapshot項目確認する理由
position_count対象ロジックの保有数を確認する
buy_count / sell_count方向別の保有状態を確認する
total_volumeロジック別の合計ロットを確認する
floating_profitロジック別の含み損益を確認する
has_position新規Entryや管理決済の前提に使う
magicどのMagic Numberで集計したか確認する

Snapshotを分けずに全体ポジションだけを見ていると、ロジックごとの判定や決済対象を誤りやすくなります。

trade_routeを段階的に接続する

複数ロジックEAでは、新しいロジックを作った直後に実売買へ接続しない方が安全です。

推奨される段階は次の通りです。

段階状態確認内容
definedLogicSlotだけ定義logic_id、name、magicが重複していないか
snapshot onlyポジション集計のみ対象ポジションを正しく集計できるか
audit only判定結果をログに出すだけsignal候補やblock理由が追えるか
pre-route gate実行前ガードだけ確認spread、保有上限、重複制御などが機能するか
trade route enable実売買へ接続order送信、retcode、Magic、position反映を確認する

この段階を飛ばすと、未検証のロジックが実売買へつながり、既存ロジックへ影響する可能性があります。

Close Scopeを分ける理由

複数ロジックEAでは、決済対象の範囲も明確に分ける必要があります。

たとえば、Logic1のTrail決済がLogic2のポジションを閉じてはいけません。Logic2のシグナルExitがLogic1のポジションを閉じるのも危険です。

そのため、決済処理では次のようなscopeを確認します。

  • 対象symbolが一致しているか
  • 対象Magic Numberが一致しているか
  • 対象方向が一致しているか
  • 対象Logic IDとPosition Snapshotが一致しているか
  • close対象が現在のLogicSlotの範囲内か

Close Scopeを設計しておくと、決済処理を追加しても他ロジックのポジションを巻き込みにくくなります。

実コード断片1:LogicSlot定義

以下は、実際のEAで使う考え方を学習用に簡略化したコード例です。完成EAのソース全文ではなく、構造を理解するための抜粋です。

// 学習用に一般化したLogicSlot定義例です。
// 実運用EAの完成ソースではありません。

struct LogicSlot
{
   int    id;
   string name;
   long   magic;
   bool   enabled;
   bool   tradeRouteEnabled;
   string runtimeReason;
};

#define LOGIC_COUNT 3

LogicSlot g_logicSlots[LOGIC_COUNT];

void InitLogicSlots()
{
   g_logicSlots[0].id = 1;
   g_logicSlots[0].name = "Logic1";
   g_logicSlots[0].magic = 910001;
   g_logicSlots[0].enabled = true;
   g_logicSlots[0].tradeRouteEnabled = true;
   g_logicSlots[0].runtimeReason = "OK";

   g_logicSlots[1].id = 2;
   g_logicSlots[1].name = "Logic2";
   g_logicSlots[1].magic = 910002;
   g_logicSlots[1].enabled = true;
   g_logicSlots[1].tradeRouteEnabled = false;
   g_logicSlots[1].runtimeReason = "AUDIT_ONLY";

   g_logicSlots[2].id = 3;
   g_logicSlots[2].name = "Logic3";
   g_logicSlots[2].magic = 910003;
   g_logicSlots[2].enabled = false;
   g_logicSlots[2].tradeRouteEnabled = false;
   g_logicSlots[2].runtimeReason = "DISABLED";
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
LogicSlotロジック単位の設定と状態をまとめる
idログや管理で使うロジックID
magic注文・ポジション識別用のMagic Number
enabledロジック自体の有効・無効
tradeRouteEnabled実売買へ接続するかどうか
runtimeReason現在の状態理由をログで確認する

Logic2のように、ロジックは有効でも実売買は無効にし、audit onlyとしてログ確認だけ行う段階を作れます。

実コード断片2:Magic Number重複を確認する

以下は、LogicSlotごとのMagic Numberが重複していないか確認する学習用コード例です。

// 学習用に一般化したMagic重複チェック例です。
// 実運用EAの完成ソースではありません。

bool ValidateLogicMagicNumbers()
{
   for(int i = 0; i < LOGIC_COUNT; i++)
   {
      if(g_logicSlots[i].magic <= 0)
      {
         Print("DIAG/LOGIC: event=VALIDATION_FAIL",
               " logic=", g_logicSlots[i].name,
               " reason=INVALID_MAGIC");
         return false;
      }

      for(int j = i + 1; j < LOGIC_COUNT; j++)
      {
         if(g_logicSlots[i].magic == g_logicSlots[j].magic)
         {
            Print("DIAG/LOGIC: event=VALIDATION_FAIL",
                  " reason=DUPLICATE_MAGIC",
                  " logic_a=", g_logicSlots[i].name,
                  " logic_b=", g_logicSlots[j].name);
            return false;
         }
      }
   }

   Print("DIAG/LOGIC: event=VALIDATION_OK",
         " reason=UNIQUE_MAGIC");

   return true;
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
magic <= 0不正なMagic Numberを検出する
二重ループLogicSlot間のMagic重複を確認する
DUPLICATE_MAGICロジック間の識別衝突をログに残す
VALIDATION_OKMagic Numberが一意であることを確認する

Magic Number重複は、複数ロジックEAで特に避けたい事故です。起動時に検出し、問題がある場合は安全側で停止または対象ロジックを無効化します。

実コード断片3:ロジック別Position Snapshot

以下は、Magic Number単位で現在ポジションを集計する考え方を簡略化した例です。売買判断や中核Entry条件は含めていません。

// 学習用に一般化したPosition Snapshot例です。
// 実運用EAの完成ソースではありません。

struct PositionSnapshot
{
   int    count;
   int    buyCount;
   int    sellCount;
   double totalVolume;
   double floatingProfit;
   bool   hasPosition;
};

PositionSnapshot BuildPositionSnapshotForMagic(long magic)
{
   PositionSnapshot snap;
   snap.count = 0;
   snap.buyCount = 0;
   snap.sellCount = 0;
   snap.totalVolume = 0.0;
   snap.floatingProfit = 0.0;
   snap.hasPosition = false;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);

      if(ticket == 0)
         continue;

      if(!PositionSelectByTicket(ticket))
         continue;

      if(PositionGetString(POSITION_SYMBOL) != _Symbol)
         continue;

      if((long)PositionGetInteger(POSITION_MAGIC) != magic)
         continue;

      long type = PositionGetInteger(POSITION_TYPE);
      double volume = PositionGetDouble(POSITION_VOLUME);
      double profit = PositionGetDouble(POSITION_PROFIT);

      snap.count++;
      snap.totalVolume += volume;
      snap.floatingProfit += profit;

      if(type == POSITION_TYPE_BUY)
         snap.buyCount++;

      if(type == POSITION_TYPE_SELL)
         snap.sellCount++;
   }

   snap.hasPosition = (snap.count > 0);
   return snap;
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
PositionsTotal現在のポジション一覧を確認する
POSITION_SYMBOL現在チャートのsymbolだけを対象にする
POSITION_MAGIC指定Magic Numberのポジションだけを集計する
buyCount / sellCount方向別の保有状態を確認する
floatingProfitロジック別の含み損益を確認する
hasPosition保有中かどうかを判定する

このようにSnapshotを作っておくと、各LogicSlotが自分のMagic Numberのポジションだけを確認できます。

実コード断片4:LogicSlotを順番に監査する

以下は、複数LogicSlotを順番に確認し、audit logを出す学習用コード例です。発注処理や中核エントリー条件は含めていません。

// 学習用に一般化したLogicSlot監査例です。
// 実運用EAの完成ソースではありません。

void PrintLogicAudit(const LogicSlot &slot,
                     const PositionSnapshot &snap,
                     string eventName,
                     string reason)
{
   Print("DIAG/LOGIC_AUDIT: logic=", slot.name,
         " magic=", slot.magic,
         " event=", eventName,
         " reason=", reason,
         " pos_count=", snap.count,
         " buy=", snap.buyCount,
         " sell=", snap.sellCount,
         " trade_route=", slot.tradeRouteEnabled);
}

void RunLogicSlotAudit()
{
   for(int i = 0; i < LOGIC_COUNT; i++)
   {
      LogicSlot slot = g_logicSlots[i];
      PositionSnapshot snap = BuildPositionSnapshotForMagic(slot.magic);

      if(!slot.enabled)
      {
         PrintLogicAudit(slot, snap, "SKIP", "LOGIC_DISABLED");
         continue;
      }

      if(!slot.tradeRouteEnabled)
      {
         PrintLogicAudit(slot, snap, "AUDIT_ONLY", slot.runtimeReason);
         continue;
      }

      PrintLogicAudit(slot, snap, "READY", "TRADE_ROUTE_ENABLED");

      // 実際のEAでは、この後にsignal / guard / executionを分けて設計します。
      // この記事では中核エントリー条件と発注処理は扱いません。
   }
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
RunLogicSlotAudit各LogicSlotを順番に確認する
LOGIC_DISABLED無効化されたロジックを実行しない
AUDIT_ONLY実売買へ接続せず、ログ確認だけ行う
TRADE_ROUTE_ENABLED実行経路が有効な状態を確認する
PositionSnapshotロジックごとの保有状態をログに出す

新しいロジックを追加する場合、いきなり実売買へ接続せず、このようなaudit段階を挟むことで安全に検証できます。

実コード断片5:Close ScopeをMagicで限定する

以下は、決済対象をLogicSlotのMagic Numberに限定する考え方を示した学習用コード例です。実際の決済送信処理は含めていません。

// 学習用に一般化したClose Scope確認例です。
// 実運用EAの完成ソースではありません。

bool IsPositionInLogicScope(ulong ticket, const LogicSlot &slot)
{
   if(ticket == 0)
      return false;

   if(!PositionSelectByTicket(ticket))
      return false;

   if(PositionGetString(POSITION_SYMBOL) != _Symbol)
      return false;

   if((long)PositionGetInteger(POSITION_MAGIC) != slot.magic)
      return false;

   return true;
}

void PlanCloseForLogic(const LogicSlot &slot)
{
   int targetCount = 0;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);

      if(!IsPositionInLogicScope(ticket, slot))
         continue;

      targetCount++;

      Print("DIAG/CLOSE_SCOPE: logic=", slot.name,
            " event=TARGET_FOUND",
            " ticket=", ticket,
            " magic=", slot.magic);
   }

   Print("DIAG/CLOSE_SCOPE: logic=", slot.name,
         " event=PLAN_SUMMARY",
         " target_count=", targetCount);
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
IsPositionInLogicScope対象ポジションが現在LogicSlotの範囲内か確認する
symbol確認別チャートや別symbolのポジションを除外する
magic確認他ロジックのポジションを除外する
TARGET_FOUND決済候補をログに残す
PLAN_SUMMARY対象件数を要約する

実際の決済処理を行う前に、対象scopeをログで確認できるようにしておくと、誤決済の切り分けがしやすくなります。

よくある失敗例

失敗1:複数ロジックで同じMagic Numberを使う

同じMagic Numberを使うと、ポジション集計、決済対象、損益集計が混ざります。Multi-Logic EAでは、LogicSlotごとに一意のMagic Numberを持たせることが基本です。

失敗2:Position Snapshotを全体集計だけにする

全体ポジションだけを見ると、どのロジックが何を保有しているのか分かりません。LogicSlotごとにSnapshotを作る必要があります。

失敗3:audit onlyを挟まずに実売買へ接続する

新しいロジックを追加した直後にtrade routeを有効化すると、想定外の発注や既存ロジックへの影響が出る可能性があります。まずはaudit onlyでログ確認します。

失敗4:決済scopeが広すぎる

symbolだけで決済対象を選ぶと、他Magicのポジションまで巻き込む可能性があります。symbol、magic、logic_idの対応を確認します。

失敗5:enabledとtradeRouteEnabledを混同する

ロジックを検証対象として有効にすることと、実売買へ接続することは別です。enabled=trueでもtradeRouteEnabled=falseにして、監査だけ行う段階を持つと安全です。

失敗6:ログにlogic_idやmagicを出していない

複数ロジックEAでは、ログにlogic_idやmagicが出ていないと、どのロジックの処理か分かりません。LOGIC_AUDIT、CLOSE_SCOPE、ORDERログなどに識別情報を含めます。

ログで確認するポイント

Multi-Logic EAでは、Expertsログで次の情報を確認できると切り分けやすくなります。

ログ見るポイント
VALIDATION_OKLogicSlotとMagic Numberが正しく初期化されているか
DUPLICATE_MAGICMagic Numberの重複がないか
LOGIC_AUDIT各LogicSlotの状態、trade route、保有数が確認できるか
AUDIT_ONLY実売買前の監査段階として動いているか
TRADE_ROUTE_ENABLED実行経路が有効なLogicSlotだけが候補になっているか
CLOSE_SCOPE決済対象がsymbolとmagicで限定されているか
PLAN_SUMMARY対象ポジション件数が想定と一致するか

ログ確認の基本は、次のページも参考にしてください。

MT5のログ確認方法|Experts・Journalの見方

開発依頼前に整理する情報

複数ロジックEAの開発や改修を依頼する場合、次の情報を先に整理しておくと仕様のすれ違いを減らせます。

  • ロジック数
  • 各ロジックの役割
  • 各ロジックのMagic Number
  • 同時稼働するか、どれか1つだけ動くか
  • BUY / SELLの扱い
  • 各ロジックの保有上限
  • 各ロジックの決済scope
  • 全体リスク管理とロジック別リスク管理の関係
  • 新規ロジックはaudit onlyから始めるか
  • ログに出すlogic_id、magic、reasonの粒度

仕様書、setファイル、ログ、スクリーンショットを整理する場合は、次のページも確認してください。

MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット

公開しない情報

この記事では、MQL5のMulti-Logic EA設計を学ぶために、公開可能な範囲だけを一般化して解説しています。以下は公開しません。

  • 完成EAソース全文
  • 外部シート参照による動作制御ロジック
  • 外部シートCSV取得、解析、時間枠、方向制御ロジック
  • 認証、口座許可判定、購入者管理ロジック
  • endpoint、token、URL、Google Sheet ID、Webhook URL、GAS URL
  • APIキー、認証トークン、口座番号、サーバー名
  • 実運用set値
  • 中核エントリー条件
  • 中核Trail / Nanpin判定
  • 独自優位性のある売買判定式
  • 利益保証、勝率保証、推奨ロット、推奨銘柄、推奨エントリー

本記事は、投資判断や売買指示ではなく、MQL5開発におけるMulti-Logic EAの構造、Magic Number、Snapshot、Close Scopeを理解するための技術解説です。

FAQ

Multi-Logic EAとは何ですか?

1つのEA内で複数のロジックや管理単位を扱うEAです。複数条件を並べるだけではなく、LogicSlot、Magic Number、Snapshot、Close Scopeを分けて管理する必要があります。

ロジックごとにMagic Numberを分ける必要がありますか?

基本的には分けるべきです。同じMagic Numberを使うと、ポジション集計や決済対象が混ざり、誤決済や検証不能につながる可能性があります。

enabledとtradeRouteEnabledは何が違いますか?

enabledはロジック自体を確認対象にするかどうか、tradeRouteEnabledは実売買へ接続するかどうかです。enabled=trueでもtradeRouteEnabled=falseなら、audit onlyとしてログ確認だけ行えます。

Position Snapshotはなぜ必要ですか?

ロジックごとの保有数、方向、ロット、損益を分けて確認するためです。全体集計だけでは、どのロジックのポジションか切り分けにくくなります。

Close Scopeとは何ですか?

決済対象の範囲です。Multi-Logic EAでは、symbolだけでなくMagic NumberやLogicSlot単位で対象を限定し、他ロジックのポジションを巻き込まないようにします。

新しいロジックはすぐ実売買へ接続してよいですか?

避けた方が安全です。まずはLogicSlot定義、Snapshot確認、audit only、pre-route gateの順に進め、ログ確認後にtrade routeを有効化する流れが安全です。

このコードは完成EAとして使えますか?

いいえ。この記事のコード例は、Multi-Logic EA設計の考え方を理解するために簡略化した学習用コードです。完成EAとしてそのまま使うことは想定していません。

実際のEAソース全文は公開されていますか?

公開していません。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開対象外です。

関連ページ

ページ確認できること
MQL5 EAの基本イベント構造を実コードで解説OnInit / OnTick / OnDeinitの責務分離
MQL5ログファースト設計を実コードで解説logic_id、magic、reasonをログで追う考え方
MQL5 EAのObject lifecycleを実コードで解説Logic別Objectや残存Objectの扱い
MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説ロジック別の値取得とsnapshot化
MT5のログ確認方法|Experts・Journalの見方ExpertsログとJournalログの基本確認
MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット開発相談前に整理する資料
不具合報告・調査依頼について不具合相談前に送る情報
免責事項投資判断、損益、利用上の注意に関する確認
投資助言を行わない方針売買助言ではなく技術支援として扱う方針

まとめ

MQL5でMulti-Logic EAを設計する時は、複数の条件式を1つのEAへ並べるだけでは不十分です。

特に、次の4点を分けておくと、誤発注・誤決済・検証不能を防ぎやすくなります。

  • LogicSlot:ロジックごとの設定・状態・実行可否を管理する
  • Magic Number:注文とポジションをロジック単位で識別する
  • Position Snapshot:ロジック別の保有数・方向・損益を固定して確認する
  • Close Scope:決済対象をsymbolとmagicで限定する

新しいロジックを追加する時は、いきなり実売買へ接続せず、defined、snapshot only、audit only、pre-route gate、trade route enableのように段階を分けて検証すると安全です。

完成EAの中核ロジックを公開しなくても、LogicSlot、Magic Number、Snapshot、Close Scopeの考え方を理解しておくことで、複数ロジックEAの設計・検証・不具合調査がしやすくなります。

ABOUT ME
記事URLをコピーしました