[SOLVED] Again the dreaded "No trading operations" error - something wrong with the auto-validation?

 

EDIT #1: I've set the max spread allowed to 0.0 in the input settings following the recommendation of @Fernando Carreiro (thanks!). I've also added a function to close the trades I'm opening on every tick (I wasn't closing them before). Finally there was an issue in the "RunChecksBeforeOrderSend" block. I was always returning "GetLastError()" in some instances where there's no call to any internal function, and therefore I might be returning a previous "OK" when the logical operation was false - now I'm returning the raw error code. Still getting the validation error below. I'm very stuck with this.

EDIT #2: Problem solved - check comment #4.

EDIT #3: I can confirm that the error received by the validator is outdated, wrong and misleading. It won't probably be fixed, but from what I've gathered from other people and from this experience myself it's clear that the error has to do with the validity of the lot size and/or free margin available and not whether the EA can open trades in the currencies/timeframes in the message.

 


Hello,

Another thread on this. I think I've read everything I could read about this issue, I've tried everything, and I'm still not able to get rid of the issue. There seems to be definitely something wrong with the auto-validation since a lot of people get the same error, which seems to have nothing to do with the issue at hand. Just as a reminder, tho I'm pretty sure by now you all know this error by heart...

test on EURUSD,H1
there are no trading operations
test on NZDUSD,H1
there are no trading operations
test on GBPUSDcheck,M30
there are no trading operations
test on XAUUSDcheck,Daily
there are no trading operations

First off, let me start by saying that my EA throws no error in the Strategy Tester nor in demo accounts nor in the two real accounts where it's actually running, at least with my current brokers. This said, I do understand that the auto-validation tries to test the EA on all possible challenging scenarios, and I've read all the checks that you're supposed to do. I believe I have, and I'm really hoping that someone proves me wrong so that I can correct the error.

From what I've been able to gather in the plethora of threads on this matter, it seems to be an issue related to not properly checking the free margin and/or the correctness of the lots. So, I started to strip off my EA of all bells and whistles, and I'm going bare-bones, sending a request to open a Buy and a Sell on every new bar. In the request:

  1. I normalize both the volume and the prices, or so I think.
  2. Before calling OrderSend I'm doing all sorts of checks (free margin, account order limits, correctness of volume, spread, and EA max orders allowed).

I think I'm catching everything with the above, but I still get the same error, and I don't know what else to do. For the sake of clarity, I'm posting my bare-bones code here, just in case any of you guys is kind enough to take a look and tell me what I'm doing wrong. The main operations are done in the "RequestOrderSend" function, and note how before calling OrderSend I normalize the volume and price, and then proceed to run some checks in the "RunChecksBeforeOrderSend" function. Then and only then I call OrderSend.

Many thanks in advance for any hints!

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2018, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict
#property version "1.0"

//+------------------------------------------------------------------+
// Include libraries
//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>

//+------------------------------------------------------------------+
// Constants
//+------------------------------------------------------------------+
const int TKT_ERR = -1;

//+------------------------------------------------------------------+
// Variables
//+------------------------------------------------------------------+
double pipPoint      = 0;
int    maxOrders     = 200;
int    maxOrdersBuy  = 200;
int    maxOrdersSell = 200;

//+------------------------------------------------------------------+
// INPUT PARAMETERS
//+------------------------------------------------------------------+
extern int    INP_magicNumber    = 20120222; // Magic number
extern double INP_initialLotSize = 0.01;     // Initial lot size
extern double INP_maxSpread      = 0.0;      // Maximum spread (pips)
extern double INP_maxSlippage    = 0.0;      // Maximum slippage (pips)

//+------------------------------------------------------------------+
// *** ONINIT *** Expert initialization function
//+------------------------------------------------------------------+
int OnInit() {
   pipPoint = Point();
   if(Digits() == 5 || Digits() == 3)
      pipPoint *= 10;

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
// *** ONTICK *** Expert tick function
//+------------------------------------------------------------------+
void OnTick() {
   bool isNewBar = IsNewBar();
   int tkt = -1;

   if(isNewBar) {
      // BUY Order
      RefreshRates();
      tkt = RequestOrderSend(OP_BUY, Ask, INP_initialLotSize, "");

      // SELL Order
      RefreshRates();
      tkt = RequestOrderSend(OP_SELL, Bid, INP_initialLotSize, "");

      Sleep(2000);
      RequestOrderClose(OP_BUY);
      RequestOrderClose(OP_SELL);
   }
}

//+------------------------------------------------------------------+
// Tally all open orders
//+------------------------------------------------------------------+
int TallyOrders(int type) {
   int count = 0;
   for(int i = 0, total = OrdersTotal(); i < total; i++)
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         if(OrderMagicNumber() == INP_magicNumber && OrderSymbol() == Symbol() && OrderType() == type)
            count++;

   return(count);
}

//+------------------------------------------------------------------+
// Sends a request to open a new position
//+------------------------------------------------------------------+
int RequestOrderSend(int pType, double pPrice, double pVolume, string pComment) {
   double normVolume   = 0;
   double normPrice    = 0;
   int    normSlippage = 0;
   int    rc           = 0;
   int    tkt          = 0;

   while(IsTradeContextBusy())
      Sleep(100);

   RefreshRates();

// Normalization
   normPrice    = NormalizeDouble(NormalizePrice(pType == OP_BUY ? Ask : Bid), Digits());
   normVolume   = NormalizeVolume(pVolume);
   normSlippage = int(INP_maxSlippage * 10);

// ORDERSEND CHECKS
   ResetLastError();
   rc = RunChecksBeforeOrderSend(Symbol(), pType, pVolume);

   if(rc == ERR_NO_ERROR) {
      // Try to open a new order
      tkt = OrderSend(Symbol(), pType, normVolume, normPrice, normSlippage, 0, 0, pComment, INP_magicNumber, 0, clrNONE);

      if(tkt < 0) {
         rc = GetLastError();
         Print("ERROR on OrderSend ", rc);
         return(TKT_ERR);
      }
   } else {
      Print("ERROR OUT ", rc);
      return(TKT_ERR);
   }

   return(tkt);
}

//+------------------------------------------------------------------+
// Normalizes the price for the trade
//+------------------------------------------------------------------+
double NormalizePrice(double pPrice) {
   double tickSize = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE);
   return(MathRound(pPrice / tickSize) * tickSize);
}

//+------------------------------------------------------------------+
// Normalizes the lot size for the trade
//+------------------------------------------------------------------+
double NormalizeVolume(double pVolume) {
   double volume  = 0;
   double volMin = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   double volMax = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
   double volStp = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);

   if(pVolume > 0) {
      volume = MathMax(volMin, pVolume);             // Prevents a too small volume
      volume = MathRound(pVolume / volStp) * volStp; // Aligns to Step value
      volume = MathMin(volMax, pVolume);             // Prevents a too large volume
   } else
      volume = volMin;

   return(volume);
}

//+------------------------------------------------------------------+
// Performs all needed checks before calling OrderSend
//+------------------------------------------------------------------+
int RunChecksBeforeOrderSend(string pSymbol, int pType, double pVolume) {
   // *** USER RETURN CODES ***
   // Maximum number of trades
   int totOrdersBuy  = TallyOrders(OP_BUY);
   int totOrdersSell = TallyOrders(OP_SELL);
   int totOrders     = totOrdersBuy + totOrdersSell;
   if(
      (pType == OP_BUY && totOrdersBuy >= maxOrdersBuy)
      || (pType == OP_SELL && totOrdersSell >= maxOrdersSell)
      || (totOrders >= maxOrders)
   ) {
      SetUserError(0);
      return(GetLastError());
   }

   // Maximum spread
   double spread = (Ask - Bid) / pipPoint;
   if(INP_maxSpread > 0 && spread > INP_maxSpread) {
      SetUserError(1);
      return(GetLastError());
   }

   // *** TRADE SERVER RETURN CODES ***
   // Free margin
   double freeMargin = AccountFreeMarginCheck(pSymbol, pType, pVolume);
   if(freeMargin <= 0)
      return(ERR_NOT_ENOUGH_MONEY); // RC#134

   // Volume correctness
   double volMin = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   double volMax = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
   double volStp = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
   int ratio     = int(MathRound(pVolume / volStp));
   if(
      pVolume < volMin                                   // Minimum lot size
      || pVolume > volMax                                // Maximum lot size
      || MathAbs((ratio * volStp) - pVolume) > 0.0000001 // Minimum lot step
   )
      return(ERR_INVALID_TRADE_VOLUME); // RC#131

   // Account order limit
   int accMaxOrders = int(AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
   if(totOrders >= accMaxOrders)
      return(ERR_TRADE_TOO_MANY_ORDERS); // RC#148

   // OTHERWISE return no error
   return(ERR_NO_ERROR);
}

//+------------------------------------------------------------------+
// Asks if there's a new bar on the chart
//+------------------------------------------------------------------+
bool IsNewBar() {
   static datetime lastTime = 0;
   bool ret = Time[0] > lastTime && lastTime > 0;
   lastTime = Time[0];

   return(ret);
}


//+------------------------------------------------------------------+
// Sends requests to close all open positions
//+------------------------------------------------------------------+
void RequestOrderClose(int type) {
   if(!IsTradeAllowed() && !MQLInfoInteger(MQL_TESTER))
      return;

   int orderList[][2];
   int orderCount = 0;
   int rc = 0;

   for(int i = 0, total = OrdersTotal(); i < total; i++) {
      while(IsTradeContextBusy())
         Sleep(100);

      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         continue;

      if(OrderMagicNumber() != INP_magicNumber || OrderSymbol() != Symbol() || OrderType() != type)
         continue;

      orderCount++;
      ArrayResize(orderList, orderCount);
      orderList[orderCount - 1][0] = (int)OrderOpenTime();
      orderList[orderCount - 1][1] = OrderTicket();
   }

   if(orderCount > 0)
      ArraySort(orderList, WHOLE_ARRAY, 0, MODE_ASCEND);

   for(int i = 0; i < orderCount; i++) {
      if(!OrderSelect(orderList[i][1], SELECT_BY_TICKET, MODE_TRADES))
         continue;

      while(IsTradeContextBusy())
         Sleep(100);

      RefreshRates();
      double normPrice = NormalizeDouble(NormalizePrice(type == OP_SELL ? Ask : Bid), Digits());
      double normLots  = NormalizeVolume(OrderLots());
      int normSlippage = int(INP_maxSlippage * 10);

      if(!OrderClose(OrderTicket(), normLots, normPrice, normSlippage, clrNONE)) {
         rc = GetLastError();
         Print("ERROR TKT", string(OrderTicket()),  " rc ",  rc);
      }
   }
}
//+------------------------------------------------------------------+
// END OF CODE
//+------------------------------------------------------------------+
Files:
Test.mq4  19 kb
 

A quick look, shows me that you have a "MaxSpread" parameter set to 1 pip.

So, what happens if the test is on a higher spread? ... Your EA will not trade — hence, "No trading operations".

Set a default for "MaxSpread" that disables it, or use a very high default for it.

EDIT: I did not check the rest of the code. There may be other reasons as well.

EDIT2: When asking about MT4 or MQL4, please post in that section (at the very end of the forum) and not in the other sections. Otherwise, you may end up receiving answers for MT5 or MQL5 instead.

 
Fernando Carreiro #:

A quick look, shows me that you have a "MaxSpread" parameter set to 1 pip.

So, what happens if the test is on a higher spread? ... Your EA will not trade — hence, "No trading operations".

Set a default for "MaxSpread" that disables it, or use a very high default for it.

EDIT: I did not check the rest of the code. There may be other reasons as well.

EDIT2: When asking about MT4 or MQL4, please post in that section (at the very end of the forum) and not in the other sections. Otherwise, you may end up receiving answers for MT5 or MQL5 instead.

Thanks for your advice. I didn't notice I was posting in the wrong forum.

Can a moderator please move this thread to the MT4 forum, or close it so that I can post it there?

Thanks.

 
Can anyone please give me a hand with the code? I'm really stuck and I have no idea what is wrong. Service Desk is sending me to the forum. I've read everything in here, and the Tester shows I'm catching all errors. I'd need another pair of eyes. Thanks so much in advance.
 

OK, I finally passed the validation, and I'm gonna post here the solution in case it can help someone. The error was really stupid: with so many variables being passed to other functions, I was using the wrong parameter in the formula. Since the names were similar it was kind of hard to spot. I had to stop and debug everything line by line, and then boom! Really, the names were so similar I totally missed that - I should have known better. So here are my modifications:

1) In "RunChecksBeforeOrderSend", from...

double NormalizeVolume(double pVolume) {
   double volume  = 0;
   double volMin = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   double volMax = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
   double volStp = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);

   if(pVolume > 0) {
      volume = MathMax(volMin, pVolume);             
      volume = MathRound(pVolume / volStp) * volStp; 
      volume = MathMin(volMax, pVolume);             
   } else
      volume = volMin;

   return(volume);
}

to...

double NormalizeVolume(double pVolume) {
   double volume  = 0;
   double volMin = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   double volMax = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
   double volStp = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);

   if(pVolume > 0) {
      volume = MathMax(volMin, pVolume);            
      volume = MathRound(volume / volStp) * volStp; // Notice how "volume" is the correct first operand of MathRound and not "pVolume"
      volume = MathMin(volMax, volume);             // Again, notice how "volume" is the correct second operand of MathMin and not "pVolume"
   } else
      volume = volMin;

   return(volume);
}


2) Finally, in "RequestOrderSend", when I call the checks before calling OrderSend, from...

// ORDERSEND CHECKS
   ResetLastError();
   rc = RunChecksBeforeOrderSend(Symbol(), pType, pVolume);

to...

// ORDERSEND CHECKS
   ResetLastError();
   rc = RunChecksBeforeOrderSend(Symbol(), pType, normVolume); // Notice how I use the just normalized volume "normVolume" instead of the original parameter "pVolume"


I hope this helps someone. Regards.

 
I have used all the controls you have implemented, with your corrections and I am still the same, desperate for not being able to get out of this dreaded "no trading operations" error. 
Reason: