MQL5 OrderSend() Guide: Syntax, MqlTradeRequest, Errors, and EA Best Practices

目次

1. What Is MQL5 OrderSend()?

OrderSend() is the MQL5 (MetaQuotes Language 5) function used to send actual trade orders to a broker.
When you build an EA (Expert Advisor), this function becomes the core feature of the order execution process.

In MetaTrader 5, detecting a buy or sell signal does not execute a trade by itself.
The EA must perform the following steps.

  • Create the order details
  • Send them to the broker
  • Check the execution result

In this sequence, OrderSend() is responsible for sending the order.

In MQL5, orders are processed in the following structure.

EA
 ↓
OrderSend()
 ↓
Trade server
 ↓
Execution result

In other words, OrderSend() is the interface that sends the order request created by the EA to the trade server.

MQL5 OrderSend execution flow diagram showing how an Expert Advisor creates a MqlTradeRequest, sends it to the trade server, and validates the MqlTradeResult using retcode, with Buy/Sell price handling (Ask/Bid), SL/TP levels, and error cases such as invalid volume or invalid price.

1.1 Role of OrderSend()

OrderSend() sends the following information together to execute a trade order.

Main order information

  • Currency pair to trade, such as EURUSD
  • Trade direction, Buy or Sell
  • Lot size
  • Order price
  • Stop Loss (SL)
  • Take Profit (TP)

In MQL5, this information is stored in structures, which are grouped data containers, and then sent.

Specifically, the following two structures are used.

StructureRole
MqlTradeRequestStores the order details
MqlTradeResultReceives the order result

The process flow is as follows.

1 Create the order details
2 Run OrderSend()
3 Check the result

A simple code image looks like this.

MqlTradeRequest request;
MqlTradeResult  result;

OrderSend(request, result);

When this function runs, the order is sent to the trade server,
and the result is stored in result.

1.2 Difference from MT4 OrderSend()

MQL5 OrderSend() is designed very differently from MetaTrader 4 (MQL4).

In MT4, the order function used a single-function format like this.

OrderSend(Symbol(),OP_BUY,0.1,Ask,10,0,0);

In MQL5, by contrast, the design is structure based.

The reasons are as follows.

  • Order information became more extensive and complex
  • Server-side processing became more advanced
  • The design needed better extensibility

Therefore, in MQL5, you first collect the order information in a structure called

MqlTradeRequest

and then run OrderSend().

Because of this difference, even traders with MT4 experience often get confused at first.

Common points that confuse beginners

  • You cannot write it the same way as MT4
  • The structure must be initialized
  • The way to get prices is different

This is one of the most common early problems in EA development.

1.3 Typical Cases Where OrderSend() Is Needed

OrderSend() is used in the following situations.

1. Automated Trading by an EA

This is the most common use case.

Example

RSI is 30 or lower → Buy
RSI is 70 or higher → Sell

In this case, OrderSend() handles the process that actually executes the trade.

2. Limit Orders and Stop Orders

An EA can also create the following orders.

  • Buy Limit (buying on a pullback)
  • Sell Limit (selling on a rebound)
  • Buy Stop (breakout)
  • Sell Stop (breakout)

These pending orders are also sent with OrderSend().

3. Multi-Currency EAs

In MT5, many EAs are built to handle the following at the same time.

  • Multiple currency pairs
  • Multiple timeframes

In this case as well, OrderSend() is executed for each currency pair.

Common Beginner Pitfalls

In EA development, the following mistakes often happen around OrderSend().

Common failures

1. The price is not set

→ The order is rejected

2. The lot size is outside broker limits

Invalid volume error

3. SL/TP is too close

Invalid stops error

4. The symbol is not set

request.symbol=""

→ The order cannot be placed

5. Ask and Bid are used incorrectly

OrderPrice
BuyAsk
SellBid

These problems become easier to solve once you understand the order structure explained in the next chapter.

2. Basic Syntax and Function Specification of OrderSend()

OrderSend() is the core function for executing trade orders in MQL5.
It sends the order information created by the EA to the trade server and receives the order result.

In MQL5, order information is not passed directly through many separate arguments. Instead, it is stored in a structure, or grouped data container, before being sent.

2.1 Function Syntax of OrderSend()

The basic syntax of OrderSend() in MQL5 is as follows.

bool OrderSend(
   MqlTradeRequest& request,
   MqlTradeResult&  result
);

The arguments mean the following.

