MQL5 - Trading Operations

Hello everyone! Today we have finally reached trading operations. First, we will get acquainted with the terminology of the MT5 platform, and then we will look at how to make an expert advisor trade.

Previous lessons

    Orders

    Orders are requests to perform trading operations accepted by the trading server and formalized in accordance with the requirements of the MetaTrader 5 platform. Orders can be for immediate execution, for example, to buy or sell a certain volume of a specified financial instrument at the current market price. Another type of order is pending orders, which contain an instruction to perform a trading operation under a certain condition. Pending orders can also contain a limit on their validity period - the expiration date.

    Active (pending) orders that are waiting for the conditions of their execution or cancellation are shown in the terminal in the "Trade" tab. These orders can be modified or canceled. Placing, canceling, and modifying orders is done using the OrderSend() function, which we will look at today. If an order was canceled, or its validity period expired, or it was executed, then it is moved to the order history. Executed and canceled orders are shown in the terminal in the "History" tab. Orders from the history are unavailable for modification; they have already done their job.

    Deals

    Deals are the result of the execution of an order (an instruction to perform a trading operation). Each deal is based on one specific order, but one order can generate many deals. For example, an instruction to buy 10 lots can be executed with the help of several consecutive deals in the case of partial execution. Deals are always in the trading history and cannot be modified. In the terminal, deals are displayed in the "History" tab.

    Positions

    Positions are the presence of bought or sold contracts for a financial instrument. A long position (Long) is formed as a result of purchases in anticipation of a price increase, a short position (Short) is the result of selling an asset in expectation of a price decline in the future. In one account, only one position can exist for each financial instrument. For each symbol, at any given time there can be only one open position - long or short.

    The position volume can increase as a result of a new trading operation in the same direction. That is, the volume of a long position will be increased after a new purchase (Buy operation) or reduced after a sale (Sell operation). A position is considered closed if, as a result of a trading operation, the volume of obligations becomes equal to zero. Such an operation is called closing a position.

    Active orders and positions are always displayed in the "Trade" tab, while deals and orders from the history are always reflected in the "History" tab.

    Trading operations

    Now let's deal with the types of trading operations. There are five of them in total:

      If you look carefully at this list, you will not find an item responsible for closing positions. The fact is that in MT5, closing a position is done by opening an order in the opposite direction. If this order is of the same volume, then the position will be closed completely; if it is smaller, then partially; if it is larger, the position will be reversed to the opposite one with the remaining volume.

      The onDeinit function

      Before we begin analyzing the code that opens positions, let's do a little work on the onDeinit function.

      The expert deinitialization reason codes returned by the UninitializeReason() function can have values from 0 to 9. Let's write a function that returns a string description of the deinitialization reason code:

      //+------------------------------------------------------------------+
      //| Funktsiya vozvrashchaet prichinu deinitsializatsii sovetnika             |
      //+------------------------------------------------------------------+
      string getUninitReasonText(int reasonCode)
      {
         string text="";
         
         switch(reasonCode)
         {
            case REASON_PROGRAM: // 0
            {
               text="Ekspert "+__FILE__+" prekratil svoyu rabotu, vyzvav funktsiyu ExpertRemove()";
               break;
            }
            case REASON_REMOVE: // 1
            {
               text="Ekspert "+__FILE__+" udalen s grafika";
               break;
            }
            case REASON_RECOMPILE: // 2
            {
               text="Ekspert "+__FILE__+" perekompilirovan";
               break;
            }
            case REASON_CHARTCHANGE: // 3
            {
               text="Simvol ili period grafika byl izmenen";
               break;
            }
            case REASON_CHARTCLOSE: // 4
            {
               text="Grafik zakryt";
               break;
            }
            case REASON_PARAMETERS: // 5
            {
               text="Vkhodnye parametry byli izmeneny polzovatelem";
               break;
            }
            case REASON_ACCOUNT: // 6
            {
               text="Aktivirovan drugoy schet libo proizoshlo perepodklyuchenie k torgovomu serveru vsledstvie izmeneniya nastroek scheta";
               break;
            }
            case REASON_TEMPLATE: // 7
            {
               text="Primenen drugoy shablon grafika";
               break;
            }
            case REASON_INITFAILED: // 8
            {
               text="Obrabotchik OnInit() vernul nenulevoe znachenie";
               break;
            }
            default:
            {
               text="Neizvestnaya prichina deinitsializatsii";
            }
         }
         
         return text;
      }

      We will also add code to the onDeinit() handler:

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
      {
         Print(__FUNCTION__, " - Kod prichiny deinitsializatsii:", reason);
         Print(__FUNCTION__, " - Prichina deinitsializatsii:", getUninitReasonText(reason));
      }

      Trade request

      We have already covered what structures are in lesson 8 devoted to date and time.

      The MqlTradeRequest and MqlTradeResult structures serve as parameters for the OrderSend function, which sends trade instructions to the server. Let's examine these structures in more detail.

      Let's create a trade request to sell at market:

      MqlTradeRequest trade_request = {0}; // Initsializatsiya struktury torgovogo zaprosa
      trade_request.action = TRADE_ACTION_DEAL; // Tip – po rynku
         // TRADE_ACTION_PENDING Otlozhennyy order
         // TRADE_ACTION_SLTP Modifikatsiya TP SL
         // TRADE_ACTION_MODIFY Modifikatsiya otlozhennogo ordera
         // TRADE_ACTION_REMOVE Udalenie otlozhennogo ordera
         // TRADE_ACTION_CLOSE_BY Zakryt pozitsiyu vstrechnoy
      trade_request.symbol = _Symbol; // Tekushchiy instrument
      trade_request.volume = 0.1; // Obem 0.1 lota
      trade_request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Tsena bid
      trade_request.type = ORDER_TYPE_SELL; // Tip ordera na prodazhu
      trade_request.type_filling = ORDER_FILLING_FOK; // Politika ispolneniya (nemedlenno ili otmena)

      Here we see the _Symbol variable. This is one of the reserved mql5 variables, among which there are the following:

      // _AppliedTo Pozvolyaet uznat v indikatore tip dannykh, na kotorykh on rascchityvaetsya
         // _Digits Kolichestvo desyatichnykh znakov posle zapyatoy
         // _Point Razmer punkta tekushchego instrumenta v valyute kotirovki
         // _LastError Znachenie posledney oshibki
         // _Period Znachenie taymfreyma tekushchego grafika
         // _RandomSeed Tekushchee sostoyanie generatora psevdosluchaynykh tselykh chisel
         // _StopFlag Flag ostanovki programmy
         // _Symbol Imya simvola tekushchego grafika
         // _UninitReason Kod prichiny deinitsializatsii programmy
         // _IsX64 Peremennaya _IsX64 pozvolyaet uznat, v kakom terminale zapushchena MQL5-programma

      The general form of the MqlTradeRequest structure:

      struct MqlTradeRequest
         {
            ENUM_TRADE_REQUEST_ACTIONS action; // Tip vypolnyaemogo deystviya
            ulong magic; // Shtamp eksperta (identifikator magic number)
            ulong order; // Tiket ordera
            string symbol; // Imya torgovogo instrumenta
            double volume; // Zaprashivaemyy obem sdelki v lotakh
            double price; // Tsena
            double stoplimit; // Uroven StopLimit ordera
            double sl; // Uroven Stop Loss ordera
            double tp; // Uroven Take Profit ordera
            ulong deviation; // Maksimalno priemlemoe otklonenie ot zaprashivaemoy tseny
            ENUM_ORDER_TYPE type; // Tip ordera
            ENUM_ORDER_TYPE_FILLING type_filling; // Tip ordera po ispolneniyu
            ENUM_ORDER_TYPE_TIME type_time; // Tip ordera po vremeni deystviya
            datetime expiration; // Srok istecheniya ordera (dlya orderov tipa ORDER_TIME_SPECIFIED)
            string comment; // Kommentariy k orderu
            1ulong position; // Tiket pozitsii
            ulong position_by; // Tiket vstrechnoy pozitsii
         };

      This MqlTradeRequest structure and the MqlTradeResult structure are parameters of the OrderSend() function:

      bool  OrderSend(
         MqlTradeRequest&  request,      // struktura zaprosa
         MqlTradeResult&   result        // struktura otveta
         );

      As you can see, it returns the bool type. In case of success, true will be returned, but this does not mean successful execution of the request, only that the request reached the server and a response was received. Whether the request was executed successfully can be judged precisely by the MqlTradeResult structure.

      In response to a trade request to place an order in the trading system, the trading server returns data containing information about the result of processing the trade request in the form of a special predefined MqlTradeResult structure. The result of the trade operation is returned in a variable of type MqlTradeResult, which is passed as the second parameter to the OrderSend() function for performing trading operations:

      struct MqlTradeResult
         {
            uint retcode; // Kod rezultata operatsii
            ulong deal; // Tiket sdelki, esli ona sovershena
            ulong order; // Tiket ordera, esli on vystavlen
            double volume; // Obem sdelki, podtverzhdyonnyy brokerom
            double price; // Tsena v sdelke, podtverzhdyonnaya brokerom
            double bid; // Tekushchaya rynochnaya tsena predlozheniya (tseny rekvota)
            double ask; // Tekushchaya rynochnaya tsena sprosa (tseny rekvota)
            string comment; // Kommentariy brokera k operatsii (po umolchaniyu zapolnyaetsya rasshifrovkoy koda vozvrata torgovogo servera)
            uint request_id; // Identifikator zaprosa, ustanavlivaetsya terminalom pri otpravke
            uint retcode_external; // Kod otveta vneshney torgovoy sistemy
         };

      When a market buy order is sent, it is processed, a corresponding buy order is created for the account, the order is executed, removed from the list of open orders, added to the order history, then a corresponding deal is added to the history and a new position is created. All these actions are trade transactions.

      To receive trade transactions applied to the account, MQL5 provides a special handler, OnTradeTransaction(). The first parameter of this handler receives the MqlTradeTransaction structure describing trade transactions:

      struct MqlTradeTransaction
      {
          ulong deal; // Tiket sdelki
          ulong order; // Tiket ordera
          string symbol; // Imya torgovogo instrumenta, po kotoromu sovershena tranzaktsiya
          ENUM_TRADE_TRANSACTION_TYPE type; // Tip torgovoy tranzaktsii
          ENUM_ORDER_TYPE order_type; // Tip torgovogo ordera
          ENUM_ORDER_STATE order_state; // Sostoyanie torgovogo ordera
          ENUM_DEAL_TYPE deal_type; // Tip sdelki
          ENUM_ORDER_TYPE_TIME time_type; // Tip ordera po vremeni deystviya
          datetime time_expiration; // Srok istecheniya otlozhennogo ordera
          double price; // Tsena. V zavisimosti ot tipa torgovoy tranzaktsii mozhet byt tsenoy ordera, sdelki ili pozitsii.
          double price_trigger; // Tsena srabatyvaniya stop-limitnogo ordera
          double price_sl; // Uroven Stop Loss
          double price_tp; // Uroven Take Profit
          double volume; // Obem v lotakh. V zavisimosti ot tipa torgovoy tranzaktsii mozhet ukazyvat na tekushchiy obem ordera, obem sdelki ili obem pozitsii.
          ulong position; // Tiket pozitsii, na kotoruyu povliyala tranzaktsiya
          ulong position_by; // Tiket vstrechnoy pozitsii. Ispolzuetsya pri zakrytii pozitsii vstrechnoy – otkrytoy po tomu zhe instrumentu, no v protivopolozhnom napravlenii.
      };

      The determining parameter for analyzing an incoming transaction is its type, which is passed in the type field. For example, if the transaction is of the TRADE_TRANSACTION_REQUEST type (the result of processing a trade request by the server has been received), then the structure has only one filled field, type, and the remaining fields do not need to be analyzed. In this case, you can analyze the two additional parameters, request and result, which are passed to the OnTradeTransaction() handler.

      Knowing the type of trade operation, you can decide whether to analyze the current state of orders, positions, and deals on the trading account. One trade request sent from the terminal to the server can generate several trade transactions, and the order in which they arrive at the terminal is not guaranteed.

      Let us write functions that will output descriptions of the MqlTradeRequest, MqlTradeResult, and MqlTradeTransaction structures:

      //+------------------------------------------------------------------+
      //| Vozvrashchaet tekstovoe opisanie tranzaktsii                         |
      //+------------------------------------------------------------------+
      string TransactionDescription(const MqlTradeTransaction &trans)
      {
         string desc=EnumToString(trans.type)+"\r\n";
         desc+="Symbol: "+trans.symbol+"\r\n";
         desc+="Deal ticket: "+(string)trans.deal+"\r\n";
         desc+="Deal type: "+EnumToString(trans.deal_type)+"\r\n";
         desc+="Order ticket: "+(string)trans.order+"\r\n";
         desc+="Order type: "+EnumToString(trans.order_type)+"\r\n";
         desc+="Order state: "+EnumToString(trans.order_state)+"\r\n";
         desc+="Order time type: "+EnumToString(trans.time_type)+"\r\n";
         desc+="Order expiration: "+TimeToString(trans.time_expiration)+"\r\n";
         desc+="Price: "+StringFormat("%G",trans.price)+"\r\n";
         desc+="Price trigger: "+StringFormat("%G",trans.price_trigger)+"\r\n";
         desc+="Stop Loss: "+StringFormat("%G",trans.price_sl)+"\r\n";
         desc+="Take Profit: "+StringFormat("%G",trans.price_tp)+"\r\n";
         desc+="Volume: "+StringFormat("%G",trans.volume)+"\r\n";
         desc+="Position: "+(string)trans.position+"\r\n";
         desc+="Position by: "+(string)trans.position_by+"\r\n";
         //--- vernem poluchennuyu stroku
         return desc;
      }
      
      //+------------------------------------------------------------------+
      //| Vozvrashchaet tekstovoe opisanie torgovogo zaprosa                  |
      //+------------------------------------------------------------------+
      string RequestDescription(const MqlTradeRequest &request)
      {
         string desc=EnumToString(request.action)+"\r\n";
         desc+="Symbol: "+request.symbol+"\r\n";
         desc+="Magic Number: "+StringFormat("%d",request.magic)+"\r\n";
         desc+="Order ticket: "+(string)request.order+"\r\n";
         desc+="Order type: "+EnumToString(request.type)+"\r\n";
         desc+="Order filling: "+EnumToString(request.type_filling)+"\r\n";
         desc+="Order time type: "+EnumToString(request.type_time)+"\r\n";
         desc+="Order expiration: "+TimeToString(request.expiration)+"\r\n";
         desc+="Price: "+StringFormat("%G",request.price)+"\r\n";
         desc+="Deviation points: "+StringFormat("%G",request.deviation)+"\r\n";
         desc+="Stop Loss: "+StringFormat("%G",request.sl)+"\r\n";
         desc+="Take Profit: "+StringFormat("%G",request.tp)+"\r\n";
         desc+="Stop Limit: "+StringFormat("%G",request.stoplimit)+"\r\n";
         desc+="Volume: "+StringFormat("%G",request.volume)+"\r\n";
         desc+="Comment: "+request.comment+"\r\n";
         //--- vernem poluchennuyu stroku
         return desc;
      }
      
      //+------------------------------------------------------------------+
      //| Vozvrashchaet tekstovoe opisanie rezultata obrabotki zaprosa       |
      //+------------------------------------------------------------------+
      string TradeResultDescription(const MqlTradeResult &result)
      {
         string desc="Retcode "+(string)result.retcode+"\r\n";
         desc+="Request ID: "+StringFormat("%d",result.request_id)+"\r\n";
         desc+="Order ticket: "+(string)result.order+"\r\n";
         desc+="Deal ticket: "+(string)result.deal+"\r\n";
         desc+="Volume: "+StringFormat("%G",result.volume)+"\r\n";
         desc+="Price: "+StringFormat("%G",result.price)+"\r\n";
         desc+="Ask: "+StringFormat("%G",result.ask)+"\r\n";
         desc+="Bid: "+StringFormat("%G",result.bid)+"\r\n";
         desc+="Comment: "+result.comment+"\r\n";
         //--- vernem poluchennuyu stroku
         return desc;
      }

      Now we can refine the OnTradeTransaction() handler:

      //+------------------------------------------------------------------+
      //| TradeTransaction function                                        |
      //+------------------------------------------------------------------+
      void OnTradeTransaction(const MqlTradeTransaction& trans,
                              const MqlTradeRequest& request,
                              const MqlTradeResult& result)
      {
         //--- poluchim tip tranzaktsii v vide znacheniya perechisleniya
         ENUM_TRADE_TRANSACTION_TYPE type = (ENUM_TRADE_TRANSACTION_TYPE)trans.type;
         //--- esli tranzaktsiya yavlyaetsya rezultatom obrabotki zaprosa, vyvedem tolko eyo nazvanie
         if (type == TRADE_TRANSACTION_REQUEST) {
            Print(EnumToString(type));
            //--- vyvedem strokovoe opisanie obrabotannogo zaprosa
            Print("------------RequestDescription\r\n",RequestDescription(request));
            //--- vyvedem opisanie rezultata zaprosa
            Print("------------ResultDescription\r\n",TradeResultDescription(result));
            //--- zapomnim tiket ordera dlya ego udaleniya na sleduyushchey obrabotke v OnTick()
            if (result.order!=0) {
               //--- udalim etot order po ego tiketu pri sleduyushchem vyzove OnTick()
               order_ticket=result.order;
               Print(" Tiket otlozhennogo ordera ",order_ticket,"\r\n");
            }
         }
         else {   // dlya tranzaktsiy drugogo tipa vyvedem polnoe opisanie
            //--- vyvedem opisanie poluchennoy tranzaktsii v Zhurnal
            Print("------------TransactionDescription\r\n",TransactionDescription(trans));
         }
      }

      CTrade Class

      Let us connect the CTrade class:

      input int MagicNumber = 1234567;
      
      //--- podklyuchim torgovyy klass CTrade i obyavim peremennuyu etogo tipa
      #include <Trade\Trade.mqh>
      CTrade trade;
      
      //--- flagi dlya ustanovki i udaleniya otlozhennogo ordera
      bool pending_done=false;
      bool pending_deleted=false;
      //--- zdes budem khranit tiket otlozhennogo ordera
      ulong order_ticket;

      Let us apply it in the onInit handler:

      //+------------------------------------------------------------------+
      //| Expert initialization function                                                     |
      //+------------------------------------------------------------------+
      int OnInit()
      {
         //--- ustanovim MagicNumber, kotorym budut pomechatsya vse nashi ordera
         trade.SetExpertMagicNumber(MagicNumber);
         //--- torgovye zaprosy budem otpravlyat v asinkhronnom rezhime s pomoshchyu funktsii OrderSendAsync()
         trade.SetAsyncMode(true);
         //--- initsializiruem peremennuyu nulem
         order_ticket=0;
         return(INIT_SUCCEEDED);
      }

      And an example of using the class in the onTick handler:

      //+------------------------------------------------------------------+
      //| Expert tick function                                             |
      //+------------------------------------------------------------------+
      void OnTick()
      {
         //--- ustanovka otlozhennogo ordera
         if(!pending_done)
         {
            double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
            double buy_stop_price = NormalizeDouble(ask+1000*_Point,(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS));
            bool res=trade.BuyStop(0.1,buy_stop_price,_Symbol);
            
            //--- esli funktsiya BuyStop() otrabotala uspeshno
            if (res) {
               pending_done=true;
               //--- poluchim rezultat otpravki zaprosa iz ctrade
               MqlTradeResult trade_result;
               trade.Result(trade_result);
               //--- poluchim request_id dlya otpravlennogo zaprosa
               uint request_id=trade_result.request_id;
               Print("Otpravlen zapros na ustanovku otlozhennogo ordera. Identifikator zaprosa Request_ID=",request_id);
               //--- zapomnim tiket ordera (pri ispolzovanii asinkhronnogo rezhima otpravki v CTrade budet raven nulyu)
               order_ticket=trade_result.order;
               //--- vsyo sdelano, poetomu dosrochno vykhodim iz obrabotchika OnTick()
               return;
            }
         }
         //--- udalenie otlozhennogo ordera
         if (!pending_deleted) {
            //--- dopolnitelnaya proverka
            if (pending_done && (order_ticket!=0)) {
               //--- popytaemsya udalit otlozhennyy order
               bool res=trade.OrderDelete(order_ticket);
               Print("OrderDelete=",res);
               //--- pri uspeshnoy otpravke zaprosa na udalenie
               if (res) {
                  pending_deleted=true;
                  //--- poluchim rezultat vypolneniya zaprosa
                  MqlTradeResult trade_result;
                  trade.Result(trade_result);
                  //--- vytashchim iz rezultata identifikator zaprosa
                  uint request_id=trade_result.request_id;
                  //--- vyvedem v Zhurnal
                  Print("Otpravlen zapros na udalenie otlozhennogo ordera #",order_ticket,
                  ". Identifikator zaprosa Request_ID=",request_id,
                  "\r\n");
                  //--- zapishem iz rezultata zaprosa tiket ordera
                  order_ticket=trade_result.order;
               }
            }
         }
      }

      Trading Without Using Third-Party Libraries

      Now let us write a method that opens a market sell trade:

      //+------------------------------------------------------------------+
      //| Prodazha po rynku                                                 |
      //+------------------------------------------------------------------+
      void marketSell()
      {
         //--- sbrosim kod posledney oshibki v nol
         ResetLastError();
         MqlTradeRequest trade_request = {}; // Initsializatsiya struktury torgovogo zaprosa
         /*
         struct MqlTradeRequest
         {
            ENUM_TRADE_REQUEST_ACTIONS action; // Tip vypolnyaemogo deystviya
            ulong magic; // Shtamp eksperta (identifikator magic number)
            ulong order; // Tiket ordera
            string symbol; // Imya torgovogo instrumenta
            double volume; // Zaprashivaemyy obem sdelki v lotakh
            double price; // Tsena
            double stoplimit; // Uroven StopLimit ordera
            double sl; // Uroven Stop Loss ordera
            double tp; // Uroven Take Profit ordera
            ulong deviation; // Maksimalno priemlemoe otklonenie ot zaprashivaemoy tseny
            ENUM_ORDER_TYPE type; // Tip ordera
            ENUM_ORDER_TYPE_FILLING type_filling; // Tip ordera po ispolneniyu
            ENUM_ORDER_TYPE_TIME type_time; // Tip ordera po vremeni deystviya
            datetime expiration; // Srok istecheniya ordera (dlya orderov tipa ORDER_TIME_SPECIFIED)
            string comment; // Kommentariy k orderu
            1ulong position; // Tiket pozitsii
            ulong position_by; // Tiket vstrechnoy pozitsii
         };
         */
         trade_request.action = TRADE_ACTION_DEAL; // Tip – po rynku
         // TRADE_ACTION_PENDING Otlozhennyy order
         // TRADE_ACTION_SLTP Modifikatsiya TP SL
         // TRADE_ACTION_MODIFY Modifikatsiya otlozhennogo ordera
         // TRADE_ACTION_REMOVE Udalenie otlozhennogo ordera
         // TRADE_ACTION_CLOSE_BY Zakryt pozitsiyu vstrechnoy
         trade_request.symbol = _Symbol; // Tekushchiy instrument
         // _AppliedTo Pozvolyaet uznat v indikatore tip dannykh, na kotorykh on rascchityvaetsya
         // _Digits Kolichestvo desyatichnykh znakov posle zapyatoy
         // _Point Razmer punkta tekushchego instrumenta v valyute kotirovki
         // _LastError Znachenie posledney oshibki
         // _Period Znachenie taymfreyma tekushchego grafika
         // _RandomSeed Tekushchee sostoyanie generatora psevdosluchaynykh tselykh chisel
         // _StopFlag Flag ostanovki programmy
         // _Symbol Imya simvola tekushchego grafika
         // _UninitReason Kod prichiny deinitsializatsii programmy
         // _IsX64 Peremennaya _IsX64 pozvolyaet uznat, v kakom terminale zapushchena MQL5-programma
         trade_request.volume = 0.1; // Obem 0.1 lota
         trade_request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Tsena bid
         trade_request.type = ORDER_TYPE_SELL; // Tip ordera na prodazhu
         trade_request.type_filling = ORDER_FILLING_FOK; // Politika ispolneniya (nemedlenno ili otmena)
         
         MqlTradeResult trade_result = {}; // Initsializatsiya struktury rezultata
         /*
         struct MqlTradeResult
         {
            uint retcode; // Kod rezultata operatsii
            ulong deal; // Tiket sdelki, esli ona sovershena
            ulong order; // Tiket ordera, esli on vystavlen
            double volume; // Obem sdelki, podtverzhdyonnyy brokerom
            double price; // Tsena v sdelke, podtverzhdyonnaya brokerom
            double bid; // Tekushchaya rynochnaya tsena predlozheniya (tseny rekvota)
            double ask; // Tekushchaya rynochnaya tsena sprosa (tseny rekvota)
            string comment; // Kommentariy brokera k operatsii (po umolchaniyu zapolnyaetsya rasshifrovkoy koda vozvrata torgovogo servera)
            uint request_id; // Identifikator zaprosa, ustanavlivaetsya terminalom pri otpravke
            uint retcode_external; // Kod otveta vneshney torgovoy sistemy
         };
         */
         MqlTradeCheckResult check_result = {}; // Initsializatsiya struktury proverki zaprosa
         bool res_check = OrderCheck(trade_request, check_result);
         if (!res_check) {
         
            Print(__FUNCTION__, " - rezultat proverki otritsatelnyy, kod otveta:", check_result.retcode);
            Print(__FUNCTION__, " - rasshifrovka koda otveta:", checkResultRetcodeText(check_result.retcode));
            // Analiziruem check_result
            /*
               struct MqlTradeCheckResult
               {
                  uint retcode; // Kod otveta
                  double balance; // Balans posle soversheniya sdelki
                  double equity; // Ekviti posle soversheniya sdelki
                  double profit; // Plavayushchaya pribyl
                  double margin; // Marzhevye trebovaniya
                  double margin_free; // Svobodnaya marzha
                  double margin_level; // Uroven marzhi
                  string comment; // Kommentariy k kodu otveta (opisanie oshibki)
               };
            */
         }
         bool res_send = OrderSendAsync(trade_request, trade_result); // Otpravka torgovogo zaprosa
         if (!res_send) {
            uint answer = trade_result.retcode;
            Print(__FUNCTION__, " - rezultat otpravki otritsatelnyy, kod otveta:", answer);
            Print(__FUNCTION__, " - rasshifrovka koda otveta:", sendResultRetcodeText(answer));
         }
      }
      
      string checkResultRetcodeText(int retcode)
      {
         switch (retcode) {
            case TRADE_RETCODE_REQUOTE: // 10004
            {
               return "Rekvota";
            }
            default:
            {
               return "Drugaya prichina";
            }
         }
      }
      
      string sendResultRetcodeText(int retcode)
      {
         switch (retcode) {
            case TRADE_RETCODE_REQUOTE: // 10004
            {
               return "Rekvota";
            }
            default:
            {
               return "Drugaya prichina";
            }
         }
      }

      The checkResultRetcodeText and sendResultRetcodeText methods, which return textual descriptions of the return code of the OrderSend and OrderCheck functions, are not fully completed; they remain as homework.

      We also have a new MqlTradeCheckResult structure:

      struct MqlTradeCheckResult
               {
                  uint retcode; // Kod otveta
                  double balance; // Balans posle soversheniya sdelki
                  double equity; // Ekviti posle soversheniya sdelki
                  double profit; // Plavayushchaya pribyl
                  double margin; // Marzhevye trebovaniya
                  double margin_free; // Svobodnaya marzha
                  double margin_level; // Uroven marzhi
                  string comment; // Kommentariy k kodu otveta (opisanie oshibki)
               };
      Rekomenduetsya samostoyatelno proverit zapros pered otpravkoy ego torgovomu serveru. Dlya proverki zaprosa sushchestvuet funktsiya OrderCheck():
      bool OrderCheck(
          MqlTradeRequest& request, // Ukazatel na strukturu tipa MqlTradeRequest, kotoraya opisyvaet trebuemoe torgovoe deystvie
          MqlTradeCheckResult& result // Ukazatel na strukturu tipa MqlTradeCheckResult, v kotoruyu budet pomeshchen rezultat proverki
      );

      The function will not only check whether there are sufficient funds to perform a trade operation, but will also return many other useful parameters in the trade request check results:

        In case of insufficient funds or incorrectly filled parameters, the function returns false. In case of a successful basic check of the structures (pointer check), true is returned - this is not evidence that the requested trade operation will necessarily be executed successfully. To obtain a detailed description of the result of the function execution, you should analyze the fields of the result structure. To get information about the error, you need to call the GetLastError() function.

        By analogy, let us write a function that places a pending buy limit order, and a function that modifies the parameters of a pending order:

        //+------------------------------------------------------------------+
        //| Otlozhennaya pokupka buy limit                                     |
        //+------------------------------------------------------------------+
        void buyLimit()
        {
           MqlTradeRequest trade_request = {}; // Initsializatsiya struktury torgovogo zaprosa
           trade_request.action = TRADE_ACTION_PENDING; // Tip – otlozhennyy
           trade_request.symbol = _Symbol; // Tekushchiy instrument
           trade_request.volume = 0.1; // Obem 0.1 lota
           trade_request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Tsena ask
           trade_request.sl = trade_request.price - 500 * _Point;
           trade_request.tp = trade_request.price + 500 * _Point;
           trade_request.type = ORDER_TYPE_BUY_LIMIT; // Tip ordera na pokupku
           trade_request.type_filling = ORDER_FILLING_FOK; // Politika ispolneniya
           trade_request.expiration = ORDER_TIME_GTC; // Srok deystviya ordera (do otmeny)
           // ORDER_TIME_GTC - Order budet nakhoditsya v ocheredi do tekh por, poka ne budet snyat
           // ORDER_TIME_DAY - Order budet deystvovat tolko v techenie tekushchego torgovogo dnya
           // ORDER_TIME_SPECIFIED - Order budet deystvovat do daty istecheniya
           // ORDER_TIME_SPECIFIED_DAY - Order budet deystvovat do 23:59:59 ukazannogo dnya. Esli eto vremya ne popadaet na torgovuyu sessiyu, istechenie nastupit v blizhayshee torgovoe vremya.
           
           MqlTradeResult trade_result = {0}; // Initsializatsiya struktury rezultata
           bool res_send = OrderSend(trade_request, trade_result); // Otpravka torgovogo zaprosa
        
        }
        //+------------------------------------------------------------------+
        //| Modifikatsiya otlozhennogo ordera na pokupku buy limit              |
        //+------------------------------------------------------------------+
        void buyLimitModify()
        {
           // 1. Sozdaem zapros
           MqlTradeRequest trade_request = {}; // Initsializatsiya struktury torgovogo zaprosa
           trade_request.action = TRADE_ACTION_MODIFY; // Tip – izmenenie parametrov
           trade_request.order = 123456; 
           trade_request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - 250 * _Point; // Tsena
           trade_request.sl = trade_request.price - 600 * _Point;
           trade_request.tp = trade_request.price + 800 * _Point;
           trade_request.type = ORDER_TYPE_BUY_LIMIT; // Tip ordera na pokupku
           trade_request.expiration = ORDER_TIME_GTC; // Srok deystviya ordera (do otmeny)
           
           // 2. Otpravit torgovyy prikaz
           MqlTradeResult trade_result = {}; // Initsializatsiya struktury rezultata
           bool res_send = OrderSend(trade_request, trade_result); // Otpravka torgovogo zaprosa
           
        }

        Conclusion

        Today we learned how to send trade orders to the server, receive and process responses, modified the OnDeinit and OnTradeTransaction handlers, and also wrote several useful functions that simplify the further operation of the expert advisor.

        As homework, I suggest writing functions analogous to those covered in the lesson for market buys, as well as for a pending sell limit order and pending stop orders. In the buyLimit and buyLimitModify functions, it is worth including a check using the OrderCheck function, as we did in the marketSell function. In addition, in the lesson we did not finish writing the checkResultRetcodeText and sendResultRetcodeText functions.

        That is all, goodbye everyone!

        Best regards, Dmitry aka Silentspec
        Tlap.io

        Trading operations in the MQL5 programming language. Video lesson on orders, deals, positions, and trading operations. Creating a new expert advisor.