Summary: Detailed technical guide to OrderSend in MQL4. Covers stop loss/takeprofit normalization using MarketInfo, preventing error 130, and proper return value handling. Includes ready-to-use code examples.




# 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:
  • Always query `MODE_STOPLEVEL` at runtime (never hardcode)

  • Add buffer: `minStopLevel + 10-20` points

  • Always use `NormalizeDouble()` with `Digits`

  • Verify SL/TP direction: For BUY, SL must be below Ask, TP above Ask


  • 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:
  • [ ] Prices normalized with `NormalizeDouble(value, Digits)`

  • [ ] Stop loss distance > MarketInfo(MODE_STOPLEVEL) + buffer

  • [ ] Take profit distance > MarketInfo(MODE_STOPLEVEL) + buffer

  • [ ] Lot size meets broker minimums

  • [ ] Trade context available (`IsTradeAllowed()`)

  • [ ] Free margin sufficient for position


  • References:
    1. MQL4 Documentation – OrderSend function (docs.mql4.com)
    2. Titan FX – MQL4 programming guide (2026)
    3. Official MetaQuotes – MQL4 Reference