ArgumentDescription
requestStructure that stores the order details
resultStructure that receives the order result

The return value is a bool.

Return valueMeaning
trueThe order was successfully sent to the server
falseThe order send operation failed

However, one important point is that true does not always mean the order was filled.

When OrderSend() succeeds, it means this.

The order reached the server

You must check result to know the actual order result.

2.2 MqlTradeRequest (Order Information)

MqlTradeRequest is the structure that stores order details.
You set the required information in it before running OrderSend().

The main members are as follows.

ItemMeaning
actionOrder action
symbolCurrency pair
volumeLot size
typeOrder direction
priceOrder price
slStop Loss
tpTake Profit
deviationAllowed slippage
magicEA identification number

Even in a minimum setup, you usually set the following.

action
symbol
volume
type
price

If these are not set correctly in an EA, the order will be rejected.

2.3 MqlTradeResult (Order Result)

MqlTradeResult is the structure that receives the order result.

The main members are as follows.

ItemMeaning
retcodeServer response code
dealDeal ticket
orderOrder ticket
priceExecution price

The especially important member is this.

retcode

It is the code that indicates the order result, and you should always check it in EA development.

Example

TRADE_RETCODE_DONE

Meaning

Order successful

There are also codes like these.

retcodeMeaning
TRADE_RETCODE_REJECTOrder rejected
TRADE_RETCODE_INVALID_VOLUMEInvalid lot size
TRADE_RETCODE_INVALID_PRICEInvalid price

In an EA, you check it like this.

if(result.retcode == TRADE_RETCODE_DONE)
{
   Print("Order successful");
}

2.4 Minimum Order Code

A minimum market Buy order example looks like this.

MqlTradeRequest request;
MqlTradeResult  result;

ZeroMemory(request);

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type   = ORDER_TYPE_BUY;
request.price  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

OrderSend(request, result);

This code performs the following steps.

1 Create the order structure
2 Set the order details
3 Send with OrderSend()

In an EA, this process is run when a trade signal occurs.

Common Pitfalls (Important)

The following mistakes are very common when implementing OrderSend().

1. Forgetting ZeroMemory()

If a structure is not initialized, it can contain garbage data.

Always run it.

ZeroMemory(request);

2. Confusing Ask and Bid

OrderPrice
BuyAsk
SellBid

Example

ORDER_TYPE_BUY → Ask
ORDER_TYPE_SELL → Bid

3. volume is outside broker limits

Example

Less than 0.01

and similar cases.

The broker’s minimum lot size differs by environment.

4. deviation is not set

This can cause order rejection in fast-moving markets.

Example

request.deviation = 10;

5. SL/TP is too close

Brokers define a minimum stop distance.

Invalid stops

This can cause the error.

Practical Point

In a real EA, you add the following processing.

  • Error handling
  • retcode checking
  • Log output
  • Retry handling

If you omit this part, it becomes difficult to identify why the EA does not trade.

3. Main MqlTradeRequest Parameters and How to Set Them

To use OrderSend() correctly, understanding each parameter of the MqlTradeRequest structure is essential.
This structure holds all information needed for a trade order.

Many order failures in EA development are caused by incorrect parameter settings.
This section focuses on the items that matter most in real development.

3.1 action (Order Action)

action specifies the order action, or trade operation type.

The commonly used values are as follows.

ValueMeaning
TRADE_ACTION_DEALMarket order
TRADE_ACTION_PENDINGLimit or stop order
TRADE_ACTION_SLTPSL/TP modification
TRADE_ACTION_REMOVEOrder deletion

The most frequently used action in EAs is a market order.

Example

request.action = TRADE_ACTION_DEAL;

For a pending order, it looks like this.

request.action = TRADE_ACTION_PENDING;

3.2 symbol (Currency Pair)

symbol specifies the instrument, or currency pair, to trade.

Usually, you use the following value.

request.symbol = _Symbol;

_Symbol means the currency pair of the current chart.

Examples

EURUSD
USDJPY
XAUUSD

For a multi-currency EA, you must specify it explicitly.

request.symbol = "EURUSD";

3.3 volume (Lot Size)

volume specifies the trade size, or lot size.

Example

request.volume = 0.10;

Be careful because lot size has broker limits.

Main limits

  • Minimum lot
  • Maximum lot
  • Lot step

Example

ItemExample
Minimum lot0.01
Lot step0.01

If you set an invalid value, the following error occurs.

