- Expert Advisors main event: OnTick
- Basic principles and concepts: order, deal, and position
- Types of trading operations
- Order types
- Order execution modes by price and volume
- Pending order expiration dates
- Margin calculation for a future order: OrderCalcMargin
- Estimating the profit of a trading operation: OrderCalcProfit
- MqlTradeRequest structure
- MqlTradeCheckResult structure
- Request validation: OrderCheck
- Request sending result: MqlTradeResult structure
- Sending a trade request: OrderSend and OrderSendAsync
- Buying and selling operations
- Modying Stop Loss and/or Take Profit levels of a position
- Trailing stop
- Closing a position: full and partial
- Closing opposite positions: fill and partial
- Placing a pending order
- Modifying a pending order
- Deleting a pending order
- Getting a list of active orders
- Order properties (active and historical)
- Functions for reading properties of active orders
- Selecting orders by properties
- Getting the list of positions
- Position properties
- Functions for reading position properties
- Deal properties
- Selecting orders and deals from history
- Functions for reading order properties from history
- Functions for reading deal properties from history
- Types of trading transactions
- OnTradeTransaction event
- Synchronous and asynchronous requests
- OnTrade event
- Monitoring trading environment changes
- Creating multi-symbol Expert Advisors
- Limitations and benefits of Expert Advisors
- Creating Expert Advisors in the MQL Wizard
Placing a pending order
In Types of orders, we theoretically considered all options for placing pending orders supported by the platform. From a practical point of view, orders are created using OrderSend/OrderSendAsync functions, for which the request structure MqlTradeRequest is prefilled according to special rules. Specifically, the action field must contain the TRADE_ACTION_PENDING value from the ENUM_TRADE_REQUEST_ACTIONS enumeration. With this in mind, the following fields are mandatory:
- action
- symbol
- volume
- price
- type (default value 0 corresponds to ORDER_TYPE_BUY)
- type_filling (default 0 corresponds to ORDER_FILLING_FOK)
- type_time (default value 0 corresponds to ORDER_TIME_GTC)
- expiration (default 0, not used for ORDER_TIME_GTC)
If zero defaults are suitable for the task, some of the last four fields can be skipped.
The stoplimit field is mandatory only for orders of types ORDER_TYPE_BUY_STOP_LIMIT and ORDER_TYPE_SELL_STOP_LIMIT.
The following fields are optional:
- sl
- tp
- magic
- comment
Zero values in sl and tp indicate the absence of protective levels.
Let's add the methods for checking values and filling fields into our structures in the MqlTradeSync.mqh file. The principle of formation of all types of orders is the same, so let's consider a couple of special cases of placing limit buy and sell orders. The remaining types will differ only in the value of the field type. Public methods with a full set of required fields, as well as protective levels, are named according to types: buyLimit and sellLimit.
ulong buyLimit(const string name, const double lot, const double p,
|
Since the structure contains the symbol field which is optionally initialized in the constructor, there are similar methods without the name parameter: they call the above methods by passing symbol as the first parameter. Thus, to create an order with minimal effort, write the following:
MqlTradeRequestSync request; // by default uses the current chart symbol
|
The general part of the code for checking the passed values, normalizing them, saving them in structure fields, and creating a pending order has been moved to the helper method _pending. It returns the order ticket on success or 0 on failure.
ulong _pending(const string name, const double lot, const double p,
|
We already know how to fill the action field and how to call the setSymbol and setVolumePrices methods from previous trading operations.
The multi-string if operator ensures that the operation being prepared is present among the allowed symbol operations specified in the SYMBOL_ORDER_MODE property. Integer type division type which divides in half and shifts the resulting value by 1, sets the correct bit in the mask of allowed order types. This is due to the combination of constants in the ENUM_ORDER_TYPE enumeration and the SYMBOL_ORDER_MODE property. For example, ORDER_TYPE_BUY_STOP and ORDER_TYPE_SELL_STOP have the values 4 and 5, which when divided by 2 both give 2 (with decimals removed). Operation 1 << 2 has a result 4 equal to SYMBOL_ORDER_STOP.
A special feature of pending orders is the processing of the expiration date. The setExpiration method deals with it. In this method, it should be ensured that the specified expiration mode ENUM_ORDER_TYPE_TIME of duration is allowed for the symbol and the date and time in until are filled in correctly.
bool setExpiration(ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
|
The bitmask of allowed modes is available in the SYMBOL_EXPIRATION_MODE property. The combination of bits in the mask and the constants ENUM_ORDER_TYPE_TIME is such that we just need to evaluate the expression 1 << duration and superimpose it on the mask: a non-zero value indicates the presence of the mode.
For the ORDER_TIME_SPECIFIED and ORDER_TIME_SPECIFIED_DAY modes, the expiration field with the specific datetime value cannot be empty. Also, the specified date and time cannot be in the past.
Since the _pending method presented earlier sends a request to the server using OrderSend in the end, our program must make sure that the order with the received ticket was actually created (this is especially important for limit orders that can be output to an external trading system). Therefore, in the completed method, which is used for "blocking" control of the result, we will add a branch for the TRADE_ACTION_PENDING operation.
bool completed()
|
In the MqlTradeResultSync structure, we add the placed method.
bool placed(const ulong msc = 1000)
|
Its main task is to wait for the order to appear using the wait in the orderExist function: it has already been used in the first stage of verification of position opening.
To test the new functionality, let's implement the Expert Advisor PendingOrderSend.mq5. It enables the selection of the pending order type and all its attributes using input variables, after which a confirmation request is executed.
enum ENUM_ORDER_TYPE_PENDING
|
The Expert Advisor will create a new order every time it is launched or parameters are changed. Automatic order removal is not yet provided. We will discuss this operation type later. In this regard, do not forget to delete orders manually.
A one-time order placement is performed, as in some previous examples, based on a timer (therefore, you should first make sure that the market is open).
void OnTimer()
|
The PlaceOrder function accepts all settings as parameters, sends a request, and returns a success indicator (non-zero ticket). Orders of all supported types are provided with pre-filled distances from the current price which are calculated as part of the daily range of quotes.
ulong PlaceOrder(const ENUM_ORDER_TYPE type,
|
For example, the coefficient of -0.5 for ORDER_TYPE_BUY_LIMIT means that the order will be placed below the current price by half of the daily range (rebound inside the range), and the coefficient of +1.0 for ORDER_TYPE_BUY_STOP means that the order will be at the upper border of the range (breakout).
The daily range itself is calculated as follows.
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
|
We find the volume and point values that will be required below.
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
|
The price level for placing an order is calculated in the price variable based on the given coefficients from the total range.
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type]; |
The stoplimit field must be filled only for *_STOP_LIMIT orders. The values for it are stored in the origin variable.
const bool stopLimit =
|
When these two types of orders are triggered, a new pending order will be placed at the current price. Indeed, in this scenario, the price moves from the current value to the price level, where the order is activated, and therefore the "former current" price becomes the correct rebound level indicated by a limit order. We will illustrate this situation below.
Protective levels are determined using the TU::TradeDirection object. For stop-limit orders, we calculated starting from origin.
TU::TradeDirection dir(type);
|
Next, the structure is described and the optional fields are filled in.
MqlTradeRequestSync request(symbol);
|
Here you can select the fill mode. By default, MqlTradeRequestSync automatically selects the first of the allowed modes, ENUM_ORDER_TYPE_FILLING.
Depending on the order type chosen by the user, we call one or another trading method.
ResetLastError();
|
If the ticket is received, we wait for it to appear in the trading environment of the terminal.
if(order != 0)
|
Let's run the Expert Advisor on the EURUSD chart with default settings and additionally select the distance to the protective levels of 1000 points. We will see the following entries in the log (assuming that the default settings match the permissions for EURUSD in your account).
Autodetected daily range: 0.01413
|
Here is what it looks like on the chart:
Pending order ORDER_TYPE_BUY_STOP
Let's delete the order manually and change the order type to ORDER_TYPE_BUY_STOP_LIMIT. The result is a more complex picture.
Pending order ORDER_TYPE_BUY_STOP_LIMIT
The price where the upper pair of dash-dotted lines is located is the order trigger price, as a result of which an ORDER_TYPE_BUY_LIMIT order will be placed at the current price level, with Stop Loss and Take Profit values marked with red lines. The Take Profit level of the future ORDER_TYPE_BUY_LIMIT order practically coincides with the activation level of the newly created preliminary order ORDER_TYPE_BUY_STOP_LIMIT.
As an additional example for self-study, an Expert Advisor AllPendingsOrderSend.mq5 is included with the book; the Expert Advisor sets 6 pending orders at once: one of each type.
Pending orders of all types
As a result of running it with default settings, you may get log entries as follows:
Autodetected daily range: 0.01413
|