# MQL4 OrderSend Function: Advanced Order Placement Guide
Understanding OrderSend Fundamentals
The `OrderSend()` function is the core order placement mechanism in MQL4. While it appears straightforward, improper usage accounts for over 70% of EA runtime errors, particularly error 130 (Invalid stops).
Function signature:
```cpp
int OrderSend(
string symbol, // symbol
int cmd, // operation (OP_BUY, OP_SELL)
double volume, // lot size
double price, // order price
int slippage, // allowed slippage in points
double stoploss, // stop loss price
double takeprofit, // take profit price
string comment, // order comment
int magic, // magic number
datetime expiration, // pending order expiry
color arrow_color // arrow color on chart
);
```
Critical Stop Loss/Take Profit Rules
The STOPLEVEL Constraint
Stop Loss and Take Profit levels cannot be placed too close to the current market price. The minimum distance is broker-specific and must be queried dynamically.
MQL4 official documentation states: *"StopLoss and TakeProfit levels cannot be too close to the market. The minimal distance of stop levels in points can be obtained using the MarketInfo() function with MODE_STOPLEVEL parameter. In the case of erroneous or unnormalized stop levels, the error 130 (ERR_INVALID_STOPS) will be generated."*
Correct Stop Loss Calculation
```cpp
// Get minimum stop distance
double minStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
// Calculate SL and TP with proper buffer
double stopLoss = NormalizeDouble(
Bid - (minStopLevel + 10) * Point,
Digits
);
double takeProfit = NormalizeDouble(
Ask + (minStopLevel + 10) * Point,
Digits
);
```
The critical error many developers make: using `minStopLevel` directly without adding a buffer. If the minimum is 20 points, placing SL at exactly 20 points risks rejection. Always add a safety margin.
Complete Order Placement Example
```cpp
//+------------------------------------------------------------------+
//| Safe order placement with full error handling |
//+------------------------------------------------------------------+
void PlaceBuyOrder(double lotSize)
{
// 1. Get current prices
double currentAsk = Ask;
double currentBid = Bid;
// 2. Get minimum stop distance
double minStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
// 3. Validate stop level exists
if(minStopLevel < 10)
{
Print("Warning: minStopLevel too low: ", minStopLevel);
minStopLevel = 50; // fallback value
}
// 4. Calculate normalized SL/TP with buffer
double stopLoss = NormalizeDouble(
currentBid - (minStopLevel + 15) * Point,
Digits
);
double takeProfit = NormalizeDouble(
currentAsk + (minStopLevel + 30) * Point,
Digits
);
// 5. Validate prices are normalized
stopLoss = NormalizeDouble(stopLoss, Digits);
takeProfit = NormalizeDouble(takeProfit, Digits);
// 6. Send order
int ticket = OrderSend(
Symbol(), // symbol
OP_BUY, // operation
lotSize, // volume
currentAsk, // price
3, // slippage
stopLoss, // stoploss
takeProfit, // takeprofit
"Technical Buy", // comment
magicNumber, // magic
0, // expiration
clrGreen // arrow color
);
// 7. Error handling
if(ticket < 0)
{
int error = GetLastError();
switch(error)
{
case 130:
Print("Error 130: Invalid stops. minStopLevel=", minStopLevel);
break;
case 129:
Print("Error 129: Invalid price. Ask=", currentAsk);
break;
case 138:
Print("Error 138: Requote. Price outdated");
break;
default:
Print("OrderSend failed. Error #", error);
}
}
else
{
Print("Order placed. Ticket: ", ticket);
}
}
```
Error 130 Deep Dive
Error 130 (ERR_INVALID_STOPS) is the most frequent order placement failure. According to MQL4 documentation, it occurs when:
1. StopLoss or TakeProfit levels are too close to market price
2. StopLoss/TakeProfit values are not normalized to Digits
3. For pending orders, the open price is too close to market
Prevention checklist:
Slippage Parameter Considerations
For market orders (OP_BUY/OP_SELL), only the current Bid (for sell) or Ask (for buy) can be used as open price. The slippage parameter allows execution within `price ± slippage` range.
Best practice: Set slippage between 1-5 points for normal conditions, 10-20 points during high volatility events.
Magic Number Usage
The magic parameter serves as a unique identifier for your EA. Always use distinct magic numbers when running multiple EAs on the same account to prevent cross-interference. A common approach:
```cpp
#define MAGIC_BASE 20240601
input int MagicNumber = MAGIC_BASE; // User-modifiable
```
Summary Checklist
Before calling OrderSend, verify:
References:
1. MQL4 Documentation – OrderSend function (docs.mql4.com)
2. Titan FX – MQL4 programming guide (2026)
3. Official MetaQuotes – MQL4 Reference