Проверка SYMBOL_VOLUME_LIMIT у некоторых брокеров всегда нуль, советник не проходит проверку маркета

 

Изучаю внимательно публикацию https://www.mql5.com/ru/articles/2555 на предмет ошибок, которые можно допустить в советнике, перед публикацией на маркете.

Там есть пример проверки максимально допустимого объема NewOrderAllowedVolume(string symbol). Эта проверка всегда возвращает нуль для некоторых брокеров, среди которых Альпари МТ5 и Робофорекс МТ5, так как у них в спецификации символов этот параметр всегда нуль. Без этого параметра проверку на маркете пройти невозможно. Но и продавать такой товар невыгодно, так как выпадают серьезные брокеры. И что же делать?

Какие проверки должен пройти торговый робот перед публикацией в Маркете
Какие проверки должен пройти торговый робот перед публикацией в Маркете
  • www.mql5.com
Все продукты Маркета перед публикацией проходят обязательную предварительную проверку, так как небольшая ошибка в логике советника или индикатора может привести к убыткам на торговом счете. Именно поэтому нами разработана серия базовых проверок, призванных обеспечить необходимый уровень качества продуктов Маркета. Если в процессе проверки...
 
Evgeniy Scherbina:

Изучаю внимательно публикацию: https://www.mql5.com/ru/articles/2555 на предмет ошибок, которые можно допустить в советник, перед публикацией на маркете.

Там есть пример проверки максимально допустимого объема NewOrderAllowedVolume(string symbol). Эта проверка всегда возвращает нуль для некоторых брокеров, среди которых Альпари МТ5 и Робофорекс МТ5, так как у них в спецификации символов этот параметр всегда нуль. Без этого параметра проверку на маркете пройти невозможно. Но и продавать такой товар невыгодно, так как выпадают серьезные брокеры. И что же делать?

Если != 0.0, выполнять проверку. Если == 0.0, значит переходить дальше и выполнять другие проверки.

То есть предусмотреть два варианта.

 

Наваял вот так:

double get_allowed_volume(){
  double allowed_volume = 0;
  double volume_max_all_brokers = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
  
  
  // этот параметр присутствует не у всех брокеров в спецификации символа
  // однако проверку маркета пройти все равно можно, если схитрить
  double volume_max_for_market = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT);
  
  
  double opened_volume = 0;
  for(int i=0; i<PositionsTotal(); i++){
    if(PositionGetSymbol(i) == _Symbol){
      if(PositionGetString(POSITION_COMMENT) == "bny"){
        opened_volume += PositionGetDouble(POSITION_VOLUME);
      }
    }
  }
  
  
  // здесь можно убедиться, что проверку выполняет маркет
  if(volume_max_for_market != 0){
    if(opened_volume >= 0 && volume_max_for_market - opened_volume <= 0){
      return(0);
    }
    
    allowed_volume = volume_max_for_market - opened_volume;
  
  
  // а это для всего остального
  }else{
    if(opened_volume >= 0 && volume_max_all_brokers - opened_volume <= 0){
      return(0);
    }
    
    allowed_volume = volume_max_all_brokers - opened_volume;
  }
  

  return(allowed_volume);
}
 
Dmytryi Voitukhov:

Уже месяц(!) не могу опубликовать сов. Или я идиот или это просто издевательство... 

Многие пишут, что нужно попробовать то же самое через 10 минут, потом через 20 минут и т.д. И сработает.

Попробуйте такой вариант:

double get_volume(string symbol, int order_type){
   double free_margin            = AccountInfoDouble(ACCOUNT_MARGIN_FREE),
          margin,
          volume_calculated,
          volume_max_all_brokers = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX),
          volume_max_market      = SymbolInfoDouble(symbol, SYMBOL_VOLUME_LIMIT),
          volume_min             = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN),
          volume_opened          = 0,
          volume_step            = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   
   string volume_string;
   
      
             
             
   // расчет моего объема
   if(StringFind(symbol, "XAUUSD", 0) > -1 || StringFind(symbol, "GOLD", 0) > -1){
      volume_string = v_x;
   
   }else{
      volume_string = v;
   }
   
   
   if(StringFind(volume_string, "%", 0) > -1){
      volume_string = StringSubstr(volume_string, 0, StringLen(volume_string)-1);
      volume_calculated = StringToDouble(volume_string);
      volume_calculated = AccountInfoDouble(ACCOUNT_EQUITY) * volume_calculated / 1000;
   
   }else{
      volume_calculated = StringToDouble(volume_string);
   }
   
   
   if(operation == Trade_Fully_Charged){
      if(StringFind(symbol, "EURGBP", 0) > -1 || StringFind(symbol, "GBPJPY", 0) > -1){
         volume_calculated /= 2;
      
      }else if(StringFind(symbol, "USDNOK", 0) > -1 || StringFind(symbol, "USDSEK", 0) > -1){
         volume_calculated /= 10;
      }
   }
   
   
   
   
   // тут лучше перестановка ценностей
   // не идти дальше, если не хватает объема, или он превышен
   int _PositionsTotal = PositionsTotal();
   
   for(int i=0; i<_PositionsTotal; i++){
      if(PositionGetSymbol(i) == symbol){
         volume_opened += PositionGetDouble(POSITION_VOLUME);
      }
   }

   
   
   
   // только после этого считать шаг и проверять маржу   
   int ratio = (int) MathFloor(volume_calculated / volume_step);
   
   if(MathAbs(ratio * volume_step - volume_calculated) > 0.0000001){
      volume_calculated = ratio*volume_step;
   }
   
   
   
   
   // проверка маржи
   if(order_type == ORDER_TYPE_BUY){
      if(!OrderCalcMargin(
            ORDER_TYPE_BUY, 
            symbol, 
            (volume_calculated < volume_min ? volume_min : volume_calculated), 
            SymbolInfoDouble(symbol, SYMBOL_ASK), 
            margin
         )){
         
         Print("Error in ", __FUNCTION__, ", error code ", GetLastError());
         return 0;
      }


      if(margin > free_margin){
         Print("Not enough money for ORDER_TYPE_BUY at ", volume_calculated, ", ", symbol, ", error code ", GetLastError());
         return 0;
      }
      
      
   }else if(order_type == ORDER_TYPE_SELL){
      if(!OrderCalcMargin(
            ORDER_TYPE_SELL, 
            symbol, 
            (volume_calculated < volume_min ? volume_min : volume_calculated), 
            SymbolInfoDouble(symbol, SYMBOL_BID), 
            margin
         )){
         
         Print("Error in ", __FUNCTION__, ", error code ", GetLastError());
         return 0;
      }
      

      if(margin > free_margin){
         Print("Not enough money for ORDER_TYPE_SELL at ", volume_calculated, ", ", symbol, ", error code ", GetLastError());
         return 0;
      }
   }
   
   
   
   
   if(volume_calculated + volume_opened > volume_max_market && volume_max_market != 0) return 0;
   if(volume_calculated + volume_opened > volume_max_all_brokers) return volume_max_all_brokers;
   if(volume_calculated < volume_min){
      if(StringFind(symbol, "EURGBP", 0) > -1 ||
         StringFind(symbol, "GBPJPY", 0) > -1 ||
         StringFind(symbol, "USDNOK", 0) > -1 ||
         StringFind(symbol, "USDSEK", 0) > -1 ||
         StringFind(symbol, "XAUUSD", 0) > -1 ||
         StringFind(symbol, "GOLD", 0) > -1) return 0;
      else return volume_min;
   }
   
   
   
   
   return volume_calculated;
}
 
Evgeniy Scherbina:

Многие пишут, что нужно попробовать то же самое через 10 минут, потом через 20 минут и т.д. И сработает.

Попробуйте такой вариант:

Такая же фигня, короче просто нужно делать так чтобы объемы при валидации были минимальными. Автоматическая валидация это конечно смех и грех.. Но куда деваться. У меня получилось, но получается что настройки по дефолту будут косыми для того чтобы валидацию пройти, и сет отдельно выкладввать

Причина обращения: