Problem Description
Solution
To achieve this in MetaTrader 4, the most robust and native method is using Global Variables of the Client Terminal.
Here is the architecture of the solution:
- The Dashboard (Master EA): Creates buttons on the chart. When you click a button, it creates a Global Variable (e.g.,
CMD_EURUSDwith a value of1for Buy or2for Sell). - The Receiver (Slave EA): Runs on the specific currency pair. It constantly checks for the existence of that Global Variable. If found, it executes the trade and resets the variable to
0to prevent duplicate orders.
Below are the two separate code files required.
1. The Dashboard (Master EA)
Compile this code and attach it to one chart (e.g., XAUUSD or an empty chart). It will control the others.
//+------------------------------------------------------------------+
//| SignalDashboard.mq4 |
//| Copyright 2023, MetaQuotes |
//| https://mql4.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative Assistant"
#property link "https://mql4.com"
#property version "1.00"
#property strict
//--- Input Parameters
input string InpSymbols = "EURUSD,GBPUSD,USDJPY,XAUUSD"; // Comma-separated symbols
input color ColorBuy = clrForestGreen;
input color ColorSell = clrFireBrick;
input int BtnWidth = 80;
input int BtnHeight = 30;
input int X_Start = 20;
input int Y_Start = 50;
//--- Global arrays to store parsed symbols
string symbolArray[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Parse the comma-separated string into an array
StringSplit(InpSymbols, ',', symbolArray);
// Create the UI
CreateDashboard();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up all objects created by this EA
ObjectsDeleteAll(0, "Dash_");
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
// Handle Button Clicks
if(id == CHARTEVENT_OBJECT_CLICK)
{
// Check if the clicked object is one of ours
if(StringFind(sparam, "Dash_") >= 0)
{
// Reset button state immediately (visual effect)
ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
// Extract command and symbol from name (Format: Dash_CMD_SYMBOL)
string parts[];
StringSplit(sparam, '_', parts);
if(ArraySize(parts) == 3)
{
string cmdType = parts[1]; // "Buy" or "Sell"
string sym = parts[2]; // "EURUSD", etc.
// Define the Global Variable Name
string gvName = "CMD_" + sym;
// Set Global Variable: 1 for Buy, 2 for Sell
double signal = (cmdType == "Buy") ? 1.0 : 2.0;
// We use GlobalVariableSet.
// The Slave EA will pick this up, execute, and delete/reset it.
GlobalVariableSet(gvName, signal);
Print("Signal Sent: " + cmdType + " for " + sym);
PlaySound("tick.wav");
}
}
}
}
//+------------------------------------------------------------------+
//| Helper: Create the Dashboard UI |
//+------------------------------------------------------------------+
void CreateDashboard()
{
int total = ArraySize(symbolArray);
for(int i = 0; i < total; i++)
{
string sym = symbolArray[i];
// Strip whitespace
StringTrimLeft(sym);
StringTrimRight(sym);
int y = Y_Start + (i * (BtnHeight + 10));
// Create Label
CreateLabel("Dash_Lbl_" + sym, sym, X_Start, y + 5);
// Create Buy Button
CreateButton("Dash_Buy_" + sym, "BUY", X_Start + 80, y, ColorBuy);
// Create Sell Button
CreateButton("Dash_Sell_" + sym, "SELL", X_Start + 80 + BtnWidth + 10, y, ColorSell);
}
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Helper: Create a Button Object |
//+------------------------------------------------------------------+
void CreateButton(string name, string text, int x, int y, color bg)
{
if(ObjectFind(0, name) < 0)
ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, BtnWidth);
ObjectSetInteger(0, name, OBJPROP_YSIZE, BtnHeight);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrNONE);
ObjectSetInteger(0, name, OBJPROP_STATE, false);
}
//+------------------------------------------------------------------+
//| Helper: Create a Label Object |
//+------------------------------------------------------------------+
void CreateLabel(string name, string text, int x, int y)
{
if(ObjectFind(0, name) < 0)
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrBlack);
}
//+------------------------------------------------------------------+
2. The Receiver (Slave EA)
Compile this code and attach it to every chart you want to trade (e.g., open a EURUSD chart and attach it, open a GBPUSD chart and attach it).
//+------------------------------------------------------------------+
//| SignalReceiver.mq4 |
//| Copyright 2023, MetaQuotes |
//| https://mql4.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative Assistant"
#property link "https://mql4.com"
#property version "1.00"
#property strict
//--- Input Parameters
input double InpLotSize = 0.1;
input int InpStopLoss = 200; // Points (0 to disable)
input int InpTakeProfit = 400; // Points (0 to disable)
input int InpMagicNum = 123456;
input int InpSlippage = 3;
//--- Global variable name to listen to
string gvName;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Define the specific variable name for THIS chart's symbol
// Example: If attached to EURUSD, it listens for "CMD_EURUSD"
gvName = "CMD_" + Symbol();
Print("Receiver started. Listening for Global Variable: ", gvName);
// Ensure the variable exists and is 0 to start
if(!GlobalVariableCheck(gvName))
GlobalVariableSet(gvName, 0);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if the Global Variable exists
if(GlobalVariableCheck(gvName))
{
// 2. Get the value
double signal = GlobalVariableGet(gvName);
// 3. If signal is 0, do nothing (waiting state)
if(signal == 0) return;
// 4. Process Signal
if(signal == 1.0) // BUY
{
ExecuteTrade(OP_BUY);
}
else if(signal == 2.0) // SELL
{
ExecuteTrade(OP_SELL);
}
// 5. Reset the Global Variable to 0 immediately to prevent double entry
GlobalVariableSet(gvName, 0);
}
}
//+------------------------------------------------------------------+
//| Helper: Execute Trade |
//+------------------------------------------------------------------+
void ExecuteTrade(int type)
{
double price, sl, tp;
color clr;
if(type == OP_BUY)
{
price = Ask;
sl = (InpStopLoss > 0) ? Ask - InpStopLoss * Point : 0;
tp = (InpTakeProfit > 0) ? Ask + InpTakeProfit * Point : 0;
clr = clrBlue;
}
else
{
price = Bid;
sl = (InpStopLoss > 0) ? Bid + InpStopLoss * Point : 0;
tp = (InpTakeProfit > 0) ? Bid - InpTakeProfit * Point : 0;
clr = clrRed;
}
// Normalize prices
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
// Send Order
int ticket = OrderSend(Symbol(), type, InpLotSize, price, InpSlippage, sl, tp, "Dashboard Trade", InpMagicNum, 0, clr);
if(ticket > 0)
Print("Order Opened Successfully. Ticket: ", ticket);
else
Print("Error Opening Order: ", GetLastError());
}
//+------------------------------------------------------------------+
How to Setup and Use
- Compile: Open MetaEditor, create the two files above, paste the code, and compile both.
- Setup Slave EAs:
- Open a chart for EURUSD. Attach
SignalReceiver.mq4. - Open a chart for GBPUSD. Attach
SignalReceiver.mq4. - (Repeat for any pairs you want to trade).
- Open a chart for EURUSD. Attach
- Setup Master EA:
- Open a separate chart (e.g., XAUUSD or just a blank chart).
- Attach
SignalDashboard.mq4. - In the inputs, ensure
InpSymbolsmatches the charts you opened in Step 2 (e.g., "EURUSD,GBPUSD").
- Trade:
- Click "BUY" next to EURUSD on the dashboard.
- The Dashboard sets the Global Variable
CMD_EURUSDto1. - The Receiver on the EURUSD chart detects the
1, executes a Buy order, and resets the variable to0.
Key Technical Details
- Global Variables: These are stored in the terminal's memory (and saved to disk). They are accessible by all EAs running in that specific terminal instance.
- StringSplit: This function is used in the Dashboard to dynamically generate buttons based on the list of symbols you provide in the settings.
- Handshake: The most critical part is
GlobalVariableSet(gvName, 0)in the Receiver. Without this, the Receiver would execute a trade on every single tick as long as the variable remained1.
Q&A
Q: Can I run the Dashboard on a Demo account and the Receiver on a Real account?
A: No, not with this code. Global Variables only work within the same terminal instance. To trade across terminals (or computers), you would need to use File operations (writing/reading CSVs in a shared folder) or Windows Sockets, which is significantly more complex.
Q: What happens if I click the button twice quickly?
A: If the Receiver hasn't processed the first click yet (reset the variable to 0), the second click just overwrites the variable with the same value, resulting in only one trade. If the Receiver has processed it, a second trade will open.
Q: How do I verify the communication is working?
A: In MT4, press F3. This opens the "Global Variables" window. When you click a button on the dashboard, you should briefly see a variable like CMD_EURUSD appear with value 1 or 2, and then almost instantly disappear (or turn to 0) as the Receiver processes it.