Building a Python Application to Automate Basket Orders in MetaTrader 5 with MQL5
Introduction
Automating trading workflows can save time, reduce errors, and streamline operations. This article provides a step-by-step guide to creating a Python application that generates basket orders and an MQL5 script to execute those orders in MetaTrader 5 (MT5). Whether you're a trader or a developer looking to integrate Python with MT5, this comprehensive guide will walk you through the process.
The Goal
Python Application:
MQL5 Script:
Part 1: Python Application
We will build a Tkinter GUI application to gather order details and save them in a file format readable by MT5.
Code Breakdown
Here’s the Python code, broken into steps:
1. Setting Up the Environment
First, define the file path where the order details will be saved. This path corresponds to the Files directory in your MT5 installation.
file_path = r"C:\Users\euric\AppData\Roaming\MetaQuotes\Terminal\698B86XXXXXXXXXX28CAC50412\MQL5\Files\send_basket.txt"
Ensure that the Files directory exists. If not, the application will attempt to create it.
2. Creating the Application Class
The BasketApp class encapsulates the GUI logic.
class BasketApp:
def __init__(self, root):
self.root = root
self.root.title("Send Basket Info")
3. Adding the Table Headers
To guide the user, headers are added to the GUI:
header_frame = tk.Frame(self.rows_frame)
header_frame.pack(pady=5)
tk.Label(header_frame, text="Ticker").grid(row=0, column=0, padx=5)
tk.Label(header_frame, text="Quantity").grid(row=0, column=1, padx=5)
tk.Label(header_frame, text="Action").grid(row=0, column=2, padx=5)
tk.Label(header_frame, text="Order Type").grid(row=0, column=3, padx=5)
These headers represent the order details:
4. Adding Input Rows
Users can dynamically add rows for multiple orders.
def add_row(self):
row_frame = tk.Frame(self.rows_frame)
row_frame.pack(pady=2)
# Add input fields for ticker, quantity, action, and order type
ticker_entry = tk.Entry(row_frame, width=15)
quantity_entry = tk.Entry(row_frame, width=10)
# Dropdown menus for action and order type
action_var = tk.StringVar(value="BUY")
action_menu = tk.OptionMenu(row_frame, action_var, "BUY", "SELL")
order_type_var = tk.StringVar(value="MARKET")
order_type_menu = tk.OptionMenu(row_frame, order_type_var, "MARKET", "LIMIT")
Each row includes:
领英推荐
Rows are stored in self.rows for easy retrieval.
5. Writing to the File
Once the user inputs all orders, they can click the "Send to Basket" button to save the details:
def write_to_file(self):
try:
with open(file_path, "w") as file:
for row in self.rows:
ticker = row["ticker"].get().strip()
quantity = row["quantity"].get().strip()
action = row["action"].get()
order_type = row["order_type"].get()
# Validate input
if not ticker or not quantity.isdigit():
self.status_label.config(text="Invalid input.")
return
file.write(f"{ticker},{quantity},{action},{order_type}\n")
except Exception as e:
self.status_label.config(text=f"Error: {e}")
This function:
6. Running the Application
Finally, initialize and run the GUI:
root = tk.Tk()
app = BasketApp(root)
root.mainloop()
Part 2: MQL5 Script
The MQL5 script reads send_basket.txt and executes the orders. Let’s break it down step-by-step:
1. Opening the File
if (!FileIsExist(fileName))
{
Print("The file does not exist.");
return;
}
int fileHandle = FileOpen(fileName, FILE_READ | FILE_TXT | FILE_ANSI);
if (fileHandle == INVALID_HANDLE)
{
Print("Error opening the file: ", GetLastError());
return;
}
This checks for the file's existence and opens it for reading.
2. Reading and Parsing the Orders
The script reads each line of the file:
while (!FileIsEnding(fileHandle))
{
string line = FileReadString(fileHandle);
StringTrimLeft(line);
StringTrimRight(line);
if (line != "")
{
string parts[];
int count = StringSplit(line, ',', parts);
if (count == 4 && !IsInArray(parts[0], sentOrders))
{
// Process the order
}
}
}
3. Sending Orders
Orders are executed using MqlTradeRequest:
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = (double)quantity;
request.type = (action == "BUY") ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
if (orderType == "LIMIT")
{
request.price = (action == "BUY")
? SymbolInfoDouble(symbol, SYMBOL_BID) - 10 * SymbolInfoDouble(symbol, SYMBOL_POINT)
: SymbolInfoDouble(symbol, SYMBOL_ASK) + 10 * SymbolInfoDouble(symbol, SYMBOL_POINT);
}
else if (orderType == "MARKET")
{
request.price = (action == "BUY") ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID);
}
This defines:
4. Tracking Sent Orders
To prevent duplicates, track sent orders:
if (result.retcode == TRADE_RETCODE_DONE)
{
ArrayResize(sentOrders, ArraySize(sentOrders) + 1);
sentOrders[ArraySize(sentOrders) - 1] = symbol;
}
Conclusion
This Python-MQL5 integration automates basket orders efficiently. The Python app simplifies user input, while the MQL5 script ensures orders are executed correctly in MT5. This setup can be extended to include advanced order parameters or error handling.
Let me know if you have questions or need further clarification!