Help (Beginner question) : Invalid request

 

Hello everybody, 

I'm a beginner in MQL5 and programmation in general. I started developing my EA last month following examples online and in the documentation and I have been able to implement custom indicators, buy and sells following conditions but I am now facing a problem that I don't know how to solve. Let me explain :

I would like my EA to close open trades (buys and sells) when the signal line of one of my indicators crosses with another line (no problem here I think). I found the code to do just that in the documentation, so I don't think the problem comes from the instructions. The problem is that there is a request that can't get executed properly, and I don't know why. I suspect an error in the memory.

Note that this problem only occurs when trying to close trades and not when opening them.

Here is the message that is shown in the terminal, for example when trying to close the trade #48 : 

"failed market buy 0.67 EURUSD, close #48 buy 0.67 EURUSD 1.18298 [Invalid request]

OrderSend error 4756

retcode=10013  deal=0  order=0"

I of course searched for this problem on the forum but I couldn't find an answer (there is maybe one but I didn't find it...) and read the doc to see if I couldn't fix it myself, so I decided to ask to the community.

Thank you very much in advance, 

Here is the code of my EA : 

//+----------------------------------------------------------

#define Expert_Magic 111111 // Magic Number of EURUSD Expert

//--- input parameters
input double      StopLossATRPercentage=1.5;      // Stop Loss
input double     TakeProfitATRPercentage=1.0;   // Take Profit
input double   Risk ;          // risk
input bool B1 = true; // Indicator 1
input bool B2 = true; // Ind 2
input bool B3 = true; // Ind 3

//--- Other parameters
int ATR_Handle; // handle for our ATR indicator
int Rex_Handle;


double ATR_val[]; // Dynamic array to hold the values of ATR for each bars
double Rex_signal[]; // Dynamic arrays to hold the values of Rex for each bars
double Rex_rex[];
double p_close; // Variable to store the close value of a bar
double p_open;
double LotToTrade;


double SL, TP;   // To be used for Stop Loss & Take Profit values
double SLprice, TPprice;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ATR_Handle = iATR(NULL,PERIOD_CURRENT, 14);
   Rex_Handle = iCustom(NULL,PERIOD_CURRENT,"Rex");
   // and others for indicators

//--- Let us handle currency pairs with 5 or 3 digit prices instead of 4
   SL = StopLossATRPercentage ;
   TP = TakeProfitATRPercentage ;
   if(_Digits==5 || _Digits==3)
     {
      SL = SL*10;
      TP = TP*10;
     }
   return(0);
  }
  
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+

void OnDeinit(const int reason)
  {
//--- Release our indicator handles
   IndicatorRelease(ATR_Handle);
   IndicatorRelease(Rex_Handle);
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  
  MqlTradeRequest request;
  MqlTradeResult  result;
   
//--- Do we have enough bars to work with
   if(Bars(_Symbol,_Period)<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }  

// We will use the static Old_Time variable to serve the bar time.
// At each OnTick execution we will check the current bar time with the saved one.
// If the bar time isn't equal to the saved time, it indicates that we have a new tick.

   static datetime Old_Time;
   datetime New_Time[1];
   bool IsNewBar=false;

// copying the last bar time to the element New_Time[0]
   int copied=CopyTime(_Symbol,_Period,0,1,New_Time);
   if(copied>0) // ok, the data has been copied successfully
     {
      if(Old_Time!=New_Time[0]) // if old time isn't equal to new bar time
        {
         IsNewBar=true;   // if it isn't a first call, the new bar has appeared
         if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("We have new bar here ",New_Time[0]," old time was ",Old_Time);
         Old_Time=New_Time[0];            // saving bar time
        }
     }
   else
     {
      Alert("Error in copying historical times data, error =",GetLastError());
      ResetLastError();
      return;
     }

//--- EA should only check for new trade if we have a new bar
   if(IsNewBar==false)
     {
      return;
     }
 
//--- Do we have enough bars to work with
   int Mybars=Bars(_Symbol,_Period);
   if(Mybars<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }

//--- Define some MQL5 Structures we will use for our trade
   MqlTick latest_price;      // To be used for getting recent/latest price quotes
   //MqlTradeRequest request;  // To be used for sending our trade requests
   //MqlTradeResult result;    // To be used to get our trade results
   MqlRates rate[];          // To be used to store the prices, volumes and spread of each bar
   ZeroMemory(request);      // Initialization of request structure
/*
     Let's make sure our arrays values for the Rates, ATR Values and Rex values 
     is store serially similar to the timeseries array
*/
// the rates arrays
   ArraySetAsSeries(rate,true);
// the  ATR values array
   ArraySetAsSeries(ATR_val,true);
//the Rex values arrays 
   ArraySetAsSeries(Rex_rex,true);
   ArraySetAsSeries(Rex_signal,true);
// and others like this with indicators
  
   
   
//--- Get the last price quote using the MQL5 MqlTick Structure
   if(!SymbolInfoTick(_Symbol,latest_price))
     {
      Alert("Error getting the latest price quote - error:",GetLastError(),"!!");
      return;
     }

//--- Get the details of the latest 3 bars
   if(CopyRates(_Symbol,_Period,0,3,rate)<0)
     {
      Alert("Error copying rates/history data - error:",GetLastError(),"!!");
      ResetLastError();
      return;
     }

//--- Copy the new values of our indicators to buffers (arrays) using the handle
   if(CopyBuffer(ATR_Handle,0,0,3,ATR_val)<0)
     {
      Alert("Error copying ATR indicator Buffers - error:",GetLastError(),"!!");
      ResetLastError();
      return;
     }
   
   if(CopyBuffer(Rex_Handle,1,0,3,Rex_signal)>10 || CopyBuffer(Rex_Handle,0,0,3,Rex_rex)>10 ) 
     {
      Alert("Error copying REX indicator Buffers - error:",GetLastError(),"!!");
      ResetLastError();
      return;
     }
    
//--- we have no errors, so continue
//--- Do we have positions opened already?
   bool Buy_opened=false;  // variable to hold the result of Buy opened position
   bool Sell_opened=false; // variables to hold the result of Sell opened position

   if(PositionSelect(Symbol())==true) // we have an opened position
     {
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
         Buy_opened=true;  //It is a Buy
        }
      else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
         Sell_opened=true; // It is a Sell
        }
     }

// Copy the bar close price for the previous bar prior to the current bar, that is Bar 1
   p_close=rate[1].close;  // bar 1 close price
   p_open=rate[1].open;
   
/*
    1. Check for a long/Buy Setup : 
*/
//--- Declare bool type variables to hold our Buy Conditions

bool Buy_Condition_1 = true; // Condition 1 to buy
bool Buy_Condition_2 = true; // Condition 2 to buy
bool Buy_Condition_3 = true; // Condition 3 to buy
   
//--- Putting all together   
   
    if( Buy_Condition_1 && Buy_Condition_2 && Buy_Condition_3)
        {
         // any opened Buy position?
         if(Buy_opened || Sell_opened)
           {
           // Alert("We already have a Buy Position!!!");
            return;    // Don't open a new Buy Position
           }
         SLprice = NormalizeDouble(latest_price.ask - (ATR_val[0]*MathPow(10,_Digits )*StopLossATRPercentage)*_Point,_Digits); // Stop Loss
         TPprice =  NormalizeDouble(latest_price.ask + (ATR_val[0]*MathPow(10,_Digits )*TakeProfitATRPercentage)*_Point,_Digits); // Take Profit  
         if(_Digits==5) {
            LotToTrade = NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Risk*0.01/
                            (NormalizeDouble(latest_price.ask,_Digits)* SYMBOL_TRADE_TICK_VALUE),2); 
                        }
          if(_Digits==3) {
            LotToTrade = NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Risk/
                            (NormalizeDouble(latest_price.ask,_Digits)* SYMBOL_TRADE_TICK_VALUE),2); 
          }
         
         ZeroMemory(request);
         request.action = TRADE_ACTION_DEAL;                                  // immediate order execution
         request.price = NormalizeDouble(latest_price.ask,_Digits);           // latest ask price
         request.sl = SLprice;
         request.tp = TPprice;
         request.symbol = Symbol();                                            // currency pair
         request.volume =  LotToTrade;                                           // Order Magic Number
         request.type = ORDER_TYPE_BUY;                                        // Buy Order
         request.type_filling = ORDER_FILLING_FOK;                             // Order execution type
         request.deviation=5;  // Deviation from current price
         request.magic = Expert_Magic;
                                   
         //--- send order
         OrderSend(request,result);
         Buy_opened = true;
         // get the result code
         
        
         
         if(result.retcode==10009 || result.retcode==10008) //Request is completed or order placed
           {
            //Alert("A Buy order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
         else
           {
            Alert("The Buy order request could not be completed -error:",GetLastError());
            ResetLastError();           
            return;
           }
        
     }
/*
    2. Check for a Short/Sell Setup : AO decreasing, Damiani ok, Coppock > 0 
*/
//--- Declare bool type variables to hold our Sell Conditions

bool Sell_Condition_1 = true; // Condition 1 to sell
bool Sell_Condition_2 = true; // Condition 2 to sell
bool Sell_Condition_3 = true; // Condition 3 to sell
               
//--- Putting all together
  
    if(Sell_Condition_1 && Sell_Condition_2 && Sell_Condition_3)
        {
         // any opened Sell position?
         if(Sell_opened || Buy_opened)
           {
           Alert("We already have a Sell position!!!");
            return;    // Don't open a new Sell Position
           }
         
         //Alert ("Free Margin = ",  AccountInfoDouble(ACCOUNT_MARGIN_FREE));
        if(_Digits==5) {
            LotToTrade = NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Risk*0.01/
                            (NormalizeDouble(latest_price.ask,_Digits)* SYMBOL_TRADE_TICK_VALUE),2); 
                        }
          if(_Digits==3) {
            LotToTrade = NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Risk/
                            (NormalizeDouble(latest_price.ask,_Digits)* SYMBOL_TRADE_TICK_VALUE),2); 
          } 
         ZeroMemory(request);
         request.action=TRADE_ACTION_DEAL; 
                                   // immediate order execution
         request.price = NormalizeDouble(latest_price.bid,_Digits);           // latest Bid price
         request.sl = NormalizeDouble(latest_price.bid + (ATR_val[0]*MathPow(10,_Digits )*StopLossATRPercentage)*_Point,_Digits); // Stop Loss
         request.tp = NormalizeDouble(latest_price.bid - (ATR_val[0]*MathPow(10,_Digits )*TakeProfitATRPercentage)*_Point,_Digits); // Take Profit
         request.symbol = Symbol();                                          // currency pair
         request.volume = LotToTrade;                                        // number of lots to trade
         request.type= ORDER_TYPE_SELL;                                     // Sell Order
         request.type_filling = ORDER_FILLING_FOK;                          // Order execution type
         request.deviation=5;   // Deviation from current price
         request.magic = Expert_Magic;
                                                 
         //--- send order
         OrderSend(request,result);
         Sell_opened = true;
         // get the result code
         if(result.retcode==10009 || result.retcode==10008) //Request is completed or order placed
           {
            //Alert("A Sell order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
           
           
         else
           {
            Alert("The Sell order request could not be completed -error:",GetLastError());
            ResetLastError();
            return;
           }
        
     }
     
//******************   
// Code to close a trade according to exit conditions
//******************

// Checker valeurs retournées  
   bool Exit_Buy_Condition_1 = (Rex_rex[0] > Rex_signal[0]);
   bool Exit_Short_Condition_1 = (Rex_rex[0] < Rex_signal[0]);
   int total = PositionsTotal(); // number of open positions   
   
   //--- iterate over all open positions
   for(int i=total-1; i>=0; i--)
     {
      //--- parameters of the order
      ulong  position_ticket=PositionGetTicket(i);                                      // ticket of the position
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // symbol 
      int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);              // number of decimal places
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber of the position
      double volume=PositionGetDouble(POSITION_VOLUME);                                 // volume of the position
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);    // type of the position
      //--- output information about the position
      PrintFormat("#%I64u %s  %s  %.2f  %s [%I64d]",
                  position_ticket,
                  position_symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  magic);
      //--- if the MagicNumber matches
      if(magic==Expert_Magic)
        {
         //--- zeroing the request and result values
         ZeroMemory(request);
         ZeroMemory(result);
         //--- setting the operation parameters
         request.action   =TRADE_ACTION_DEAL;        // type of trade operation
         request.position =position_ticket;          // ticket of the position
         request.symbol   =position_symbol;          // symbol 
         request.volume   =volume;                   // volume of the position
         request.deviation=5;                        // allowed deviation from the price
         request.magic    =Expert_Magic;             // MagicNumber of the position
         //--- set the price and order type depending on the position type
         if(type==POSITION_TYPE_BUY && Exit_Buy_Condition_1)
           {
            request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID);
            request.type =ORDER_TYPE_SELL;
           }
         else if (type == POSITION_TYPE_SELL && Exit_Short_Condition_1)
           {
            request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK);
            request.type =ORDER_TYPE_BUY;
           }
         //--- output information about the closure
         PrintFormat("Close #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
         //--- send the request
         if(!OrderSend(request,result))
            PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
         //--- information about the operation   
         PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
         //---
        }
     }
return;
 }

  
 

I added the following to capture any current market positions:

        ulong buyTicket = 0, sellTicket = 0;
        for(int i = 0; i < PositionsTotal(); i++)
        {
           ulong ticket = PositionGetTicket(i);
           PositionSelectByTicket(ticket);
           
           if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
              buyTicket = ticket;
              Buy_opened = true;
           }
           else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
           {
              sellTicket = ticket;
              Sell_opened = true;
           }
        }

I added this to make sure the sell is closed before opening the buy.

   if(Buy_Condition_1 && Buy_Condition_2 && Buy_Condition_3 && Buy_opened==false)
     {
      // Close sell order
      if(sellTicket > 0)
        {
         PositionSelectByTicket(sellTicket);
         request.action = TRADE_ACTION_DEAL;
         request.type = ORDER_TYPE_BUY;
         request.symbol = _Symbol;
         request.position = sellTicket;
         request.volume = PositionGetDouble(POSITION_VOLUME);
         request.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         request.deviation = 5;
         bool sent = OrderSend(request, result);
         Sell_opened = false;
        }

I split the opening order and SL_TP modifcation into two stages. 1st stage

      request.action = TRADE_ACTION_DEAL;                                 
      request.price = NormalizeDouble(latest_price.ask,_Digits);           
      request.sl = 0;
      request.tp = 0;
      request.position = 0; //Clear out redundant ticket
      request.symbol = Symbol();                                           
      request.volume =  LotToTrade;                                           
      request.type = ORDER_TYPE_BUY;                                        
      request.type_filling = ORDER_FILLING_FOK;                          
      request.deviation=5;  // Deviation from current price
      request.magic = Expert_Magic;

      //--- send order
      bool sent = OrderSend(request,result);

2nd stage stage

      // Modify SL/TP
      if(result.retcode == TRADE_RETCODE_PLACED || result.retcode == TRADE_RETCODE_DONE)
        {
         request.action = TRADE_ACTION_SLTP;
         request.position = result.order;

         PositionSelectByTicket(result.order);
         double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);

         if(SLprice > 0)
            request.sl = SLprice;
         if(TPprice > 0)
            request.tp = TPprice;

         if(request.sl > 0 && request.tp > 0)
            sent = OrderSend(request,result);
        }
      else
        {
         Alert("The Buy order request could not be completed -error:",GetLastError());
         ResetLastError();
         return;
        }
 
Max Brown #:

I added the following to capture any current market positions:

I added this to make sure the sell is closed before opening the buy.

I split the opening order and SL_TP modifcation into two stages. 1st stage

2nd stage stage

Thank you for your response ! May I ask you why it is better to split opening orders into two stages ?

 
BaptisteFx #:

Thank you for your response ! May I ask you why it is better to split opening orders into two stages ?


For me it makes the process easier, old habits.  However, it is not necessary because brokers no longer require a two stage order submission.

 
Max Brown #:


For me it makes the process easier, old habits.  However, it is not necessary because brokers no longer require a two stage order submission.

Noted, I will continue to do this from now on because it allows to check the SL and TP prices easily, and it is an useful check ! Thanks again sir.
Reason: