When a trade error occurs, we need to notify the user so they can take appropriate action. We will also log relevant trade information to assist in troubleshooting. Some error conditions (such as requotes, timeouts and connection errors) are self-correcting if we simply retry the order placement again.
The first thing we need to do is check the return code from the server. As you'll recall, the MqlTradeResult object that we pass to the OrderSend() function contains the return code from the server in the retcode variable. The complete list of return codes is on page 87.
Return codes 10008 (TRADE_RETCODE_PLACED) and 10009 (TRADE_RETCODE_DONE) indicate that the trade has been placed successfully. If any other code is returned from the server, this indicates a likely error condition. We will create a function to check the return code and evaluate whether the return code indicates an error condition or a successful order placement.
First, we will create an enumeration that will be used as a return value to determine whether an order was placed successfully. This enumeration will be defined in our Trade.mqh file:
enum ENUM_CHECK_RETCODE {
CHECK_RETCODE_OK, CHECK_RETCODE_ERROR, };
The constant CHECK_RETCODE_OK indicates that the trade operation was successful, while the constant CHECK_RETCODE_ERROR indicates that the trade operation has failed.
Next, we'll create a function to check the return code. The CheckReturnCode() function will use the switch- case operators to evaluate a list of return code constants. Depending on the return code passed to the function, the switch operator will return one of the constants from the ENUM_CHECK_RETCODE enumeration above.
Here is the CheckReturnCode() function. This will be placed in the Trade.mqh file: int CheckReturnCode(uint pRetCode)
{ int status; switch(pRetCode) { case TRADE_RETCODE_DONE: case TRADE_RETCODE_DONE_PARTIAL: case TRADE_RETCODE_PLACED: case TRADE_RETCODE_NO_CHANGES: status = CHECK_RETCODE_OK; break;
default: status = CHECK_RETCODE_ERROR; }
return(status); }
The CheckReturnCode() function accepts one parameter, a uint variable named pRetCode. This contains the return code from the MqlTradeResult object.
We declare an integer variable named status, which will hold a value from our ENUM_CHECK_RETCODE enumeration. The switch operator compares the value of pRetCode against a list of return code constants indicated by the case operators. If the value of pRetCode matches any of the case operators, program execution will continue until a break operator is reached, or the switch operator ends.
First, we check for a successful order placement. We've added several return codes that indicate a successful order placement or a non-error condition. If the pRetCode value matches any of the return codes in this list, the status variable is assigned the CHECK_RETCODE_OK constant. Otherwise, the default label is executed and the status variable is assigned the CHECK_RETCODE_ERROR constant. The value of status is returned to the program, and the function exits.
Let's return to our market order placement function and add the CheckReturnCode() function: int checkCode = 0;
OrderSend(request,result);
checkCode = CheckReturnCode(result.retcode);
We declare an integer variable named checkCode. This will hold the return value of the CheckReturnCode() function. We call the OrderSend() function to place the order. Then we pass the result.retcode variable to the CheckReturnCode() function, and store the return value in checkCode.
Next, we will check the value of the checkCode variable to determine whether the return code indicates a successful trade or an error condition. In the event of an error, an alert will be displayed to the user:
if(checkCode == CHECK_RETCODE_ERROR) {
string errDesc = TradeServerReturnCodeDescription(result.retcode); Alert("Open market order: Error ",result.retcode," - ",errDesc); break;
}
If checkCode contains the value of CHECK_RETCODE_ERROR, we obtain an error description from the
TradeServerReturnCodeDescription() function. This function is contained in the errordescription.mqh file, which is installed with MetaTrader 5. To add this file to our project, we place this #include directive at the top of our Trade.mqh file:
#include <errordescription.mqh>
The TradeServerReturnCodeDescription() function returns a string with a description of the error code. This is stored in the errDesc variable. The Alert() function shows the alert popup window with the return code and description:
Next, we will print the order information to the log for troubleshooting purposes. If an error has occurred, this information may be helpful. We will print the order type, the deal number, the return code and description, as well as the order price and the current Bid and Ask prices.
We've created a function to check the order type constant and return a descriptive string describing the order type:
string CheckOrderType(ENUM_ORDER_TYPE pType) {
string orderType;
if(pType == ORDER_TYPE_BUY) orderType = "buy";
else if(pType == ORDER_TYPE_SELL) orderType = "sell";
else if(pType == ORDER_TYPE_BUY_STOP) orderType = "buy stop"; else if(pType == ORDER_TYPE_BUY_LIMIT) orderType = "buy limit"; else if(pType == ORDER_TYPE_SELL_STOP) orderType = "sell stop"; else if(pType == ORDER_TYPE_SELL_LIMIT) orderType = "sell limit";
else if(pType == ORDER_TYPE_BUY_STOP_LIMIT) orderType = "buy stop limit"; else if(pType == ORDER_TYPE_SELL_STOP_LIMIT) orderType = "sell stop limit"; else orderType = "invalid order type";
return(orderType); }
This function is defined in the Trade.mqh file. It is a public function that can be used anywhere in our program. The pType parameter contains a value of the ENUM_ORDER_TYPE enumeration. We use if-else operators to evaluate the value of pType and assign the appropriate string value to the orderType string variable. The string is then returned to the program. Note that we could have used the switch-case
operators here, but we wanted to keep this function simple, and it doesn't require the advanced functionality of the switch operator that was necessary in our CheckReturnCode() function.
We'll use the CheckOrderType() and TradeServerReturnCodeDescription() functions to retrieve strings describing our order type and return code. Then we'll call the Print() function to print the trade information to the log:
string orderType = CheckOrderType(pType);
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("Open ",orderType," order #",result.deal,": ",result.retcode," - ",errDesc, ", Volume: ",result.volume,", Price: ",result.price,", Bid: ",result.bid, ", Ask: ",result.ask);
If we examine the experts log, here is what the Print() function output will look like for a successful buy market order:
Open Buy order #105624: 10009 - Request is completed, Volume: 0.1, Price: 1.31095, Bid: 1.31076, Ask: 1.31095
Finally, we will evaluate the return code to determine whether to return a true or false value to the program. If the order was placed successfully, we will print a comment to the chart:
if(checkCode == CHECK_RETCODE_OK) {
Comment(orderType," position opened at ",result.price," on ",pSymbol); return(true);
}
else return(false);
If the checkCode variable contains the value of CHECK_RETCODE_OK, we will print a comment to the chart and return a value of true, indicating that the trade operation was successful. Otherwise, we will return a value of false. Fig. 10.2 shows a chart comment placed on successful
order completion.