Introduction to Trade Copiers and MQL5
What is a Trade Copier and Why Use One?
A trade copier, also known as a trade replication system, automatically duplicates trades from one account (the master or sender) to one or more other accounts (the slaves or receivers). This is useful for:
- Fund managers: Replicating trades across multiple client accounts.
- Proprietary trading firms: Distributing strategies to junior traders.
- Individual traders: Managing multiple accounts with the same strategy or mirroring trades between their own accounts.
Trade copiers eliminate the need for manual trade entry, reducing latency and the risk of errors. They improve efficiency and allow for consistent strategy execution across multiple accounts.
Overview of MQL5 for Trade Automation
MQL5 is a high-level, object-oriented programming language used in the MetaTrader 5 platform. It offers a rich set of functions for automated trading, technical analysis, and custom indicator development. Compared to MQL4, MQL5 provides significant advantages, including:
- Improved execution speed: MQL5 code typically executes faster than MQL4 due to optimized compilation and execution.
- Object-oriented programming (OOP): MQL5 supports OOP principles, promoting code reusability and maintainability. MQL4 supports this partially, but MQL5 is much more efficient and comfortable in use.
- Event-driven architecture: MQL5 provides robust event handling mechanisms for responding to market events and user actions.
- Standard Library: A comprehensive collection of pre-built functions and classes that simplify development.
- Strategy Tester: The multi-threaded strategy tester allows for faster and more accurate backtesting and optimization.
Key Components of a Trade Copier in MQL5
A trade copier typically consists of two Expert Advisors (EAs):
- Sender EA (Master): This EA runs on the account whose trades will be copied. It detects trade events (OrderSend, OrderModify, OrderClose) and transmits the relevant trade data to the receiver EAs.
- Receiver EA (Slave): This EA runs on the accounts that will receive and execute the copied trades. It receives trade data from the sender EA, deserializes it, and executes the corresponding trade operations.
Communication between the sender and receiver EAs can be achieved through various methods, including:
- Global Variables: Simple and quick for data transmission within the same terminal, but not reliable across different terminals.
- Files: More robust for cross-terminal communication but slower than global variables.
- Network Sockets: The most efficient and reliable method for cross-terminal communication but requires more complex implementation.
Setting Up the Environment and Basic Code Structure
Installing MetaTrader 5 and MetaEditor
Ensure you have MetaTrader 5 installed. MetaEditor, the MQL5 IDE, is included with MetaTrader 5. Launch MetaEditor from within MetaTrader 5 (Tools -> MetaQuotes Language Editor).
Creating a New Expert Advisor (EA) Project
In MetaEditor, create a new EA project (File -> New -> Expert Advisor (template)). Give your EA a descriptive name (e.g., “TradeCopierSender” or “TradeCopierReceiver”).
Defining Global Variables and Input Parameters
Define global variables to store important data, such as the magic number for identifying trades managed by the EA, and input parameters that the user can configure.
Example (Sender EA):
input int MasterMagicNumber = 12345; // Magic number for identifying trades to copy
input string ReceiverEA_ID = "ReceiverEA_1"; // Unique ID for the Receiver EA
Example (Receiver EA):
input string SenderEA_ID = "SenderEA_1"; // Unique ID of the Sender EA
input double LotSizeMultiplier = 1.0; // Multiplier for adjusting lot sizes
Implementing Basic Error Handling
Implement error handling using the Print() and GetLastError() functions to log errors and diagnose issues.
Example:
int ticket = OrderSend(_Symbol, OP_BUY, 0.1, Ask, 3, Bid - 20 * _Point, Bid + 20 * _Point, "My EA", 12345, 0, clrGreen);
if (ticket < 0) {
Print("OrderSend failed, error: ", GetLastError());
}
Implementing the Sender (Master) EA
Detecting and Sending Trade Events (OrderSend, OrderModify, OrderClose)
The OnTrade() event handler is triggered whenever a trade event occurs. Use this handler to detect OrderSend, OrderModify, and OrderClose events and extract the relevant trade data.
void OnTrade() {
for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) {
ulong ticket = OrderGetTicket(i);
if (OrderGetInteger(ORDER_MAGIC) == MasterMagicNumber && OrderGetInteger(ORDER_STATE) == ORDER_STATE_CLOSED) {
// Code to send close event data to receiver
}
}
}
Using Global Variables or Files for Communication
For simplicity, let’s use global variables for communication. For a more robust solution, consider using files or network sockets. When you use global variables, keep in mind that receiver EA should reside on the same MT5 terminal.
Example (Sender EA):
void SendTradeData(string tradeData) {
GlobalVariableSet(ReceiverEA_ID + "_TradeData", tradeData);
}
Implementing Data Serialization (Converting Trade Data to String)
Serialize the trade data into a string format for transmission. Use a custom format or a standard format like JSON. A custom format allows for a compact representation and the developer can control the exact structure. JSON is more flexible and easier to parse but adds overhead.
Example (Custom format):
string SerializeTradeData(int operationType, string symbol, double volume, double price, double stopLoss, double takeProfit) {
string data = StringFormat("%d;%s;%f;%f;%f;%f", operationType, symbol, volume, price, stopLoss, takeProfit);
return data;
}
Error Handling and Logging for the Sender EA
Log all errors and important events using the Print() function. This helps in debugging and monitoring the trade copier’s performance.
void OnDeinit(const int reason) {
Print("Sender EA stopped, reason: ", reason);
}
Implementing the Receiver (Slave) EA
Receiving and Deserializing Trade Data
The OnTick() event handler is suitable for periodically checking for new trade data. Retrieve the trade data from the global variable, deserialize it, and execute the trade.
void OnTick() {
string tradeData = GlobalVariableGetString(SenderEA_ID + "_TradeData");
if (tradeData != "") {
// Deserialize trade data
ExecuteTrade(tradeData);
GlobalVariableDel(SenderEA_ID + "_TradeData");
}
}
Executing Trades Based on Received Data
Use the OrderSend() function to execute trades based on the deserialized trade data. Consider using OrderSendAsync() for non-blocking order execution.
bool ExecuteTrade(string tradeData) {
// Implement parsing of data string into variables
StringSplit(tradeData, ';', trade_params);
int operationType = StringToInteger(trade_params[0]);
string symbol = trade_params[1];
double volume = StringToDouble(trade_params[2]) * LotSizeMultiplier; // Apply lot size multiplier
double price = StringToDouble(trade_params[3]);
double stopLoss = StringToDouble(trade_params[4]);
double takeProfit = StringToDouble(trade_params[5]);
double sl_price = NormalizeDouble(stopLoss, Digits());
double tp_price = NormalizeDouble(takeProfit, Digits());
if (operationType == 0) {
// Execute BUY order
trade_result = OrderSend(symbol, OP_BUY, volume, price, 3, sl_price, tp_price, "Copied trade", 0, 0, clrNONE);
} else if(operationType == 1) {
// Execute SELL order
trade_result = OrderSend(symbol, OP_SELL, volume, price, 3, sl_price, tp_price, "Copied trade", 0, 0, clrNONE);
}
if (trade_result.retcode != 10009) {
PrintFormat("OrderSend error: %d", trade_result.retcode);
return false;
}
return true;
}
Handling Slippage and Deviation
Specify an appropriate slippage value in the OrderSend() function to account for potential price fluctuations.
Implementing Risk Management Features (Lot Size Adjustment, Stop Loss/Take Profit)
Implement risk management features, such as lot size adjustment, to control the risk exposure of the receiver accounts. The LotSizeMultiplier input parameter can be used to adjust the lot sizes proportionally.
Testing, Optimization, and Deployment
Backtesting the Trade Copier
Backtesting a trade copier is complex as it involves testing two EAs simultaneously. It is best done manually using visual mode, or by writing additional test scripts that simulate trade events on one chart, and observing the execution on another.
Optimizing Parameters for Performance
Optimize the parameters, such as the LotSizeMultiplier, to achieve the desired risk-reward profile. Note that network latency will affect the performance and must be considered during optimization.
Real-Time Testing on Demo Accounts
Before deploying the trade copier on live accounts, thoroughly test it on demo accounts to ensure its functionality and stability.
Deployment Considerations and Security
- Security: Protect the communication channel between the sender and receiver EAs to prevent unauthorized access and manipulation of trade data.
- Latency: Minimize network latency to ensure timely trade execution.
- Monitoring: Continuously monitor the trade copier’s performance and address any issues promptly.
- Account Permissions: Ensure that the receiving accounts have adequate permissions to execute trades.
By following these steps, you can build a robust and reliable trade copier in MQL5 to automate trade replication across multiple accounts.