TRADE_RETCODE_INVALID_VOLUME

You can check it in an EA with this function.

SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

3.4 type (Order Direction)

type specifies the trade direction or order type.

Typical values are as follows.

ValueMeaning
ORDER_TYPE_BUYMarket buy
ORDER_TYPE_SELLMarket sell
ORDER_TYPE_BUY_LIMITBuy limit
ORDER_TYPE_SELL_LIMITSell limit
ORDER_TYPE_BUY_STOPBuy stop
ORDER_TYPE_SELL_STOPSell stop

Example

request.type = ORDER_TYPE_BUY;

3.5 price (Order Price)

price specifies the order price.

For market orders

OrderPrice
BuyAsk
SellBid

Example

request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

Sell order

request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);

If the price is set incorrectly, the order will be rejected.

3.6 sl / tp (Stop Loss and Take Profit)

sl is the stop-loss price.
tp is the take-profit price.

Example

request.sl = Ask - 100 * _Point;
request.tp = Ask + 200 * _Point;

Here, _Point means

Minimum price unit

Examples

Currency pair_Point
EURUSD0.00001
USDJPY0.001

3.7 deviation (Slippage Tolerance)

deviation specifies how much price movement is acceptable.

Example

request.deviation = 10;

The unit is

points

If it is not set, orders may be rejected in volatile markets.

3.8 magic (EA Identification Number)

magic is an identification number for the EA.

Setting it lets you distinguish between

  • EA positions
  • Manual positions

Example

request.magic = 123456;

In EA development, it is almost a required parameter.

Common Pitfalls

The most common mistakes in MqlTradeRequest settings are summarized below.

1. price is not set

Invalid price

This causes an error.

2. symbol is not set

request.symbol = ""

The order fails.

3. volume is too small

Invalid volume

4. SL / TP is too close

Invalid stops

Each broker has a minimum stop distance.

5. action and type do not match

Example

TRADE_ACTION_DEAL
+
ORDER_TYPE_BUY_LIMIT

This is a contradictory setting.

Practical Tip

In EAs, the following initialization is commonly used.

MqlTradeRequest request;
MqlTradeResult result;

ZeroMemory(request);
ZeroMemory(result);

This helps prevent bugs caused by undefined data.

4. Practical OrderSend() Code Examples (Market Orders)

This section explains the basic implementation for placing market orders, meaning buy or sell orders executed immediately, with OrderSend() in MQL5.
For beginners, the first code to run should be the minimum setup for a Buy order and a Sell order.

A market order uses the current market price.
However, simply calling OrderSend() is not enough. At minimum, you need to understand the following three points.

  • Initialize MqlTradeRequest correctly
  • Use Ask for Buy and Bid for Sell
  • Check the result with result.retcode

4.1 Buy Order Sample Code

First, here is the most basic market Buy order.

void BuyOrder()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   request.action    = TRADE_ACTION_DEAL;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_BUY;
   request.price     = ask;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "MQL5 Buy Order";

   if(OrderSend(request, result))
   {
      Print("Buy order sent successfully, retcode=", result.retcode);
   }
   else
   {
      Print("Buy order send failed");
   }
}

This code flows as follows.

  • Prepare request and result
  • Initialize them with ZeroMemory()
  • Get the Ask price
  • Set the information needed for the Buy order
  • Run OrderSend()
  • Check the result in the log

For a Buy order, use Ask as the price.

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.price = ask;

If you use Bid here, it can cause order rejection or unexpected behavior depending on the environment and conditions.

4.2 Sell Order Sample Code

Next is a market Sell order.

void SellOrder()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   request.action    = TRADE_ACTION_DEAL;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_SELL;
   request.price     = bid;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "MQL5 Sell Order";

   if(OrderSend(request, result))
   {
      Print("Sell order sent successfully, retcode=", result.retcode);
   }
   else
   {
      Print("Sell order send failed");
   }
}

For a Sell order, use Bid as the price.

double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.price = bid;

Price selection for market orders is a point beginners often get wrong.
It is safer to remember the following mapping first.

Order typePrice to use
BuyAsk
SellBid

4.3 Practical Example with SL and TP

In real operation, Stop Loss and Take Profit are often set at the same time.
The following example adds sl and tp to a Buy order.

void BuyOrderWithSLTP()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   request.action    = TRADE_ACTION_DEAL;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_BUY;
   request.price     = ask;
   request.sl        = ask - 100 * _Point;
   request.tp        = ask + 200 * _Point;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "Buy with SLTP";

   if(OrderSend(request, result))
   {
      Print("Buy order sent, retcode=", result.retcode);
   }
   else
   {
      Print("Buy order send failed");
   }
}

Here, the settings are as follows.

  • Stop Loss: 100 points below
  • Take Profit: 200 points above

However, the value of _Point differs by instrument.
Also, brokers may enforce minimum stop-distance limits, so these values are not guaranteed to pass in every environment.

4.4 Setting MagicNumber

In EA development, setting magic is very important.
It is the number that identifies which EA placed the order.

request.magic = 123456;

When MagicNumber is set, you can distinguish the following during later position management.

  • Manual orders
  • Orders from other EAs
  • Orders from the current EA

It is almost required for the following processing.

  • Closing only positions from your EA
  • Running multiple EAs on the same currency pair
  • Organizing operation logs

If you do not set magic, later management becomes much harder.

4.5 Minimum Result Checking

Even when OrderSend() returns true, it does not guarantee the actual order result.
Therefore, at minimum, check result.retcode.

if(OrderSend(request, result))
{
   if(result.retcode == TRADE_RETCODE_DONE)
   {
      Print("Order successful");
   }
   else
   {
      Print("Order was sent but execution failed, retcode=", result.retcode);
   }
}
else
{
   Print("OrderSend itself failed");
}

A common beginner mistake is judging the order as successful just because true was returned.
In real development, checking retcode is part of the same order process.

Common Pitfalls, Notes, and Mistakes

1. Using Bid for a Buy order

If the price mapping is reversed, it can cause order rejection or faulty behavior.

  • Buy → Ask
  • Sell → Bid

2. Omitting ZeroMemory()

Unwanted data may remain in the structure and lead to failures that are hard to explain.

ZeroMemory(request);
ZeroMemory(result);

It is safer to include this every time as a basic habit.

3. Not checking retcode

The return value of OrderSend() alone is not enough.
Without checking result.retcode, you cannot know why the order failed.

4. Lot size does not match the environment

0.10 is not always valid.
Minimum lot and lot step differ by account and instrument.

5. SL/TP distance is too close

If broker limits are violated, you get Invalid stops.
When using fixed values, consider environment differences.

6. Assuming NormalizeDouble() is always required

It is useful in some price calculations, but mechanically applying NormalizeDouble() everywhere is not the right approach.
First make the price retrieval and calculation logic correct, then use it only where needed.

5. Implementing Limit Orders and Stop Orders

OrderSend() supports not only market orders but also limit orders and stop orders.
In EA development, pending orders are often used for breakout strategies, buying pullbacks, and selling rebounds. Understanding them greatly expands the strategies you can implement.

The main difference from a market order is that the order is not executed immediately. It is triggered when the specified price is reached.
Therefore, in addition to setting action and type, you must correctly understand where to place the price.

5.1 Basics of Limit Orders and Stop Orders

For pending orders, set action as follows.

request.action = TRADE_ACTION_PENDING;

Then select the order type with type.

Order typeMeaning
ORDER_TYPE_BUY_LIMITBuy below the current price
ORDER_TYPE_SELL_LIMITSell above the current price
ORDER_TYPE_BUY_STOPBuy above the current price
ORDER_TYPE_SELL_STOPSell below the current price

First, organize and memorize this relationship.

Price placement image

  • Buy Limit
    Wait for a pullback and buy below the current price
  • Sell Limit
    Wait for a rebound and sell above the current price
  • Buy Stop
    Confirm an upside breakout and buy above the current price
  • Sell Stop
    Confirm a downside breakout and sell below the current price

If you understand this backward, the EA will place orders in the opposite location from what you intended, which is critical in live operation.

5.2 Buy Limit Implementation Example

Use a Buy Limit when you place a buy order below the current price.

void PlaceBuyLimit()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double price = ask - 100 * _Point;

   request.action    = TRADE_ACTION_PENDING;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_BUY_LIMIT;
   request.price     = price;
   request.sl        = price - 100 * _Point;
   request.tp        = price + 200 * _Point;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "Buy Limit";

   if(OrderSend(request, result))
      Print("Buy Limit sent, retcode=", result.retcode);
   else
      Print("Buy Limit send failed");
}

In this example, the Buy Limit is placed 100 points below the current Ask.

The key point is that the Buy Limit price must be below the current price.
If you place it above, the order becomes invalid.

5.3 Sell Limit Implementation Example

Use a Sell Limit when you place a sell order above the current price.

void PlaceSellLimit()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double price = bid + 100 * _Point;

   request.action    = TRADE_ACTION_PENDING;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_SELL_LIMIT;
   request.price     = price;
   request.sl        = price + 100 * _Point;
   request.tp        = price - 200 * _Point;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "Sell Limit";

   if(OrderSend(request, result))
      Print("Sell Limit sent, retcode=", result.retcode);
   else
      Print("Sell Limit send failed");
}

Sell Limit is often used in rebound-selling EAs.
Here again, the price relationship matters: a Sell Limit is placed above the current price.

5.4 Buy Stop Implementation Example

A Buy Stop is a pending order that places a buy order above the current price.
It is often used in strategies that confirm a new high or upside breakout.

void PlaceBuyStop()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double price = ask + 100 * _Point;

   request.action    = TRADE_ACTION_PENDING;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_BUY_STOP;
   request.price     = price;
   request.sl        = price - 100 * _Point;
   request.tp        = price + 200 * _Point;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "Buy Stop";

   if(OrderSend(request, result))
      Print("Buy Stop sent, retcode=", result.retcode);
   else
      Print("Buy Stop send failed");
}

A Buy Stop is placed above the current price.
If you use this while intending to buy a pullback, the logic becomes completely reversed.

5.5 Sell Stop Implementation Example

A Sell Stop is a pending order that places a sell order below the current price.
It is used for strategies that confirm a break below a low or a downside breakout.

void PlaceSellStop()
{
   MqlTradeRequest request;
   MqlTradeResult  result;

   ZeroMemory(request);
   ZeroMemory(result);

   double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double price = bid - 100 * _Point;

   request.action    = TRADE_ACTION_PENDING;
   request.symbol    = _Symbol;
   request.volume    = 0.10;
   request.type      = ORDER_TYPE_SELL_STOP;
   request.price     = price;
   request.sl        = price + 100 * _Point;
   request.tp        = price - 200 * _Point;
   request.deviation = 10;
   request.magic     = 123456;
   request.comment   = "Sell Stop";

   if(OrderSend(request, result))
      Print("Sell Stop sent, retcode=", result.retcode);
   else
      Print("Sell Stop send failed");
}

A Sell Stop must be placed below the current price.

5.6 Extra Items to Consider for Pending Orders

For pending orders, price-setting consistency is even more important than for market orders.
At minimum, check the following.

  • Whether action = TRADE_ACTION_PENDING is set
  • Whether type is for a pending order
  • Whether the price position is correct relative to the current price
  • Whether sl / tp is too close
  • Whether result.retcode is checked

Depending on the environment, an order expiration setting may also be required.
Because this varies by broker and instrument specification, check type_time and expiration as needed.

Common Pitfalls, Notes, and Mistakes

1. Reversing Limit and Stop

This is the most common mistake.

  • Buy on a pullback → BUY_LIMIT
  • Buy on an upside breakout → BUY_STOP

If these are reversed, the EA logic itself breaks down.

2. Invalid price position

For example, placing a Buy Limit above the current price is invalid.
Placing a Sell Stop above the current price is also invalid.

Understand that each order type has its own price-position rule.

3. Leaving action as TRADE_ACTION_DEAL

This often happens when reusing market-order code.
For pending orders, you must set the following.

request.action = TRADE_ACTION_PENDING;

4. SL/TP direction is reversed

An example is placing SL above and TP below for a Buy-side order.
By trade direction, the rule is as follows.

DirectionSLTP
Buy sideBelowAbove
Sell sideAboveBelow

5. Ignoring retcode

Pending orders are more likely than market orders to be rejected because of specification mismatches.
After sending, always check result.retcode.

6. How to Read MqlTradeResult and Check Order Results

After running OrderSend(), an EA must always perform order-result checking.
Many beginners only look at the OrderSend() return value, true or false, and stop there. That is not enough.

The reason is that the return value of OrderSend() only guarantees this.

Whether the order could be sent to the server

The actual order result, such as success or rejection, becomes clear only when you check the contents of the MqlTradeResult structure.

6.1 Meaning of the OrderSend() Return Value

The return value of OrderSend() is a bool.

bool OrderSend(request, result);

The meaning is as follows.

Return valueMeaning
trueThe order request was sent successfully
falseThe order send operation itself failed

However, even when true is returned, the order is not necessarily executed.

Example

Order send succeeded
↓
Rejected by the server

This can happen normally.

Therefore, always check the following.

result.retcode

6.2 retcode (Most Important Item)

retcode is the server’s order result code.
In an EA, you check this value and branch the processing.

Example

if(result.retcode == TRADE_RETCODE_DONE)
{
   Print("Order successful");
}

Common retcode values are as follows.

retcodeMeaning
TRADE_RETCODE_DONEOrder successful
TRADE_RETCODE_PLACEDPending order placed successfully
TRADE_RETCODE_REJECTOrder rejected
TRADE_RETCODE_INVALID_VOLUMEInvalid lot size
TRADE_RETCODE_INVALID_PRICEInvalid price
TRADE_RETCODE_INVALID_STOPSInvalid SL/TP

In EA development, logging this retcode helps identify the cause of trouble.

6.3 deal (Deal Ticket)

deal is the ticket number of the executed deal.

result.deal

When an order is executed, this value contains the trade ID.

Example

deal = 123456789

You can use this ticket for the following.

  • Getting deal history
  • Trade logs
  • Trade analysis

However, for a pending order, deal is 0 because it has not been executed yet.

6.4 order (Order Ticket)

order is the order ID.

result.order

It is issued for both of the following.

  • Pending orders
  • Market orders

Example

order = 987654321

This ID is used for the following purposes.

  • Order cancellation
  • SL/TP modification
  • Order management

In EA position management, this number is sometimes saved.

6.5 price (Execution Price)

price is the actual execution price.

result.price

With market orders, it may not exactly match the requested price.
This is due to slippage.

Example

ItemPrice
Order price1.10000
Execution price1.10002

This difference depends on market liquidity and server processing.

6.6 Practical Result-Checking Code

In real development, result checking and log output are often implemented together like this.

if(OrderSend(request, result))
{
   if(result.retcode == TRADE_RETCODE_DONE)
   {
      Print("Order successful");
   }
   else
   {
      Print("Order send succeeded but execution failed retcode=", result.retcode);
   }
}
else
{
   Print("OrderSend send failed");
}

This structure lets you distinguish between the following.

  • Send error
  • Server rejection
  • Successful execution

In EA development, this log becomes the lifeline for debugging.

6.7 Log Output Often Used in EA Development

During EA development, always displaying retcode makes it easier to identify causes.

Example

Print("retcode=", result.retcode);
Print("order=", result.order);
Print("deal=", result.deal);
Print("price=", result.price);

This lets you check the following flow.

Order send
↓
Server response
↓
EA log

Common Pitfalls, Notes, and Mistakes

1. Not checking retcode

The return value of OrderSend() alone cannot determine the order result.

2. Ignoring results other than TRADE_RETCODE_DONE

For pending orders, this is the normal code.

TRADE_RETCODE_PLACED

3. Not logging error codes

Without logs, cause analysis is difficult in EA development.

4. Confusing deal and order

This is a common source of confusion for beginners.

ItemMeaning
orderOrder ID
dealDeal ID

5. Thinking a different execution price is an error

Slippage is normal.
It is not unusual for the price not to match exactly.

Important Practical Point

In practice, EA order processing is designed with this flow.

OrderSend()
↓
Check retcode
↓
Log output
↓
Position management

With this design, handling EA trading problems becomes much easier.

7. Common OrderSend() Errors and How to Fix Them

When developing EAs with OrderSend(), order rejection will inevitably occur.
Especially in a beginner’s first EA, many problems such as “orders do not go through” or “the EA does not trade” are caused by incorrect settings or a mismatch with the trading environment.

This chapter organizes common error causes in real EA development and specific ways to fix them.

7.1 Invalid volume (Invalid Lot Size)

Error code example

TRADE_RETCODE_INVALID_VOLUME

This error occurs when the lot size does not meet the broker’s conditions.

Main causes

  • Below the minimum lot
  • Above the maximum lot
  • Does not match the lot step

Example

Minimum lot 0.01
Lot step 0.01

In this environment,

volume = 0.015

is invalid.

How to fix it

In an EA, it is safer to get the following information first.

double minLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

When calculating the lot size, you need to adjust it to match the step.

7.2 Invalid price (Invalid Price)

Error code example

TRADE_RETCODE_INVALID_PRICE

