-
Monitor trades / positions (most reliable)
-
Watch for new deals/orders/position changes using OnTradeTransaction() or by snapshotting PositionsTotal() and PositionGet... properties.
-
You can detect: symbol, volume, magic number, comment, price, direction — then trigger your action.
-
Works even if the other EA is EX5 because all trade operations go through the terminal.
-
-
Detect chart objects the EA draws (arrows, labels)
-
Some EAs draw arrows/text when they signal. You can scan chart objects ( ObjectsTotal , ObjectName , ObjectGet ) and react to a new object.
-
Less reliable (object naming conventions vary).
-
-
Read Terminal Global Variables
-
If the EX5 EA uses GlobalVariableSet() to publish signals, your EA can GlobalVariableGet() them. Requires that EA to actually use global variables.
-
-
Read files / shared memory / DLL / windows messages
-
Only possible if the EX5 writes files or uses a DLL / shared mechanism. Rare and often unsafe (DLLs require terminal settings and are platform dependent).
-
-
Use iCustom / indicators
-
If the EX5 uses a visible indicator with accessible buffers you can call iCustom() to read buffers. Only works if that indicator is present and you know buffer indices.
-
-
Use trade/position monitoring. It's simple, reliable and requires no cooperation from the other EA.
-
If you cannot distinguish which EA placed a trade, let the user pick a trade from history to “follow”, or auto-detect the first trade after attaching your EA and store its magic/comment to follow subsequent trades.
Example MQL5 EA — listens for other EAs' trade activity and reacts
This EA:
-
builds a set of currently known position tickets on init,
-
uses OnTradeTransaction() to detect trade changes,
-
when it sees a new position open or position closed, it calls OnExternalSignalDetected(...) where you place your custom action (open hedge, notify, etc.),
-
shows how to auto-detect the other EA's magic/comment or let user specify it.
Paste the code into MetaEditor as a new EA and compile.
//+------------------------------------------------------------------+ //| FollowExternalTrades.mq5 | //| Example: detect other EA's opens/closes and react | //+------------------------------------------------------------------+ #property copyright "Example" #property version "1.00" #property strict input long FollowMagic = -1; // if >=0 follow this magic; -1 = auto-detect first external trade input string FollowComment = ""; // optionally follow by comment (non-empty to match) input bool AutoDetect = true; // when FollowMagic==-1 try to auto-detect // internal storage of known position tickets ulong knownTickets[]; //+------------------------------------------------------------------+ //| Utility: add ticket if not present | //+------------------------------------------------------------------+ void AddKnownTicket(ulong ticket) { for(int i=0;i<ArraySize(knownTickets);i++) if(knownTickets[i]==ticket) return; ArrayResize(knownTickets, ArraySize(knownTickets)+1); knownTickets[ArraySize(knownTickets)-1] = ticket; } //+------------------------------------------------------------------+ //| Utility: remove ticket | //+------------------------------------------------------------------+ void RemoveKnownTicket(ulong ticket) { int idx=-1; for(int i=0;i<ArraySize(knownTickets);i++) if(knownTickets[i]==ticket) { idx=i; break; } if(idx==-1) return; for(int j=idx;j<ArraySize(knownTickets)-1;j++) knownTickets[j]=knownTickets[j+1]; ArrayResize(knownTickets, ArraySize(knownTickets)-1); } //+------------------------------------------------------------------+ //| Utility: is known | //+------------------------------------------------------------------+ bool IsKnownTicket(ulong ticket) { for(int i=0;i<ArraySize(knownTickets);i++) if(knownTickets[i]==ticket) return true; return false; } //+------------------------------------------------------------------+ //| Called on initialization | //+------------------------------------------------------------------+ int OnInit() { ArrayResize(knownTickets,0); // populate knownTickets with current positions so only new ones are detected int total = PositionsTotal(); for(int i=0;i<total;i++) { if(PositionSelectByIndex(i)) { ulong ticket = (ulong)PositionGetInteger(POSITION_TICKET); AddKnownTicket(ticket); } } Print("FollowExternalTrades initialized. Known positions: ", ArraySize(knownTickets)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Called on deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // cleanup if needed } //+------------------------------------------------------------------+ //| Called for every trade transaction in terminal | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { // Keep it simple: when any transaction occurs, re-scan positions and detect differences // This is robust and avoids deep parsing of MqlTradeTransaction fields. DetectPositionChanges(); } //+------------------------------------------------------------------+ //| Helper: scan positions and detect new opens / closes | //+------------------------------------------------------------------+ void DetectPositionChanges() { // Build a set of current position tickets ulong currentTickets[]; ArrayResize(currentTickets, 0); int total = PositionsTotal(); for(int i=0;i<total;i++) { if(PositionSelectByIndex(i)) { ulong ticket = (ulong)PositionGetInteger(POSITION_TICKET); ArrayResize(currentTickets, ArraySize(currentTickets)+1); currentTickets[ArraySize(currentTickets)-1] = ticket; } } // detect newly opened positions (present in current but not in known) for(int i=0;i<ArraySize(currentTickets);i++) { ulong t = currentTickets[i]; if(!IsKnownTicket(t)) { // New position detected if(PositionSelectByTicket(t)) { long magic = (long)PositionGetInteger(POSITION_MAGIC); string comment = PositionGetString(POSITION_COMMENT); string sym = PositionGetString(POSITION_SYMBOL); double vol = PositionGetDouble(POSITION_VOLUME); int ptype = (int)PositionGetInteger(POSITION_TYPE); // 0 = long, 1 = short datetime time = (datetime)PositionGetInteger(POSITION_TIME); // If user requested filtering by magic/comment, respect it bool match = true; if(FollowMagic>=0 && magic!=FollowMagic) match = false; if(StringLen(FollowComment)>0 && comment!=FollowComment) match = false; // If auto-detect is enabled and FollowMagic==-1, set FollowMagic to magic of first detected if(AutoDetect && FollowMagic==-1 && match) { FollowMagic = magic; PrintFormat("Auto-detected FollowMagic = %d (comment='%s')", FollowMagic, comment); } // If following by magic/comment and this matches, call handler if((FollowMagic==-1 || magic==FollowMagic) && (StringLen(FollowComment)==0 || comment==FollowComment)) { PrintFormat("Detected NEW position: ticket=%I64u sym=%s type=%d vol=%.2f magic=%d comment=%s time=%s", t, sym, ptype, vol, magic, comment, TimeToString(time, TIME_DATE|TIME_SECONDS)); OnExternalSignalDetected(true, t, sym, ptype, vol, magic, comment, time); } // Add to known set regardless to avoid repeated processing AddKnownTicket(t); } } } // detect closed positions (present in known but not in current) // copy knownTickets to iterate to avoid mutation issues int knownCount = ArraySize(knownTickets); for(int i=knownCount-1;i>=0;i--) { ulong t = knownTickets[i]; bool stillExists = false; for(int j=0;j<ArraySize(currentTickets);j++) if(currentTickets[j]==t) { stillExists=true; break; } if(!stillExists) { // position closed PrintFormat("Detected CLOSED position ticket=%I64u", t); OnExternalSignalDetected(false, t, "", -1, 0.0, 0, "", 0); RemoveKnownTicket(t); } } } //+------------------------------------------------------------------+ //| User hook: called when an external position open/close detected | //| is_open = true => open detected; false => closed detected | //+------------------------------------------------------------------+ void OnExternalSignalDetected(bool is_open, ulong ticket, string symbol, int pos_type, double volume, long magic, string comment, datetime open_time) { // --> PUT YOUR ACTIONS HERE <-- // Examples: // - Place a hedging order // - Send notification / email // - Copy the trade // - Update internal state if(is_open) { // Example: print and (example) open a small opposite position as reaction: PrintFormat("*** ACTION: external OPEN detected. Ticket=%I64u symbol=%s type=%d vol=%.2f magic=%d comment=%s", ticket, symbol, pos_type, volume, magic, comment); // Example placeholder: open 0.01 lot opposite (CAUTION: real trading) // double lots = 0.01; // int opposite_type = (pos_type==POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY; // (You would use trade.Request/OrderSend here - omitted to avoid accidental trading) } else { PrintFormat("*** ACTION: external CLOSE detected. Ticket=%I64u", ticket); // handle close: maybe close your mirror order or log } } //+------------------------------------------------------------------+ //| Helper: select position by ticket | //+------------------------------------------------------------------+ bool PositionSelectByTicket(ulong ticket) { // iterate positions and match ticket for(int i=0;i<PositionsTotal();i++) { if(PositionSelectByIndex(i)) { if((ulong)PositionGetInteger(POSITION_TICKET) == ticket) return true; } } return false; } //+------------------------------------------------------------------+ //| OnTick - nothing heavy here | //+------------------------------------------------------------------+ void OnTick() { // EA idle; logic is event driven by OnTradeTransaction }


