MQL5 Multi-Logic EA設計を実コードで解説|LogicSlot・Magic Number・Snapshotを分ける理由
MQL5でEAを拡張していくと、1つのEA内に複数のロジックを入れたくなる場面があります。
たとえば、順張りロジック、逆張りロジック、時間足違いのロジック、買い専用・売り専用ロジック、検証中の追加ロジックなどです。しかし、複数ロジックを1本のEAへ入れる場合、単に条件式を増やすだけでは危険です。
Magic Numberが混ざる、どのロジックのポジションか分からなくなる、決済対象を間違える、同じポジションを複数ロジックが管理してしまう、検証OFFのロジックが実売買へつながる。このような問題を避けるには、LogicSlot・Magic Number・Snapshot・Close Scopeを分けて設計する必要があります。
この記事では、MQL5のMulti-Logic EA設計を、学習用に一般化したコード断片で解説します。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開しません。
- この記事で扱う範囲
- Multi-Logic EAとは
- LogicSlotでロジック単位を固定する
- Magic Numberをロジックごとに分ける理由
- Position Snapshotを分ける理由
- trade_routeを段階的に接続する
- Close Scopeを分ける理由
- 実コード断片1:LogicSlot定義
- 実コード断片2:Magic Number重複を確認する
- 実コード断片3:ロジック別Position Snapshot
- 実コード断片4:LogicSlotを順番に監査する
- 実コード断片5:Close ScopeをMagicで限定する
- よくある失敗例
- ログで確認するポイント
- 開発依頼前に整理する情報
- 公開しない情報
- FAQ
- 関連ページ
- まとめ
この記事で扱う範囲
| 項目 | この記事で扱う内容 | 扱わない内容 |
|---|---|---|
| 目的 | 複数ロジック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では、新しいロジックを作った直後に実売買へ接続しない方が安全です。
推奨される段階は次の通りです。
| 段階 | 状態 | 確認内容 |
|---|---|---|
| defined | LogicSlotだけ定義 | 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_OK | Magic 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_OK | LogicSlotとMagic Numberが正しく初期化されているか |
| DUPLICATE_MAGIC | Magic Numberの重複がないか |
| LOGIC_AUDIT | 各LogicSlotの状態、trade route、保有数が確認できるか |
| AUDIT_ONLY | 実売買前の監査段階として動いているか |
| TRADE_ROUTE_ENABLED | 実行経路が有効なLogicSlotだけが候補になっているか |
| CLOSE_SCOPE | 決済対象がsymbolとmagicで限定されているか |
| PLAN_SUMMARY | 対象ポジション件数が想定と一致するか |
ログ確認の基本は、次のページも参考にしてください。
開発依頼前に整理する情報
複数ロジック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の設計・検証・不具合調査がしやすくなります。

