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:

  • StopLoss or TakeProfit levels are too close to market price

  • StopLoss/TakeProfit values are not normalized to Digits

  • 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:
  • MQL4 Documentation – OrderSend function (docs.mql4.com)

  • Titan FX – MQL4 programming guide (2026)

  • Official MetaQuotes – MQL4 Reference