Causes

  • price is not set
  • Bid / Ask is used incorrectly
  • The price position of a pending order is invalid

Example

Placed a Buy Limit above the current price

This violates the specification.

How to fix it

Organize the basic rules.

OrderPrice
BuyAsk
SellBid

For pending orders, always check the positional relationship with the current price.

Order typePrice position
Buy LimitBelow current price
Sell LimitAbove current price
Buy StopAbove current price
Sell StopBelow current price

7.3 Invalid stops (Invalid SL / TP)

Error code example

TRADE_RETCODE_INVALID_STOPS

Causes

  • SL is too close
  • TP is too close
  • SL / TP direction is wrong

Brokers define a minimum stop distance.

Example

StopLevel = 20 points

In this case, SL / TP within 20 points will be rejected.

How to fix it

You can get the following information in an EA.

int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

When setting SL / TP, you must place it farther away than this value.

7.4 Trade disabled (Trading Not Allowed)

Error code example

TRADE_RETCODE_TRADE_DISABLED

Causes

  • The symbol is not tradable
  • The market is closed
  • Automated trading is disabled

How to fix it

Check the following settings.

  1. The “Algo Trading” button in MT5 is ON
  2. “Algo Trading” is allowed in the EA settings
  3. The market is within trading hours

The EA can also perform the following check.

bool tradeAllowed = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);

7.5 Not enough money (Insufficient Margin)

Error code example

TRADE_RETCODE_NO_MONEY

Causes

  • Insufficient margin
  • Lot size is too large

How to fix it

Run a margin check before placing the order.

OrderCalcMargin(...)

This is required as part of risk management in an EA.

7.6 Off quotes / Requote

This is order rejection caused by price movement.

Causes

  • Fast market movement
  • Spread widening
  • Lower liquidity

It is especially likely around the following.

  • Economic news releases
  • Market open after the weekend

How to fix it

Set deviation.

request.deviation = 10;

However, if the value is too large, the order may be executed at an unfavorable price.

7.7 Checklist When an EA Does Not Trade

If an EA does not trade, checking in the following order makes it easier to identify the cause.

  1. Is Algo Trading ON?
  2. Are there errors in the log?
  3. Is OrderSend() being executed?
  4. Are you checking retcode?
  5. Is price retrieval correct?
  6. Is the lot size valid?

If you output retcode to the log, cause identification becomes much faster.

Common Pitfalls, Notes, and Mistakes

1. Confusing Ask and Bid

This is the mistake beginners make most often.

2. SL / TP distance is too short

This happens when broker specifications are not considered.

3. Invalid lot size

The minimum lot differs by environment.

4. Forgetting ZeroMemory()

Garbage data in a structure can cause failures.

5. Not checking retcode

In EA development, this is one of the biggest causes of trouble.

Practical Point

In EA development, order errors cannot be completely prevented.
Therefore, in live operation, use the following design.

Order
↓
Check retcode
↓
Retry if failed

Implementing this retry processing greatly improves stability in a real trading environment.

8. EA Design Best Practices for Using OrderSend() Safely

OrderSend() is the core order process in an EA, but in live operation, simply sending an order is not enough.
Because market conditions, server responses, and broker specifications affect execution, a stable EA requires an understanding of order-processing design patterns.

This section summarizes safe order-processing design methods often used in practical EA development.

8.1 Always Run Pre-Order Checks

Before sending an order, an EA should check whether trading is currently possible.

Main items to check

  • Whether automated trading is allowed
  • Whether the market is within trading hours
  • Whether the spread is too large
  • Whether there is enough margin

Example

if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
   Print("Automated trading is not allowed");
   return;
}

Spread-check example

double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);

if(spread > 30)
{
   Print("Skipping order because the spread is too large");
   return;
}

A spread filter is especially important around the following.

  • Economic news releases
  • Market open after the weekend
  • Low liquidity

8.2 Manage Positions

If an EA sends unlimited orders, it can create an unintended large number of positions.
Therefore, check the current number of positions before placing an order.

Example

if(PositionsTotal() > 0)
{
   Print("A position already exists");
   return;
}

You can also manage positions with MagicNumber.

for(int i=0;i<PositionsTotal();i++)
{
   ulong ticket = PositionGetTicket(i);
}

Use this kind of logic to manage the following.

  • Maximum simultaneous positions
  • EA-specific positions

8.3 Retry Processing When an Order Fails

On live accounts, orders can fail for the following reasons.

  • Slippage
  • Price updates
  • Server delay
  • Temporary communication errors

