Problem Description
Solution
To open a buy or sell trade programmatically in MQL4, you use the OrderSend() function. This is the primary function for executing trade operations.
Below is a complete, robust code snippet demonstrating how to create wrapper functions for opening Buy and Sell orders. This code includes price normalization and error handling, which are essential for live trading.
MQL4 Code for Opening Trades
//+------------------------------------------------------------------+
//| TradeExecutor.mq4 |
//| User Request |
//| https://www.metaquotes.net|
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input double LotSize = 0.1; // Volume in lots
input int StopLoss = 500; // Stop Loss in points (50 pips on 5-digit broker)
input int TakeProfit = 1000; // Take Profit in points (100 pips on 5-digit broker)
input int Slippage = 3; // Max slippage allowed in points
input int MagicNumber = 12345; // Unique identifier for this EA
//+------------------------------------------------------------------+
//| Function to Open a Buy Order |
//+------------------------------------------------------------------+
void OpenBuy()
{
double openPrice = Ask;
double sl = 0;
double tp = 0;
// Calculate Stop Loss and Take Profit if defined
if(StopLoss > 0)
sl = NormalizeDouble(openPrice - StopLoss * Point, Digits);
if(TakeProfit > 0)
tp = NormalizeDouble(openPrice + TakeProfit * Point, Digits);
// Send the order
int ticket = OrderSend(
Symbol(), // Symbol
OP_BUY, // Operation: Buy
LotSize, // Volume
openPrice, // Price (Ask for Buy)
Slippage, // Slippage tolerance
sl, // Stop Loss
tp, // Take Profit
"Buy Order", // Comment
MagicNumber, // Magic Number
0, // Expiration (0 for market orders)
clrGreen // Arrow Color
);
// Error Handling
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
else
{
Print("Buy order placed successfully. Ticket: ", ticket);
}
}
//+------------------------------------------------------------------+
//| Function to Open a Sell Order |
//+------------------------------------------------------------------+
void OpenSell()
{
double openPrice = Bid;
double sl = 0;
double tp = 0;
// Calculate Stop Loss and Take Profit if defined
if(StopLoss > 0)
sl = NormalizeDouble(openPrice + StopLoss * Point, Digits);
if(TakeProfit > 0)
tp = NormalizeDouble(openPrice - TakeProfit * Point, Digits);
// Send the order
int ticket = OrderSend(
Symbol(), // Symbol
OP_SELL, // Operation: Sell
LotSize, // Volume
openPrice, // Price (Bid for Sell)
Slippage, // Slippage tolerance
sl, // Stop Loss
tp, // Take Profit
"Sell Order", // Comment
MagicNumber, // Magic Number
0, // Expiration
clrRed // Arrow Color
);
// Error Handling
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
else
{
Print("Sell order placed successfully. Ticket: ", ticket);
}
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Example usage: Open a buy trade immediately upon loading
// Note: In a real strategy, you would call these in OnTick() based on logic
// OpenBuy();
return(INIT_SUCCEEDED);
}
Key Components Explained
OrderSend(): This is the core function. It returns the ticket number of the order if successful, or-1if it fails.OP_BUY/OP_SELL: These constants define the direction of the trade.Ask/Bid:- Buy orders open at the Ask price.
- Sell orders open at the Bid price.
NormalizeDouble(..., Digits): This is crucial. Calculated prices (like Stop Loss) often result in floating-point errors (e.g., 1.1234500001). The server will reject these.NormalizeDoublerounds the price to the correct number of decimal places supported by the symbol.Point: This holds the size of the smallest price change (e.g., 0.00001 for 5-digit brokers).- Error Handling: We check if
ticket < 0. If true, we printGetLastError()to the "Experts" tab in the terminal to diagnose issues (e.g., "Not enough money", "Invalid stops").
Q&A: Common Issues with OrderSend
Q: Why do I get Error 130 (ERR_INVALID_STOPS)?
A: This usually happens if your Stop Loss or Take Profit is too close to the current price. Every broker has a MODE_STOPLEVEL (minimum distance). Ensure your SL/TP distance in points is greater than MarketInfo(Symbol(), MODE_STOPLEVEL).
Q: Why do I get Error 131 (ERR_INVALID_TRADE_VOLUME)?
A: The LotSize is incorrect. It might be too small (below MODE_MINLOT), too large (above MODE_MAXLOT), or not a multiple of MODE_LOTSTEP.
Q: How do I handle ECN brokers?
A: Some ECN brokers do not allow setting SL and TP during the initial OrderSend call. You must pass 0 for SL and TP in OrderSend, capture the ticket number, and then immediately use OrderModify() to set the Stop Loss and Take Profit.