Three clients came to us this year with the same problem: a multi-EA account losing money in ways no single EA could explain. Running two or more EAs on the same account only works safely when every EA uses a unique magic number *and* verifies order ownership before every modify, close, and position-count operation. Most EAs do neither — and the result is one EA quietly acting on orders it didn’t place, with no error, no warning, and no log entry to show for it.
In every case, the cause was the same structural gap — the same unguarded loop, repeated across every EA they were running.
How Magic Number Collisions Surface in Practice
Magic number collisions don’t announce themselves with errors. MetaTrader logs no warning when one EA modifies or closes an order it doesn’t own. The terminal accepts the operation silently, and the EA that placed the original order has no idea anything happened.
What you see instead:
- A position closed at a price that doesn’t match the EA’s trailing-stop or take-profit logic
- A stop-loss that moved overnight, but no EA logged the modification
- A risk-management EA blocking new entries because it counts five open positions when only one of them belongs to it
We have traced three recurring patterns across portfolio rescue engagements this year.
First: a trailing-stop EA iterates all open positions to update stop-losses. It doesn’t filter by magic number. It moves the SL on every open order on the account — including orders placed by a separate mean-reversion EA that was never designed to be trailed.
Second: a breakeven EA fires its close-at-breakeven logic based on total position count. It catches a scalper’s position at +12 pips, decides the breakeven rule applies, and closes it. The scalper EA is never informed the trade was touched.
Third: a basket-close EA designed to flatten all positions on a symbol at end-of-day counts positions by symbol instead of by magic number. It closes every open order on EURUSD regardless of which EA placed them.
In each case, the EAs were otherwise working correctly. The failure lived entirely in the interaction between them.
Why This Happens: `OrderSelect()`Sees Every Order on the Account
`OrderSelect()` is not EA-aware. When you loop through `OrdersTotal()`, you are iterating every order on the account — including every order placed by every other EA running in the same terminal, on any chart.
Most EAs filter by magic number correctly in one place: the entry check, where they count existing positions to avoid entering twice. That filter works. The problem is every other loop in the same EA.
Modification loops, position-count loops, and close-all operations often filter only by symbol. In a single-EA backtest, that’s sufficient — there are no other orders in the pool. In a live portfolio account, it means the loop acts on every order on that symbol regardless of who placed them.
The dangerous pattern looks like this:
// DANGEROUS: no ownership check — acts on every order for this symbol
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == Symbol())
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
}This loop will modify the stop-loss on every open position for the current symbol — including positions placed by every other EA on the account. It will not return an error. It will execute cleanly, log nothing unusual, and leave no trace.
The fix is one additional condition:
// CORRECT: verifies ownership before acting
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS)
&& OrderSymbol() == Symbol()
&& OrderMagicNumber() == MAGIC_NUMBER)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0);
}
One condition. The loop now acts only on orders this EA placed. That is the entire fix — and it is absent from the majority of EAs we review.
The Three Ownership Checks Every EA Must Have
Ownership verification is not a single gate applied once at entry. It must appear at three distinct points in every EA that shares an account with another.
1. Before every `OrderModify()`and `OrderClose()`call
Any loop that modifies or closes orders must confirm `OrderMagicNumber()` == MAGIC before acting. Without this check, a trailing-stop or breakeven EA will silently alter orders it doesn’t own. No error is thrown. The terminal complies. The EA that placed the original order learns nothing until the damage is visible in the account’s trade history.
2. Inside position-count loops used for risk-budget calculations
When an EA counts open positions to decide whether to add risk, it must count only its own positions. A portfolio of three EAs may have six positions open simultaneously. If the trend EA’s risk-management loop sees all six, it will refuse to enter new trades even when the trend EA itself has zero open positions. The account appears fully deployed when only two of the three strategies are active.
3. When basket-level operations iterate the full order pool
End-of-day close-all logic, trailing-stop sweeps, and basket-profit managers are the most hazardous category. These operations are designed to act on multiple positions at once. If the sweep filters by symbol instead of magic number, it becomes an account-wide override — closing or modifying every position on that symbol regardless of which strategy placed them. In a portfolio account, one EA’s housekeeping function can undo another EA’s active trades.

All three checks use the same fix: confirm `OrderMagicNumber() == MAGIC` before acting. The check costs one line per loop. The absence of it costs positions.
Magic Number Namespace Strategies for Portfolios
Unique magic numbers don’t happen by accident. Three EAs each defaulting to `12345` — or to `0` because the developer never set the field — will collide on every shared account. At barmenteros FX, we see this in roughly half the portfolio rescue engagements we take on, and in nearly every AI-generated EA we review. The AI produces working code, but the default magic number is arbitrary, and it is never checked against what else is running on the account.
Three practical schemes prevent collisions across a portfolio:
| Approach | Example Values | When to Use | Risk |
|---|---|---|---|
| Range allocation | EA-A: 1000–1999, EA-B: 2000–2999 | Fixed portfolio with manually coordinated EAs | Easy to miss when a new EA joins the portfolio |
| EA-ID × 1000 + variant | Base ID 1 → EURUSD: 1001, GBPUSD: 1002 | Same EA deployed across multiple symbols | Requires consistent ID assignment across all instances |
| Hash-from-symbol | Derived from symbol name at runtime | Dynamic symbol sets, portfolio managers | Verify there are no collisions across your specific symbol list before deploying |
Range allocation is the simplest to audit and coordinate. The EA-ID × 1000 + variant scheme works well when the same EA runs on multiple charts. The hash-from-symbol approach suits portfolio managers where the symbol list isn’t fixed at compile time.
Whichever scheme you use, document the assignment in the EA source as a comment. It takes 30 seconds to write and eliminates ambiguity when the portfolio grows.
How to Audit an Existing Portfolio in 15 Minutes
If you suspect collisions are already occurring, here are three checks you can run before engaging anyone.
Step 1: List every magic number in every active EA
For each EA running on the account, find the magic number — it is usually an input parameter visible in the EA’s settings dialog, or declared as a constant near the top of the source file. Write every value down. If any two EAs share the same number, you have a confirmed collision. If any EA uses `0`, it will act on orders with no magic number — which includes orders placed by terminals or tools that also omit the field.
Step 2: Search each source file for `OrderSelect()`loops without an ownership filter
Open each `.mq4` or `.mq5` source file and search for `OrderSelect`. For every loop you find, check whether it includes a condition against `OrderMagicNumber()` before any call to `OrderModify()` or `OrderClose()`. A loop that filters only by `OrderSymbol()` or `OrderType()` — with no magic number check before acting — is a live collision risk.
Step 3: Check position-count functions
Find any function that counts open orders (look for loops over `OrdersTotal()` that increment a counter). Verify the counter increments only when `OrderMagicNumber() == MAGIC`. If it counts all orders without that filter, the EA’s risk-management logic is working with the wrong number.
These three checks take 15 minutes on a three-EA portfolio. In most cases, the collision is visible immediately — a shared magic number or an unguarded loop in the modification logic.
When the source isn’t available — compiled `.ex4` files, purchased EAs, or inherited code delivered without source — the audit shifts to execution logs: correlating order IDs across EA journals and reconstructing which EA was responsible for each modification or close. That log-based forensic process is the pattern we encounter in most Code Review / Rescue engagements when a portfolio account starts behaving inconsistently.


Leave a Reply