Building a Python Application to Automate Basket Orders in MetaTrader 5 with MQL5

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:

  • Create a user-friendly interface to input multiple orders with parameters such as ticker symbols, quantities, actions (BUY/SELL), and order types (MARKET/LIMIT).
  • Write the order details to a file named send_basket.txt.



MQL5 Script:

  • Read send_basket.txt in MT5, parse the orders, and execute them.
  • Ensure that each order is processed only once to avoid duplicates.


Add Expert To MQL5 Graph



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")        

  • self.root initializes the main application window.
  • self.root.title() sets the window title.


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:

  • Ticker (e.g., WDOZ24)
  • Quantity (e.g., 2)
  • Action (BUY/SELL)
  • Order Type (MARKET/LIMIT).


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:

  • Text fields (Entry) for the ticker and quantity.
  • Dropdown menus (OptionMenu) for action and order type.

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:

  1. Validates the inputs.
  2. Saves the orders to send_basket.txt in a CSV-like format.


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
        }
    }
}        

  • Each line is split into components: Ticker, Quantity, Action, and Order Type.
  • Orders are tracked using the sentOrders array to prevent duplicates.


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:

  • action: BUY or SELL.
  • orderType: MARKET or LIMIT.
  • price: Derived from bid/ask values.


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!






要查看或添加评论,请登录

Eurico Paes的更多文章

社区洞察

其他会员也浏览了