For this reason, EAs often include retry processing.

Example

int retry = 3;

while(retry > 0)
{
   if(OrderSend(request,result))
      break;

   retry--;
   Sleep(500);
}

However, infinite loops are dangerous.
Always limit the maximum number of attempts.

8.4 Always Use MagicNumber

In an EA, use magic to identify orders.

request.magic = 10001;

Setting it lets you distinguish between the following.

  • Manual orders
  • Orders from other EAs
  • Orders from the current EA

It is almost required for position management.

8.5 Always Keep Logs

In EA development, cause analysis becomes difficult without logs.

Minimum information to output

  • retcode
  • order
  • deal
  • price

Example

Print("retcode=", result.retcode);
Print("order=", result.order);
Print("deal=", result.deal);
Print("price=", result.price);

These logs are important in all of the following.

  • Backtesting
  • Forward testing
  • Live accounts

8.6 Basic Structure of EA Order Processing

In a practical EA, order processing usually has the following structure.

Trade signal
↓
Pre-order checks
↓
OrderSend()
↓
Check retcode
↓
Log output
↓
Position management

This structure makes the following much easier.

  • Debugging
  • Operation
  • Improvement

Common Pitfalls, Notes, and Mistakes

1. No order-condition checks

This can cause the EA to send unlimited orders.

2. No MagicNumber

Position management becomes impossible.

3. No log output

You cannot identify why the EA does not work.

4. No retry processing

Order failures commonly happen in live environments.

5. No spread filter

Orders may be executed at dangerous prices during news events.

Practical Design Point

In a stable EA, order processing consists of three elements.

Safety
Stability
Debuggability
  • Safety → Order-condition checks
  • Stability → Retry processing
  • Debuggability → Log output

Implementing these three greatly improves EA quality.

9. FAQ

9.1 Should I Use OrderSend() or the CTrade Class?

Both can place orders, but they fit different use cases.

MethodFeature
OrderSend()Low-level API with detailed control
CTradeWrapper class with simpler code

For beginners, CTrade often keeps the code shorter.
If you want fine control over an EA, OrderSend() is more flexible.

Example (CTrade)

CTrade trade;
trade.Buy(0.1);

Example (OrderSend)

OrderSend(request,result);

If you want to understand an EA’s internal order processing deeply, learning OrderSend() is worthwhile.

9.2 Why Does OrderSend() Return true Even Though the Order Is Not Executed?

The return value of OrderSend() only shows whether the order send operation succeeded.

You must check the actual order result with

result.retcode

Example

if(result.retcode == TRADE_RETCODE_DONE)

Only when this condition is satisfied can you judge the order as successful.

9.3 Why Are the Prices Different for Buy and Sell Orders?

In FX, there are two prices.

PriceMeaning
BidSell price
AskBuy price

The order mapping is as follows.

OrderPrice used
BuyAsk
SellBid

This mechanism exists because of the spread, or the difference between buying and selling prices.

9.4 What Causes the Invalid stops Error?

The main causes are the following three.

  1. SL / TP is too close
  2. SL / TP direction is reversed
  3. The broker’s StopLevel restriction is violated

You can check StopLevel with the following function.

SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

You must set SL/TP farther away than this value.

9.5 Why Is OrderSend() Not Executed?

Common causes are as follows.

  • Algo Trading is OFF
  • Automated trading is disabled in the EA settings
  • The logic condition is not met
  • The error log has not been checked

If an EA does not trade, checking log output first is important.

9.6 Is ZeroMemory() Always Required?

It is not mandatory, but in practice it is almost required.

It prevents uninitialized data from remaining in structures.

Example

ZeroMemory(request);
ZeroMemory(result);

Adding this helps prevent unexplained order failures.

9.7 What Is the Basic Method for Managing Orders in an EA?

In an EA, positions are usually managed with the following method.

  1. Set MagicNumber
  2. Get current positions
  3. Process only positions belonging to the EA

Example

request.magic = 123456;

This lets you distinguish them from the following.

  • Manual trades
  • Trades from other EAs

9.8 Why Do Orders Become Unstable with OrderSend()?

Real markets have the following factors.

  • Price movement
  • Server delay
  • Spread changes
  • Lower liquidity

Therefore, EAs commonly use the following countermeasures.

  • deviation setting
  • Retry processing
  • Spread filter

Implementing these measures improves order stability.