Меню

Possible use of uninitialized variable mql4 ошибка

Чтобы было понятней давайте расшифруем всё по-порядку

#property strict

void Trailing(int Magic_to_function, string Symbol_Curent ,int Dist_to_function, int Shag_to_function, bool Isp_shag, bool Bezubitok)
{  
     double dist; 
     double shag;
     
     if      (Digits==3 || Digits==5){dist=Dist_to_function*10*Point;    shag=Shag_to_function*10*Point;}
     else if (Digits==2 || Digits==4){dist=Dist_to_function*Point;       shag=Shag_to_function*Point;}

1. Объявили переменные без явной инициализации

2. Присваивается значение этим переменным только при условии 1 или 2

Соответственно в случае не выполнения этих условий переменные так и останутся не инициализированными… О чём и предупреждает компилятор.

Я-бы написал так, учитывая что это, как мне кажется, для мультивалютника…

#property strict

void Trailing(int Magic_to_function, string Symbol_Curent ,int Dist_to_function, int Shag_to_function, bool Isp_shag, bool Bezubitok)
{
     double sp = MarketInfo(Symbol_Curent, MODE_POINT);
     double dist = Dist_to_function*sp; 
     double shag = Shag_to_function*sp;
     
     if(Digits == 3 || Digits == 5) // или лучше if(Digits % 2 == 1)
      {
       dist = Dist_to_function*10*sp;
       shag = Shag_to_function*10*sp;
      }
// и дальше по тексту
}

Konstantin Erin:

1. Судя по всему, LabelCreate() — это Ваша пользовательская функция. И что второй параметр? Обратный слеж используется для указания Esc-последовательностей: n — новая строка  (посмотрите ссылку), t — табуляция и т.д. а Вам что нужно?

2. Поставьте курсор на datetime и нажмите F1 — примеры задания времени: datetime A = D’23:59′;

3. Ставьте курсор на OBJPROP_FONT и нажмите F1 -надо ObjectSetString

4. int m=CurTime(); F1 Устарело, надо TimeCurrent() F1. Возвращает datetime 8 байт, как уместить лишь в 4 байта int ? Попробуйте long

ну и так далее …  Почаще нажимайте F1

Спасибо, помогли, не понятно что с 3 пунктом:
вот код:

      if (ObjectCreate(0, "MouseInfo", OBJ_LABEL, 0, 0, 0)) ObjectSetString(0, "MouseInfo", OBJPROP_TEXT, " ");
      ObjectSet("MouseInfo", OBJPROP_BACK, false);                    // Рисовать объект в фоне
      ObjectSet("MouseInfo", OBJPROP_SELECTED, false);                // Снять выделение с объекта
      ObjectSet("MouseInfo", OBJPROP_SELECTABLE, false);              // Запрет на редактирование
      ObjectSet("MouseInfo", OBJPROP_HIDDEN, true);                   // Скроем (true) или отобразим (false) имя графического объекта в списке объектов
      ObjectSet("MouseInfo", OBJPROP_FONT, "Arial");
      ObjectSet("MouseInfo", OBJPROP_FONTSIZE, 10);
      ObjectSet("MouseInfo", OBJPROP_COLOR, clrDodgerBlue);

и первый, мне нужно просто на экране получить OBJ_LABEL, в котором 2 символа:

Alt

23.03.18

Elite Mitglied

 

Registriert seit: Mar 2018

Ort: Hamburg

Beitr�ge: 606

AVT befindet sich auf einem aufstrebenden Ast

Standard
possible use of uninitialized variable


Ich habe ein Verst�ndnisproblem, warum ich die Warnung
«possible use of uninitialized variable ‘Factor’ » f�r folgenden Codeaufbau bekomme, und zwar f�r die rote Zeile:

Code:

// head
int a;          // used everywhere in several functions
double FinalVal;
// end head

Func()
{
   if(Condition)
   {
      int Factor;
      if(Cond1)      Factor=2;
      else if(Cond2) Factor=3;
      // more code for a and Variable calc
      FinalVal=NormalizeDouble(a*Variable*Factor,2);
   }
}

Factor wird ausschlie�lich in Func() gebraucht, also geh�rt es da rein und nicht in den Head (steht es da, ist die Warnung weg) und es wird auch nur gebraucht, wenn die Bedingung true ist, also geh�rt es da rein und nicht an den Anfang der Func(). Und auch wenn dazwischen 1000 Zeilen Code stehen, bevor FinalVal kommt, das Ding ist initialized und ich verstehe nicht, warum ich ne Warnung kriege. Kann mich da vielleicht mal jemand erleuchten.
Danke. AVT

Alt

23.03.18

Premium Mitglied

 

Registriert seit: Apr 2015

Beitr�ge: 422

Raul0 befindet sich auf einem aufstrebenden Ast

Standard


Versuche doch der Variable Faktor einen Erst-Wert zu geben, zB:

PHP-Code:



int Factor 0




Alt

24.03.18

Premium Mitglied

 

Registriert seit: May 2015

Beitr�ge: 367

next user befindet sich auf einem aufstrebenden Ast

Standard


Zitat:

Zitat von AVT
Beitrag anzeigen

Und auch wenn dazwischen 1000 Zeilen Code stehen, bevor FinalVal kommt, das Ding ist initialized…

Nicht ganz. Der Compiler sieht da die Deklaration deiner Variablen ohne einen Anfangswert zu definieren.
Sofern eine Variable keinen «echten» Wert zugewiesen bekommt, «erh�lt» sie einen undefinierten Standardwert.
Einen echten Wert erh�lt deine Variable aber nur beim Zutreffen einer Bedingung. W�re da ein «if-else» anstatt «if-else if», so w�rde
deine Variable in jedem Fall einen echten Wert bekommen.

Also kurz:
Erh�lt eine Variable nur unter Bedingungen einen Wert, denkt der Compiler sich «die Bedingungen k�nnen auch NICHT zutreffen».
Eine weitere Nutzung einer solchen Variable l�sst den Compiler dann warnen «diese Variable wurde vorher

m�glicherweise

nicht
mit einem Wert gef�tter…»

Alt

24.03.18

Elite Mitglied

 

Registriert seit: Mar 2018

Ort: Hamburg

Beitr�ge: 606

AVT befindet sich auf einem aufstrebenden Ast

Standard


Ich danke Euch, Raul0 und next user.

Zitat:

Zitat von next user
Beitrag anzeigen

Nicht ganz. Der Compiler sieht da die Deklaration deiner Variablen ohne einen Anfangswert zu definieren.
Sofern eine Variable keinen «echten» Wert zugewiesen bekommt, «erh�lt» sie einen undefinierten Standardwert.

declaration != initialization

Zitat:

Zitat von next user
Beitrag anzeigen

W�re da ein «if-else» anstatt «if-else if», so w�rde deine Variable in jedem Fall einen echten Wert bekommen..

Jep, die 3. Zeile «else» hatte ich auskommentiert, mein Fehler. Alte Regel «kein if ohne else» (macht zwar den Code manchmal unn�tig lang, verhindert aber Fehler) mal wieder mi�achtet.
Wer mal die glibc mit allwarnings kompiliert hat, lernt schnell eine Warnung ist eine Warnung und kein Fehler, aber ich hab’s lieber ohne Warnungen im strict Modus. AVT

Alt

24.03.18

Premium Mitglied

 

Registriert seit: May 2015

Beitr�ge: 367

next user befindet sich auf einem aufstrebenden Ast

Standard


Zitat:

Zitat von AVT
Beitrag anzeigen

declaration != initialization

Hi,

mir sind die Unterschiede zwischen Deklaration, Definition, Initialisierung ect. bekannt.
Deine Anmerkung passt allerdings nicht zu meinen S�tzen. Du musst diese schon zusammen betrachten.
Besonders im ersten Satz von mir «umschreibe» ich da KEINE Deklaration mit einer Initialisierung, aber ist ja auch egal…

Zitat:

Zitat von AVT
Beitrag anzeigen

… aber ich hab’s lieber ohne Warnungen im strict Modus.

Geht mir genauso.

Alt

24.03.18

Elite Mitglied

 

Registriert seit: Mar 2018

Ort: Hamburg

Beitr�ge: 606

AVT befindet sich auf einem aufstrebenden Ast

Standard


Zitat:

Zitat von next user
Beitrag anzeigen

mir sind die Unterschiede zwischen Deklaration, Definition, Initialisierung ect. bekannt.

Aber mir anscheinend nicht genug! Und ich hatte Dich so verstanden, da� eine «int a;» eben nur eine Deklaration ist, die besagt da� ich mal ein a vom integer Typ benutzen will — und erst mit «a=1;» eine Intialisierung draus wird, die sagt nun la� uns mal konkret bei 1 anfangen mit der a Benutzung.
F�r mich war urspr�nglich die Initialisierung mit «int a;» abgeschlossen und nun habe ich als Fazit im Lernspeicher: Achtung ist nicht dasselbe.

Zitat:

Zitat von next user
Beitrag anzeigen

aber ist ja auch egal…

Speicher kann man auch wieder freigeben, wenn’s sein mu� … Sch�nes Wochenende. AVT

Alt

25.03.18

Elite Mitglied

 

Registriert seit: Apr 2011

Beitr�ge: 2.695

traderdoc befindet sich auf einem aufstrebenden Ast

Standard


«Speicher kann man auch wieder freigeben, wenn’s sein mu� …»

Das ist mir jetzt etwas zu platt. Welchen Speicher meinst Du?
Da wir hier die ganze Zeit um die Deklaration und Initialisierung einer Integer-Variablen geschrieben haben, erkl�rst Du mal bitte die Freigabe konkret daran.

Danke.

traderdoc

__________________
Ich erf�lle Euch gern Eure EA-, Indikator- und Script-Programmierungsw�nsche auf Honorarbasis.

Alt

25.03.18

Premium Mitglied

 

Registriert seit: Jun 2013

Beitr�ge: 362

Ca$hDigger befindet sich auf einem aufstrebenden Ast

Standard


Dynamische Speicherverwaltung: new, delete.
Sollte aber nur mit Klassen gehen. Ein einziges int in eine Klasse packen sollte sich nicht lohnen, die 4Byte m�sste der RAM verkraften

C$D

Alt

25.03.18

Elite Mitglied

 

Registriert seit: Apr 2011

Beitr�ge: 2.695

traderdoc befindet sich auf einem aufstrebenden Ast

Standard


Zitat:

Zitat von Ca$hDigger
Beitrag anzeigen

Dynamische Speicherverwaltung: new, delete.
Sollte aber nur mit Klassen gehen. Ein einziges int in eine Klasse packen sollte sich nicht lohnen, die 4Byte m�sste der RAM verkraften
C$D

Ne, die dynamische Speicherverwaltung kann er nicht meinen.

traderdoc

__________________
Ich erf�lle Euch gern Eure EA-, Indikator- und Script-Programmierungsw�nsche auf Honorarbasis.

Alt

25.03.18

Premium Mitglied

 

Registriert seit: Jun 2013

Beitr�ge: 362

Ca$hDigger befindet sich auf einem aufstrebenden Ast

Standard


Ein global deklariertes int wie hier l�sst sich nicht freigeben, ausser wie genannt es befindet sich in einer dynamischen Struktur wie Klasse oder Array…

Mal davon abgesehen, was sollte der Sinn davon sein, warum sollte man ein einzelnes int mit 4Byte freigeben wollen?

  • #8 901

double LOTHIS()
  {
   double hislot;
   for(int y=0; y<=OrdersHistoryTotal()-1; y++)
     {
      if(OrderSelect(y, SELECT_BY_POS,MODE_HISTORY)==true && OrderMagicNumber()==Magic && OrderSymbol()==_Symbol)//Выбираем ордер
        {
        }
     }
   return(hislot);
  }
//##

Почему выдает эту ошибку:
possible use of uninitialized variable ‘hislot’ Umr3.mq4 162 11

Ведь я проинициализировал в самой функции.

  • #8 902

double LOTHIS()
  {
   double hislot;
   for(int y=0; y<=OrdersHistoryTotal()-1; y++)
     {
      if(OrderSelect(y, SELECT_BY_POS,MODE_HISTORY)==true && OrderMagicNumber()==Magic && OrderSymbol()==_Symbol)//Выбираем ордер
        {
        }
     }
   return(hislot);
  }
//##

Почему выдает эту ошибку:
possible use of uninitialized variable ‘hislot’ Umr3.mq4 162 11

Ведь я проинициализировал в самой функции.

А, если не было в истории ни одного ордера с указанным меджиком и символом — какое значение должна вернуть ф-ция ???

  • #8 903

при такой записи

extern int StopLoss = 250;//Фиксированный уровень стопа
extern int TakeProfit = 500;//Фиксированный уровень профита
int coeff,intBars;
//+------------------------------------------------------------------+
int OnInit(){
   if(MarketInfo(Symbol(),MODE_DIGITS)==5)
      coeff = 10;
   if(MarketInfo(Symbol(),MODE_DIGITS)==3)
      coeff = 10;
   StopLoss  *= coeff;
   TakeProfit*= coeff;
}

если Digits() не равен 3 или 5, допустим он равен 2 или 1, то чему будет равен StopLoss и TakeProfit ?

  • #8 904

void OnTick()
  {
   if(OrdersTotal()==0)
     {
      uo(svecha);
      ue(sltp);
      if(svecha[4][1]<0 && svecha[4][2]<0 && svecha[4][3]<0)
         Print(Bid-sltp[0]*Point);
      ticketss=OrderSend(Symbol(),OP_BUY,Lot,Ask,Slippage,Bid-sltp[0]*Point,0,"S1 buy",Magic,clrNONE);
      if(svecha[4][1]>0 && svecha[4][2]>0 && svecha[4][3]>0)
         ticketss=OrderSend(Symbol(),OP_SELL,Lot,Bid,Slippage,Ask+sltp[0]*Point,0,"S1 sell",Magic,clrNONE);
     }
  }
//+------------------------------------------------------------------+
//| User function                                                    |
//+------------------------------------------------------------------+
void ue(double &gh2[3])//Значения стопп и профита sltp[2];
  {
   gh2[0]=NormalizeDouble(StopLoss*Point,Digits);//Фиксирование убытков
   gh2[1]=NormalizeDouble(TakeProfit*Point,Digits);//Фиксирование приболи
   gh2[2]=NormalizeDouble(MarketInfo(Symbol(),MODE_FREEZELEVEL),Digits);//Минимальный стоплос и профит
   gh2[3]=NormalizeDouble(MarketInfo(Symbol(),33),Digits);//Минимальный лот
  };
//###############################################################################
void uo(double &gh[10][31])//Массив свечей svecha[10][31];
  {
   for(int i = 0; i < ArrayRange(gh, 1); i++)
     {
      gh[0][i] = Open[i];//Открытие свечи
      gh[1][i] = Close[i];//Закрытие свечи
      gh[2][i] = High[i];//Макс свечи
      gh[3][i] = Low[i];//Мин свечи
      gh[4][i] = Open[i]-Close[i];//Тело свечи
      gh[5][i] = High[i]-Low[i];//Высота свечи
      gh[6][i] = High[i]-Open[i];//верхняя тень черной свечи
      gh[7][i] = High[i]-Close[i];//Верхняя тень белой свечи
      gh[8][i] = Open[i]-Low[i];//Нижняя тень белой свечи
      gh[9][i] = Close[i]-Low[i];//Нижняя тень черной свечи
     }
  };
//+------------------------------------------------------------------+

Весь код. Не понимаю что не так.

  • #8 905

при такой записи

extern int StopLoss = 250;//Фиксированный уровень стопа
extern int TakeProfit = 500;//Фиксированный уровень профита
int coeff,intBars;
//+------------------------------------------------------------------+
int OnInit(){
   if(MarketInfo(Symbol(),MODE_DIGITS)==5)
      coeff = 10;
   if(MarketInfo(Symbol(),MODE_DIGITS)==3)
      coeff = 10;
   StopLoss  *= coeff;
   TakeProfit*= coeff;
}

если Digits() не равен 3 или 5, допустим он равен 2 или 1, то чему будет равен StopLoss и TakeProfit ?

if(MarketInfo(Symbol(),MODE_DIGITS)==2)
coeff = 10;
if(MarketInfo(Symbol(),MODE_DIGITS)==1)
coeff = 10

  • #8 906

if(MarketInfo(Symbol(),MODE_DIGITS)==2)
coeff = 10;
if(MarketInfo(Symbol(),MODE_DIGITS)==1)
coeff = 10

А если 0 или 6, то тогда что? Распиши уже на все случаи жизни, чтобы ни ку кого не возникало больше вопросов.

  • #8 907

void OnTick()
  {
   if(OrdersTotal()==0)
     {
      uo(svecha);
      ue(sltp);
      if(svecha[4][1]<0 && svecha[4][2]<0 && svecha[4][3]<0)
         Print(Bid-sltp[0]*Point);
      ticketss=OrderSend(Symbol(),OP_BUY,Lot,Ask,Slippage,Bid-sltp[0]*Point,0,"S1 buy",Magic,clrNONE);
      if(svecha[4][1]>0 && svecha[4][2]>0 && svecha[4][3]>0)
         ticketss=OrderSend(Symbol(),OP_SELL,Lot,Bid,Slippage,Ask+sltp[0]*Point,0,"S1 sell",Magic,clrNONE);
     }
  }
//+------------------------------------------------------------------+
//| User function                                                    |
//+------------------------------------------------------------------+
void ue(double &gh2[3])//Значения стопп и профита sltp[2];
  {
   gh2[0]=NormalizeDouble(StopLoss*Point,Digits);//Фиксирование убытков
   gh2[1]=NormalizeDouble(TakeProfit*Point,Digits);//Фиксирование приболи
   gh2[2]=NormalizeDouble(MarketInfo(Symbol(),MODE_FREEZELEVEL),Digits);//Минимальный стоплос и профит
   gh2[3]=NormalizeDouble(MarketInfo(Symbol(),33),Digits);//Минимальный лот
  };
//###############################################################################
void uo(double &gh[10][31])//Массив свечей svecha[10][31];
  {
   for(int i = 0; i < ArrayRange(gh, 1); i++)
     {
      gh[0][i] = Open[i];//Открытие свечи
      gh[1][i] = Close[i];//Закрытие свечи
      gh[2][i] = High[i];//Макс свечи
      gh[3][i] = Low[i];//Мин свечи
      gh[4][i] = Open[i]-Close[i];//Тело свечи
      gh[5][i] = High[i]-Low[i];//Высота свечи
      gh[6][i] = High[i]-Open[i];//верхняя тень черной свечи
      gh[7][i] = High[i]-Close[i];//Верхняя тень белой свечи
      gh[8][i] = Open[i]-Low[i];//Нижняя тень белой свечи
      gh[9][i] = Close[i]-Low[i];//Нижняя тень черной свечи
     }
  };
//+------------------------------------------------------------------+

Весь код. Не понимаю что не так.

А в такой записи стопы ставяться что -не так не пойму?

void OnTick()
  {
   if(OrdersTotal()==0)
     {
      ticketss=OrderSend(Symbol(),OP_SELL,Lot,Bid,Slippage,Ask+StopLoss*Point,0,"S1 sell",Magic,clrNONE);
     }
  }

  • #8 908

Добрый день знатокам, помогите написать индикатор. Сам, ну очень далек от программирования. условия очень простые, не займет много времени.
Берем бар, находим середину бара через хай и лоу. если уровень открытия и закрытия находится в нижней половине бара — то это бар на продажу. на покупку открытие и закрытие должно быть в верхней половине. удовлетворяющий условиям бар нужно подкрасить и стрелку добавить.
Помогите кому не трудно, буду очень признателен.

  • #8 909

if(MarketInfo(Symbol(),MODE_DIGITS)==2)
coeff = 10;
if(MarketInfo(Symbol(),MODE_DIGITS)==1)
coeff = 10

если переменная coeff везде равна 10, то почему бы сразу так не записать

или без переменной coeff

StopLoss  *= 10;
TakeProfit*= 10;

или сразу так :)

extern int StopLoss = 2500;//Фиксированный уровень стопа
extern int TakeProfit = 5000;//Фиксированный уровень профита

вот пример

  int coeff = 1; // задай стартовое значение (инициализируй), может меньше условий придётся писать
  long dig = SymbolInfoInteger(symbol,SYMBOL_DIGITS); // для другого графика, для текущего достаточно Digits()
// тут не забудь про фильтры, к какой группе относится символ форекс/не форекс (когда будет актуально разберёшься ))
  if(dig == 3 || dig == 5)coeff = 10;

  • #8 910

А в такой записи стопы ставяться что -не так не пойму?

если не понятно, значит ошибка в таком месте, где даже не ждал, что она там будет.
тот же самый алгоритм действий: принтуй значения стопов от выставления ордера до их объявления.
если всё везде правильно, но стопы не выставляются, то проверь тип счёта может это ECN

Весь код. Не понимаю что не так.

скобки забываешь ставить после условий, может когда добавляешь принты

  • #8 911

Добрый день знатокам, помогите написать индикатор. Сам, ну очень далек от программирования. условия очень простые, не займет много времени.
Берем бар, находим середину бара через хай и лоу. если уровень открытия и закрытия находится в нижней половине бара — то это бар на продажу. на покупку открытие и закрытие должно быть в верхней половине. удовлетворяющий условиям бар нужно подкрасить и стрелку добавить.
Помогите кому не трудно, буду очень признателен.

Подобные просьбы размещают в Бесплатное написание программ или в Предложения по автоматизации торговли.
А здесь задают вопросы по языку программирования те кто сам пишет и чего то не понял.

  • #8 912

Привет. Ребята, что вписать в код индикатора чтобы он ставился на график много раз при смене настроек, а непереставлялся только с новыми ???
И другой вопрос, чтобы убирал за собой линии и т.д.

griz

griz

Активный участник


  • #8 913

чтобы он ставился на график много раз при смене настроек, а непереставлялся только с новыми ???

Т.е. в настройках индикатора меняешь параметры, и на графике каждый раз (при изменении параметров) создаются новые версии этого индикатора, как бы каждая версия со своими параметрами, я правильно понял?

  • #8 914

почему после нормализации все равно выдает:
2022.11.06 20:10:49.998 2004.04.13 00:00:46 Umr3 AUDCAD,H4: ДЛя открытия сделок Бай=SL=0.9844000000000001=TP=1.061=ASK=1.011=BID=1.0094

  • #8 915

Т.е. в настройках индикатора меняешь параметры, и на графике каждый раз (при изменении параметров) создаются новые версии этого индикатора, как бы каждая версия со своими параметрами, я правильно понял?

Да,все так.

griz

griz

Активный участник


  • #8 916

почему после нормализации все равно выдает:
2022.11.06 20:10:49.998 2004.04.13 00:00:46 Umr3 AUDCAD,H4: ДЛя открытия сделок Бай=SL=0.9844000000000001=TP=1.061=ASK=1.011=BID=1.0094

допиши:

string SL_2 = DoubleToString(SL,Digits);
Print("SL_2=",SL_2);

  • #8 917

допиши:

string SL_2 = DoubleToString(SL,Digits);
Print("SL_2=",SL_2);

Мне потом в ордер сенд вставлять нужно.

griz

griz

Активный участник


  • #8 918

Т.е. в настройках индикатора меняешь параметры, и на графике каждый раз (при изменении параметров) создаются новые версии этого индикатора, как бы каждая версия со своими параметрами, я правильно понял?

Вроде так нельзя делать. Тут нужно разрабатывать индюк, чтобы он мог создавать свои дубли с настраиваемыми параметрами.

  • #8 919

И другой вопрос, чтобы убирал за собой линии и т.д.

если совсем простенький вариант, то добавь это

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

void OnDeinit(const int reason){
  ObjectsDeleteAll(chart_id/*идентификатор графика*/,prefix/*одинаковая не меняющаяся часть названия у объектов*/,sub_window/*номер подокна*/,object_type/*тип объекта*/);
}

если функция OnDeinit в коде уже есть, то в неё просто добавь содержимое из этого примера,
подставь нужные значения (последние два параметра не обязательные)
тут справка -https://docs.mql4.com/ru/objects/objectsdeleteall, возможно оттуда подойдут другие варианты

griz

griz

Активный участник


  • #8 920

Мне потом в ордер сенд вставлять нужно.

в ордер сенд вставляй так:

Разработка торговых экспертов на языке MQL4 является не такой уж простой задачей. Во-первых – алгоритмизация любой сложной торговой системы уже представляет собой проблему, так как нужно учесть очень много деталей, начиная с особенностей ТС и заканчивая спецификой среды MetaTrader 4. Во-вторых, даже наличие детальнейшего алгоритма не избавляет от сложностей, возникающих при переносе разработанного алгоритма на язык программирования MQL4.

Компилятор оказывает некоторую помощь при написании корректных экспертов. После начала компиляции MetaEditor сообщит обо всех синтаксических ошибках в вашем коде. Но, к сожалению, помимо синтаксических ошибок ваш советник может содержать еще и логические ошибки, которые компилятор выловить не может. Поэтому этим нам придется заняться самим. Как это сделать – в нашем сегодняшнем материале.

MQL4 — Ошибки и как их исправить

Самые распространенные ошибки компиляции

При наличии ошибок в коде программа не может быть скомпилирована. Для полного контроля всех ошибок рекомендуется использовать строгий режим компиляции, который устанавливается директивой:

Этот режим значительно упрощает поиск ошибок. Теперь перейдем к самым распространенным ошибкам при компиляции.

Идентификатор совпадает с зарезервированным словом

Если наименование переменной или функции совпадает с одним из зарезервированных слов:

int char[];  // неправильно
int char1[]; // правильно
int char()   // неправильно
{
    return(0);
}

то компилятор выводит сообщения об ошибках:

Для исправления данной ошибки нужно исправить имя переменной или функции. Я рекомендую придерживаться следующей системы для именования:

Все функции должны обозначать действие. То есть это должен быть глагол. Например, OpenLongPosition() или ModifyStopLoss(). Ведь функции всегда именно что-то делают, верно?

Кроме того, функции желательно называть в так называемом CamelCase стиле. А переменные в cebab_case стиле. Это общепринятая практика.

Кстати, об именах переменных. Переменные – это существительные. Например, my_stop_loss, day_of_week, current_month. Не так страшно назвать переменную длинным именем, гораздо страшнее назвать ее непонятно. Что такое dow, индекс Dow Jones? Нет, это, оказывается, день недели. Конечно, сегодня вам и так понятно, что это за переменная. Но когда вы откроете код советника месяц спустя, все будет уже не так явно. А это время, упущенное на расшифровку посланий из прошлого – оно вам надо?

Специальные символы в наименованиях переменных и функций

Идем дальше. Если наименования переменных или функций содержат специальные символы ($, @, точка):

int $var1; // неправильно
int @var2; // неправильно
int var.3; // неправильно
void f@()  // неправильно
{
    return;
}

то компилятор выводит сообщения об ошибках:

Для исправления данной ошибки снова нужно скорректировать имена переменных или функций, ну или сразу называть их по-человечески. В идеале код нужно писать так, чтобы даже человек, не знающий программирование, просто его прочел и понял, что там вообще происходит.

Ошибки использования оператора switch

Старая версия компилятора позволяла использовать любые значения в выражениях и константах оператора switch:

void start()
{
    double n=3.14;
    switch(n)
    {
        case 3.14: 
            Print("Pi");
            break;
        case 2.7: 
            Print("E");
            break;
    }
}

В новом компиляторе выражения и константы оператора switch должны быть целыми числами, поэтому при использовании подобных конструкций возникают ошибки:

Поэтому, когда вы разбираете код классики, такой, как WallStreet, Ilan и прочей нетленки (что очень полезно для саморазвития), можно натолкнуться на эту ошибку. Лечится она очень просто, например, при использовании такой вот строки:

switch(MathMod(day_48, 10))

Вот так можно запросто решить проблему:

switch((int)MathMod(day_48, 10))

Возвращаемые значений функций

Все функции, кроме void, должны возвращать значение объявленного типа. Например:

При строгом режиме компиляции (strict) возникает ошибка:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Если возвращаемое значение функции не соответствует объявлению:

Тогда при строгом режиме компиляции возникает ошибка:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Для исправления таких ошибок в код функции всего-навсего нужно добавить оператор возврата return c возвращаемым значением соответствующего типа.

Массивы в аргументах функций

Массивы в аргументах функций передаются только по ссылке. Раньше это было не так, поэтому в старых советниках можно встретить эту ошибку. Вот пример:

double ArrayAverage(double a[])
{
    return(0);
}

Данный код при строгом режиме компиляции (strict) приведет к ошибке:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Для исправления таких ошибок нужно явно указать передачу массива по ссылке, добавив префикс & перед именем массива:

double ArrayAverage(double &a[])
{
    return(0);
}

Кстати, константные массивы (Time[], Open[], High[], Low[], Close[], Volume[]) не могут быть переданы по ссылке. Например, вызов:

вне зависимости от режима компиляции приводит к ошибке:

Для устранения подобных ошибок нужно скопировать необходимые данные из константного массива:

//--- массив для хранения значений цен открытия
double OpenPrices[];
//--- копируем значения цен открытия в массив OpenPrices[]
ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY);
//--- вызываем функцию
ArrayAverage(OpenPrices);

Одна из самых распространенных ошибок – потеря советником индикатора. В таких случаях обычно пользователи эксперта на форумах гневно пишут: «Советник не работает!» или «Ставлю советник на график и ничего не происходит!». Решение этого вопроса на самом деле очень простое. Как всегда, достаточно просто заглянуть на вкладку «Журнал» терминала и обнаружить там запись вроде:

2018.07.08 09:15:44.957 2016.01.04 00:51 cannot open file 
'C:Users1AppDataRoamingMetaQuotesTerminal
MQL4indicatorsKELTNER_F12.ex4' [2]

Говорит это нам о том, что индикатор в папку положить забыли, или же он назван по-другому. Если индикатор отсутствует, нужно добавить его в папку с индикаторами. Если он есть, стоит проверить его название в коде советника – скорее всего там он называется по-другому.

Предупреждения компилятора

Предупреждения компилятора носят информационный характер и не являются сообщениями об ошибках, однако они указывают на возможные источники ошибок и лучше их скорректировать. Чистый код не должен содержать предупреждений.

Пересечения имен глобальных и локальных переменных

Если на глобальном и локальном уровнях присутствуют переменные с одинаковыми именами:

int i; // глобальная переменная
void OnStart()
{
    int i=0,j=0; // локальные переменные

    for (i=0; i<5; i++) {
        j+=i;
    }
    PrintFormat("i=%d, j=%d",i,j);
}

то компилятор выводит предупреждение и укажет номер строки, на которой объявлена глобальная переменная:

Для исправления таких предупреждений нужно скорректировать имена глобальных переменных.

Несоответствие типов

В следующем примере:

#property strict
void OnStart()
{
    double a=7;
    float b=a;
    int c=b;
    string str=c;
    Print(c);
}

при строгом режиме компиляции при несоответствии типов компилятор выводит предупреждения:

В данном примере компилятор предупреждает о возможной потере точности при присвоении различных типов данных и неявном преобразовании типа int в string.

Для исправления нужно использовать явное приведение типов:

#property strict
void OnStart()
{
    double a=7;
    float b=(float)a;
    int c=(int)b;
    string str=(string)c;
    Print(c);
}

Неиспользуемые переменные

Наличие переменных, которые не используются в коде программы (лишние сущности) не является хорошим тоном.

void OnStart()
{
    int i,j=10,k,l,m,n2=1;
    for(i=0; i<5; i++) {j+=i;}
}

Сообщения о таких переменных выводятся вне зависимости от режима компиляции:

Для исправления нужно просто убрать неиспользуемые переменные из кода программы.

Диагностика ошибок при компиляции

Часто после написания программы возникают проблемы при компиляции, вызванные ошибками в коде. Это могут быть самые различные ошибки, но в любом случае возникает необходимость оперативного обнаружения участка кода, где допущена ошибка.

Нередко у людей уходит немало времени и масса нервов на поиски какой-нибудь лишней скобки. Однако, есть способ быстрого обнаружения ошибок, который основан на использовании комментирования.

Написать достаточно большой код без единой ошибки – очень приятно. Но, к сожалению, так получается не часто. Я не рассматриваю здесь ошибки, которые приводят к неверному исполнению кода. Здесь пойдёт речь об ошибках, из-за которых становится невозможной компиляция.

Весьма распространённые ошибки – вставка лишней скобки в сложном условии, нехватка скобки, не выставление двоеточия, запятой при объявлении переменных, опечатка в названии переменной и так далее. Часто при компиляции можно сразу увидеть, в какой строке допущена подобная ошибка. Но бывают и случаи, когда найти такую ошибку не так просто. Ни компилятор, ни зоркий глаз нам не могут помочь сразу найти ошибку. В таких случаях, как правило, начинающие программисты начинают “обходить” весь код, пытаясь визуально определить ошибку. И снова, и снова, пока выдерживают нервы.

Однако MQL, как и другие языки программирования, предлагает отличный инструмент – комментирование. Используя его, можно отключать какие-то участки кода. Обычно комментирование используют именно для вставки каких-то комментариев, или же отключения неиспользуемых участков кода. Комментирование можно также успешно применять и при поиске ошибок.

Поиск ошибок обычно сводится к определению участка кода, где допущена ошибка, а затем, в этом участке, визуально находится ошибка. Думаю, вряд ли кто-то будет сомневаться в том, что исследовать “на глаз” 5-10 строчек кода проще и быстрей, чем 100-500, а то и несколько тысяч.

При использовании комментирования задача предельно проста. Сначала нужно закомментировать различные участки кода (иногда чуть ли не весь код), тем самым “отключив” его. Затем, по очереди, комментирование снимается с этих участков кода. После очередного снятия комментирования совершается попытка компиляции. Если компиляция прошла успешно – ошибка не в этом участке кода. Затем открывается следующий участок кода и так далее. Когда находится проблемный участок кода, визуально ищется ошибка, затем устраняется. Опять происходит попытка компиляции. Если всё прошло успешно, ошибка устранена.

Важно правильно определять участки кода, которые необходимо комментировать. Если это условие (или иная логическая конструкция), то оно должно комментироваться полностью. Если комментируется участок кода, где объявляются переменные, важно, чтобы не был открыт участок, где происходит обращение к этим переменным. Иначе говоря – комментирование должно применяться по логике программирования. Несоблюдения такого подхода приводит к возникновению новых, вводящих в заблуждение, ошибок при компиляции.

Вот отличный пример ошибки, когда неясно, где ее искать и нас может выручить комментирование кода.

Ошибки времени выполнения

Ошибки, возникающие в процессе исполнения кода программы, принято называть ошибками времени выполнения (runtime errors). Такие ошибки обычно зависят от состояния программы и связаны с некорректными значениями переменных.

Например, если переменная используется в качестве индекса элементов массива, то ее отрицательные значения неизбежно приведут к выходу за пределы массива.

Выход за пределы массива (Array out of range)

Эта ошибка часто возникает в индикаторах при обращении к индикаторным буферам. Функция IndicatorCounted() возвращает количество баров, не изменившихся после последнего вызова индикатора. Значения индикаторов на уже рассчитанных ранее барах не нуждаются в пересчете, поэтому для ускорения расчетов достаточно обрабатывать только несколько последних баров.

Большинство индикаторов, в которых используется данный способ оптимизации вычислений, имеют такой вид:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

int start()
{
    //--- иногда для расчета требуется не менее N баров (например, 100)
    // если на графике нет такого количества баров (например, на таймфрейме MN)
    if (Bars<100) {
        return(-1); // прекращаем расчет и выходим досрочно
    }

    //--- количество баров, не изменившихся с момента последнего вызова индикатора
    int counted_bars=IndicatorCounted();
    //--- в случае ошибки выходим
    if (counted_bars<0) {
        return(-1);
    }
    //--- позиция бара, с которого начинается расчет в цикле
    int limit=Bars-counted_bars;

    //--- если counted_bars=0, то начальную позицию в цикле нужно уменьшить на 1,
    if (counted_bars==0) {
        limit--;  // чтобы не выйти за пределы массива при counted_bars==0
        //--- в расчетах используется смещение на 10 баров вглубь 
        //--- истории, поэтому добавим это смещение при первом расчете
        limit-=10;
    } else {
        //--- индикатор уже рассчитывался ранее, counted_bars>0
        //--- при повторных вызовах увеличим limit на 1, чтобы 
        //--- гарантированно обновлять значения индикатора для последнего бара
        limit++;
    }
    //--- основной цикл расчета
    for (int i=limit; i>0; i--) {
        // используются значения баров, уходящих вглубь истории на 5 и 10
        Buff1[i]=0.5*(Open[i+5]+Close[i+10]) 
    }
}

Часто встречается некорректная обработка случая counted_bars==0 (начальную позицию limit нужно уменьшить на значение, равное 1 + максимальный индекс относительно переменной цикла).

Также следует помнить о том, что в момент исполнения функции start() мы можем обращаться к элементам массивов индикаторных буферов от 0 до Bars()-1. Если есть необходимость работы с массивами, которые не являются индикаторными буферами, то их размер следует увеличить при помощи функции ArrayResize() в соответствии с текущим размером индикаторных буферов. Максимальный индекс элемента для адресации также можно получить вызовом ArraySize() с одним из индикаторных буферов в качестве аргумента.

Деление на ноль (Zero divide)

Ошибка “Zero divide” возникает в случае, если при выполнении операции деления делитель оказывается равен нулю:

void OnStart()
{
    int a=0, b=0,c;
    c=a/b;
    Print("c=",c);
}

При выполнении данного скрипта во вкладке “Эксперты” возникает сообщение об ошибке и завершении работы программы:

Обычно такая ошибка возникает в случаях, когда значение делителя определяется значениями каких-либо внешних данных. Например, если анализируются параметры торговли, то величина задействованной маржи оказывается равна 0, если нет открытых ордеров. Другой пример: если анализируемые данные считываются из файла, то в случае его отсутствия нельзя гарантировать корректную работу. По этой причине желательно стараться учитывать подобные случаи и корректно их обрабатывать.

Самый простой способ – проверять делитель перед операцией деления и выводить сообщение о некорректном значении параметра:

void OnStart()
{
    int a=0, b=0,c;
    if (b!=0) {
        c=a/b; Print(c);
    } else {
        Print("Error: b=0"); 
        return; 
    }
}

В результате критической ошибки не возникает, но выводится сообщение о некорректном значении параметра и работа завершается:

Использование 0 вместо NULL для текущего символа

В старой версии компилятора допускалось использование 0 (нуля) в качестве аргумента в функциях, требующих указания финансового инструмента.

Например, значение технического индикатора Moving Average для текущего символа можно было запрашивать следующим образом:

AlligatorJawsBuffer[i]=iMA(0,0,13,8,MODE_SMMA,PRICE_MEDIAN,i);    // неправильно

В новом компиляторе для указания текущего символа нужно явно указывать NULL:

AlligatorJawsBuffer[i]=iMA(NULL,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Кроме того, текущий символ и период графика можно указать при помощи функций Symbol() и Period().

AlligatorJawsBuffer[i]=iMA(Symbol(),Period(),13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Еще лучше, если вы будете использовать предопределенные переменные _Symbol и _Period – они обрабатываются быстрее:

AlligatorJawsBuffer[i]=iMA(_Symbol,_Period,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Строки в формате Unicodе и их использование в DLL

Строки представляют собой последовательность символов Unicode. Следует учитывать этот факт и использовать соответствующие функции Windows. Например, при использовании функций библиотеки wininet.dll вместо InternetOpenA() и InternetOpenUrlA() следует вызывать InternetOpenW() и InternetOpenUrlW(). При передаче строк в DLL следует использовать структуру MqlString:

#pragma pack(push,1)
struct MqlString
{
    int      size;       // 32-битное целое, содержит размер распределенного для строки буфера
    LPWSTR   buffer;     // 32-разрядный адрес буфера, содержащего строку
    int      reserved;   // 32-битное целое, зарезервировано, не использовать
};
#pragma pack(pop,1)

Совместное использование файлов

При открытии файлов необходимо явно указывать флаги FILE_SHARE_WRITE и FILE_SHARE_READ для совместного использования.

В случае их отсутствия, файл будет открыт в монопольном режиме, что не позволит больше никому его открывать, пока он не будет закрыт монополистом.

Например, при работе с оффлайновыми графиками требуется явно указывать флаги совместного доступа:

// 1-st change - add share flags
ExtHandle=FileOpenHistory(c_symbol+i_period+".hst",
    FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);

Особенность преобразования datetime

Следует иметь ввиду, что преобразование типа datetime в строку зависит от режима компиляции:

datetime date=D'2014.03.05 15:46:58';
string str="mydate="+date;
//--- str="mydate=1394034418" - без директивы #property strict
//--- str="mydate=2014.03.05 15:46:58" - с директивой #property strict

Например, попытка работы с файлами, имя которых содержит двоеточие, приведет к ошибке.

Обработка ошибок времени выполнения

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

В наборе “из коробки” доступны некоторые библиотеки для упрощения написания советников, в том числе и для работы с ошибками. Хранятся они в папке MQL4/Include:

Нам понадобятся две библиотеки:

  • stderror.mqh – содержит константы для номера каждой ошибки;
  • stdlib.mqh – содержит несколько вспомогательных функций, в том числе и функцию возврата описания ошибки в виде строки:
string ErrorDescription(int error_code)

Поэтому подключим в наш проект обе эти библиотеки:

#include <stderror.mqh>
#include <stdlib.mqh>

Сами описания ошибок находятся в файле MQL4/Library/stdlib.mql4 и они на английском языке. Поэтому, если вы против иностранных языков, всегда можно переписать описания на свой родной.

Еще одна встроенная необходимая нам функция – GetLastError(). Именно она возвращает коды ошибок в виде целого числа (int), который мы потом будем обрабатывать. Сами коды ошибок и их описания на русском можно посмотреть в руководстве по mql4 от MetaQuotes. Оттуда же можно взять информацию для перевода файла stdlib.mql4 на русский.

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

К сожалению, средствами MQL4 нельзя написать обобщенную библиотеку для обработки всех возможных ошибочных ситуаций. В каждом отдельном случае придется обрабатывать ошибки отдельно. Но не все так плохо, – многие ошибки не нужно обрабатывать, их достаточно исключить на этапе разработки и тестирования эксперта, хотя для этого и нужно вовремя узнать об их наличии.

Рассмотрим для примера две типичные для экспертов на MQL4 ошибки:

  1. Ошибка 130 – ERR_INVALID_STOPS
  2. Ошибка 146 – ERR_TRADE_CONTEXT_BUSY

Одним из случаев, когда возникает первая ошибка, является попытка эксперта выставить отложенный ордер слишком близко к рынку. Ее наличие может серьезно ухудшить показатели эксперта в некоторых случаях. Например, допустим эксперт, открыв прибыльную позицию, поджимает прибыль каждые 150 пунктов. Если при очередной такой попытке возникнет ошибка 130, а цена безвозвратно вернется к предыдущему уровню стопа, эксперт может лишить вас законной прибыли. Несмотря на возможность таких последствий, данную ошибку можно исключить в корне, доработав код эксперта так, чтобы он учитывал минимальное допустимое расстояние между ценой и стопами.

Вторую ошибку, связанную с занятостью торгового контекста терминала, полностью исключить не получится. При работе нескольких экспертов в одном терминале всегда возможна ситуация, когда один из экспертов попытается открыть позицию, пока другой все еще делает то же самое. Следовательно, такую ошибку всегда нужно обрабатывать.

Таким образом, мы всегда должны быть в курсе, если какая-то из используемых встроенных функций возвращает ошибку во время работы эксперта. Добиться этого можно, используя следующую нехитрую вспомогательную функцию:

void logError(string functionName, string msg, int errorCode = -1)
{
    Print("ERROR: in " + functionName + "()");
    Print("ERROR: " + msg );

    int err = GetLastError();

    if (errorCode != -1) {
        err = errorCode;
    }

    if (err != ERR_NO_ERROR) {
        Print("ERROR: code=" + err + " - " + ErrorDescription( err ));
    }
}

Использовать ее мы будем следующим образом:

void openLongTrade()
{
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask + 5, 5, 0, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

Конечно, это упрощенный пример. Для написания более грамотных функций открытия, закрытия и модификации ордеров смотрите этот урок.

Первым параметром в функцию logError() передается имя функции, в которой была обнаружена ошибка, в нашем примере – в функции openLongTrade(). Если наш эксперт вызывает функцию OrderSend() в нескольких местах, это позволит нам точно установить, в каком из них произошла ошибка. Вторым параметром передается описание ошибки, чтобы можно было понять, где именно внутри функции openLongTrade() была обнаружена ошибка. Это может быть как краткое описание ошибки, так и более развернутое, с перечислением значений всех параметров, переданных во встроенную функцию.

Я предпочитаю последний вариант, так как при возникновении ошибки можно сразу получить всю необходимую для анализа информацию. Для примера допустим, что до вызова OrderSend() текущая цена успела сильно отклониться от последней известной нам цены. В результате при выполнении этого примера произойдет ошибка и в протоколе работы эксперта появятся следующие строки:

ERROR: in openLongTrade()
ERROR: could not open order
ERROR: code=138 - requote

То есть сразу будет видно:

  • в какой функции произошла ошибка;
  • к чему она относится (в данном случае – к попытке открыть позицию);
  • какая именно ошибка возникла (код ошибки и ее описание).

Теперь рассмотрим третий, необязательный, параметр функции logError(). Он необходим в тех случаях, когда мы хотим обработать конкретный вид ошибки, а об остальных будем отчитываться в протоколе работы эксперта, как и прежде:

void updateStopLoss(double newStopLoss)
{
    bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), 
        newStopLoss, OrderTakeProfit(), OrderExpiration());
    if (!modified) {
        int errorCode = GetLastError();
        if (errorCode != ERR_NO_RESULT ) {
            logError("updateStopLoss", "failed to modify order", errorCode);
        }
    }
}

Здесь в функции updateStopLoss() вызывается встроенная функция OrderModify(). Эта функция несколько отличается в плане обработки ошибок от OrderSend(). Если ни один из параметров изменяемого ордера не отличается от его текущих параметров, то функция вернет ошибку ERR_NO_RESULT. Если в нашем эксперте такая ситуация допустима, то мы должны игнорировать конкретно эту ошибку. Для этого мы анализируем значение, возвращаемое GetLastError(). Если произошла ошибка с кодом ERR_NO_RESULT, то мы ничего не выводим в протокол.

Однако если произошла другая ошибка, то необходимо полностью отрапортовать о ней, как мы делали это раньше. Именно для этого мы сохраняем результат функции GetLastError() в промежуточной переменной и передаем его третьим параметром в функцию logError(). Дело в том, что встроенная функция GetLastError() автоматически обнуляет код последней ошибки после своего вызова. Если бы мы не передали код ошибки явно в logError(), то в протоколе была бы отражена ошибка с кодом 0 и описанием “no error”.

Похожие действия необходимо совершать и при обработке других ошибок, например, реквотов. Основная идея заключается в том, чтобы обрабатывать только ошибки, требующие обработки, а остальные передавать в функцию logError(). Тогда мы всегда будем в курсе, если во время работы эксперта произошла непредвиденная ошибка. Проанализировав логи, мы сможем решить, требует ли данная ошибка отдельной обработки или же ее можно исключить, доработав код эксперта. Такой подход часто заметно упрощает жизнь и сокращает время, уходящее на борьбу с ошибками.

Диагностика логических ошибок

Логические ошибки в коде эксперта могут доставить много проблем. Отсутствие возможности пошаговой отладки экспертов делают борьбу с такими ошибками не очень приятным занятием. Основным средством для диагностики этого на данный момент является встроенная функция Print(). С ее помощью можно выполнять распечатку текущих значений важных переменных, а также протоколировать ход работы эксперта прямо в терминале во время тестирования. При отладке эксперта во время тестирования с визуализацией также может помочь встроенная функция Comment(), которая выводит сообщения на график. Как правило, убедившись, что эксперт работает не так, как было задумано, приходится добавлять временные вызовы функции Print() и протоколировать внутреннее состояние эксперта в предполагаемых местах возникновения ошибки.

Однако, для обнаружения сложных ошибочных ситуаций порой приходится добавлять десятки таких вызовов функции Print(), а после обнаружения и устранения проблемы их приходится удалять или комментировать, чтобы не загромождался код эксперта и не замедлялось его тестирование. Ситуация ухудшается, если в коде эксперта функция Print() уже используется для периодического протоколирования различных состояний. Тогда удаление временных вызовов Print() не удается выполнить путем простого поиска фразы ‘Print’ в коде эксперта. Приходится задумываться, чтобы не удалить еще и полезные вызовы этой функции.

Например, при протоколировании ошибок функций OrderSend(), OrderModify() и OrderClose() полезным бывает печатать в протокол текущее значение переменных Bid и Ask. Это несколько облегчает распознавание причин таких ошибок, как ERR_INVALID_STOPS и ERR_OFF_QUOTES.

Чтобы выделить такие диагностические выводы в протокол, я рекомендую использовать такую вспомогательную функцию:

void logInfo(string msg)
{
    Print("INFO: " + msg);
}

Это желательно сделать по нескольким причинам. Во-первых, теперь такие вызовы не будут попадаться при поиске ‘Print’ в коде эксперта, ведь искать мы будем logInfo. Во-вторых, у этой функции есть еще одна полезная особенность, о которой мы поговорим чуть позже.

Добавление и удаление временных диагностических вызовов функции Print() отнимает у нас драгоценное время. Поэтому я предлагаю рассмотреть еще один подход, который эффективен при обнаружении логических ошибок в коде и позволяет немного сэкономить наше время. Рассмотрим следующую несложную функцию:

void openLongTrade(double stopLoss)
{
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

В данном случае, так как мы открываем длинную позицию, совершенно очевидно, что при нормальной работе эксперта значение параметра stopLoss никогда не будет больше или равно текущей цене Bid. То есть, при вызове функции openLongTrade() всегда выполняется условие stopLoss < Bid. Так как мы знаем об этом еще на этапе написания рассматриваемой функции, то мы сразу же можем этим воспользоваться следующим образом:

void openLongTrade( double stopLoss )
{
    assert("openLongTrade", stopLoss < Bid, "stopLoss < Bid");
 
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

То есть мы логируем наше утверждение в коде при помощи новой вспомогательной функции assert(). Сама функция выглядит довольно просто:

void assert(string functionName, bool assertion, string description = "")
{
    if (!assertion) {
        Print("ASSERT: in " + functionName + "() - " + description);
    }
}

Первым параметром функции является ее имя, в котором проверяется наше условие (по аналогии с функцией logError()). Вторым параметром передается результат проверки этого условия. И третьим параметром передается его описание. В результате, если ожидаемое условие не выполняется, в протокол будет выведена следующая информация:

  • название функции, в которой условие было нарушено;
  • описание нарушенного условия.

В качестве описания можно передавать, например, само условие, а можно выводить и более подробное описание, содержащее значения контролируемых переменных на момент проверки условия, если это поможет разобраться в причинах ошибки.

Конечно же, рассмотренный пример максимально упрощен. Но, надеюсь, основную идею отражает достаточно хорошо. В процессе наращивания функциональности эксперта мы отдаем себе отчет в том, как он должен работать и какие состояния и входные параметры функций допустимы, а какие нет. Фиксируя это в коде эксперта при помощи функции assert() мы получаем ценную информацию о месте, в котором нарушается логика работы эксперта. Более того, мы частично избавляем себя от необходимости добавлять и удалять временные вызовы функции Print(), так как функция assert() выдает диагностические сообщения в протокол только в момент обнаружения несоответствий в ожидаемых нами условиях.

Еще одним полезным приемом является использование этой функции перед каждой операцией деления. Дело в том, что иногда в результате той или иной логической ошибки иногда происходит деление на ноль. Работа эксперта в этом случае прекращается, а в протоколе появляется одна лишь строка с печальным диагнозом: ‘zero divide’. Узнать, в каком именно месте произошла эта ошибка, если операция деления используется в коде неоднократно, достаточно сложно. Вот здесь и поможет функция assert(). Вставляем соответствующие проверки перед каждой операцией деления:

assert("buildChannel", distance > 0, "distance > 0");
double slope = delta / distance;

И теперь, в случае деления на ноль, достаточно будет лишь взглянуть в логи, чтобы узнать, в каком именно месте произошла ошибка.

Обработка состояний

Во время работы эксперта на вашем счете могут возникнуть некоторые ситуации, которые не являются ошибками – так называемые состояния эксперта. Такие состояния не являются ошибками, но все же их стоит логировать. В этом помогают специальные функции языка mql4.

Функция IsExpertEnabled() возвращает информацию о возможности запуска экспертов. Функция вернет true, если в клиентском терминале разрешен запуск экспертов, иначе возвращает false. В случае возврата false полезно будет известить об этом пользователя с просьбой включить соответствующую настройку. Пример:

void OnStart()
{
    if (!IsExpertEnabled() {
        //советникам не разрешено торговать
        Alert("Attention! Please press the "Expert Advisors" button in MT4");
    }
    //рабочий алгоритм советника
    return;
}

Если эксперт использует внешние библиотеки, пригодится функция IsLibrariesAllowed(). Она возвращает true, если эксперт может вызвать библиотечную функцию, иначе возвращает false.

Если библиотека в виде dll файла, пригодится функция IsDllsAllowed(). Также нелишним будет проверить, есть ли вообще возможность торговать при помощи экспертов с помощью функции IsTradeAllowed().

Если вы хотите узнать, является ли счет демонстрационным, или же реальным, можно использовать функцию IsDemo().

Все вышеперечисленные проверки стоит сделать в функции OnInit().

Конечно же, стоит проверять периодически связь с сервером. В этом поможет функция IsConnected().

Следующие три функции помогут определить, в каком режиме находится советник. Если IsOptimisation() возвращает true, проводится оптимизация, если IsTesting(), то тестирование, IsVisualMode() – тестирование в режиме визуализации. Под каждый из этих вариантов в советнике может быть предусмотрена своя логика. Например, для режима визуализации можно что-то выводить на график (и не выводить в других режимах ради экономии ресурсов). В режиме тестирования можно выводить отладочную информацию, в режиме оптимизации максимально облегчить код, чтобы сэкономить время.

И последняя функция – IsTradeContextBusy(). Она вернет true, если поток для выполнения торговых операций занят. Это бывает полезно при совершении экспертом торговых операций. Можно применить функцию Sleep для ожидания некоторого момента и новой попытки.

Еще одна полезная функция – UninitializeReason()

int deinit()
{
    switch(UninitializeReason())
    {
        case REASON_CHARTCLOSE:
        case REASON_REMOVE:      
            CleanUp(); 
            break;    // очистка и освобождение ресурсов.
        case REASON_RECOMPILE:
        case REASON_CHARTCHANGE:
        case REASON_PARAMETERS:
        case REASON_ACCOUNT:     
            StoreData(); 
            break;  // подготовка к рестарту.
    }
    //...
}

Можно также логировать причину выхода советника.

Коды самых распространенных ошибок и их вероятное решение

№ ошибки Значение Проблема Решение
4, 146 Торговый сервер занят Советник подал слишком много приказов одновременно или не дождавшись ответа от сервера, при выполнении операции – советник пытается отправить новый приказ Перезагрузка терминала или оптимизация кода советника с помощью функций обработки ошибок
8, 141 Слишком частые запросы Предыдущие причины ошибки, в сильно частом запросе Аналогичное решение
129 Неправильная цена Цена по которой Вы пытаетесь открыть позицию (BUY или SELL) неправильная BUY нужно открывать по Ask а закрывать по BID;
SELL нужно открывать по BID а закрывать по ASK
130, 145 Неправильные стопы Стоп лосс, тейк профит или уровень открытия отложки или лимитника неверные.
Стопы расположены слишком близко к цене.
Ваш счет открыт в группе ECN (ЕЦН) или NDD (НДД), что не дает сразу выставлять стопы
Проверьте значения Ваших стоп лоссов, тейк профитов, уточните минимальный стоп уровень по Вашему инструменту у брокера, при выставлении стопов – соблюдайте уровень минимальной дистанции. В хорошо написанном советнике должны быть функции работы на счетах ECN и NDD – это происходит путем модификации ордера уже после его открытия
131 Неправильный объем Неправильный лот при открытии сделки, или меньше минимального (больше максимального). Разрядность лота тоже может отличаться от разрядности брокера Проверьте правильность открытия лота, изучите спецификацию контракта и прочтите условия торговли в Вашем ДЦ, проверьте минимальный и максимальный лот в Вашем ДЦ и на Вашем счете
132 Рынок закрыт Рынок закрыт на выходные дни Пробуйте связаться с рынком после выходных
133 Торговля запрещена В данный момент торговля запрещена По данной валютной паре запрещено торговать – в конкретный момент времени или вообще. Часто у брокеров есть перерыв в несколько минут в полночь
134 Недостаточно денег для совершения операции Лот, который Вы пытаетесь открыть, слишком большой, на него не хватает маржи Проверьте уровень свободных средств и рассчитайте средства, которые Вам нужны для открытия лота, следите за уровнем Ваших свободных средств
135-138 Цена изменилась Реквот, слишком быстрый рынок (новости), Брокер или ДЦ не дает Вам поставить позицию по заявленной цене Не торгуйте в такие моменты, увеличьте уровень проскальзывания, но помните, что это влечет за собой открытие позиций не по заявленной Вами цене. Предусмотрите в советнике функцию обработки ошибок и количество попыток открытия позиций
147 Использование даты истечения ордера запрещено брокером Ваш советник или Вы пытаетесь установить срок истечения отложенного ордера В советнике, в функции OrderSend в параметре срок истечения поставьте 0 (ноль). Не устанавливайте срок истечения ордера
148 Количество открытых и отложенных ордеров достигло предела, установленного брокером Максимальное количество открытых ордеров и позиций достигло предела, установленного брокером Удалите или закройте часть позиций. Остановите процесс открытия новых позиций
4012, 4013 Остаток от деления на ноль Вы пытаетесь поделить число на 0 (ноль) Проверьте код советника на наличие ошибки, или же проверьте все значения из MarketInfo функций на момент возвращения 0, иногда при MarketInfo(Symbol(),MODE_SPREAD) возвращается не спред, а 0 (у брокеров с плавающим спредом)
4017 Вызовы DLL не разрешены В Вашем терминале запрещен вызов DLL Разрешите вызов DLL через Меню – сервис – Настройки – Советник – Разрешить вызов DLL
4018, 4019 Невозможно загрузить библиотеку Библиотека повреждена или ее вызов завершается с ошибкой, возможно она вообще отсутствует Проверьте библиотеку DLL
4020 Вызовы внешних библиотечных функций не разрешены В Вашем терминале запрещен вызов функций из внешних экспертов Разрешите вызов функций через Меню – сервис – Настройки – Советник – Разрешить вызов внешних экспертов
4103 Невозможно открыть файл Данный файл не существует или заблокирован другим процессом Проверьте наличие указанного файла. Проверьте, не заблокирован ли файл системой антивируса, разрешен ли режим записи-чтения файла
4106 Неизвестный символ Символа нет в обзоре рынка В обзоре рынка – правой кнопкой мыши – показать все символы. Проверить названия символа в советнике и наличие его в обзоре рынка. Некоторые советники используют четкие названия без суффиксов, а брокеры намеренно ставят суффиксы, например EURUSDx где х – суффикс
4108 Неверный номер тикета Тикет ордера, который выбирает эксперт – не существует. Эксперт пытается выбрать тикет, но данный ордер был закрыт другим советником или руками. При попытке осуществления приказа над ордером, тикет был исполнен и закрыт брокером Если данная ошибка появляется очень часто, 100-1000 раз за минуту, проверьте функции Вашего советника. Отключите другие советники или настройте их так, чтобы они не конфликтовали, не закрывайте ордер руками, когда эксперт выполняет операцию. Иногда такое случается, когда несколько советников используют одинаковый MagicNumber
4109 Торговля не разрешена Советнику запрещено торговать, на графике грустный смайл или крестик Включите галочку «Разрешить советнику торговать» во вкладе при установке советника, либо в меню – сервис – настройки – советники
4110, 4111 Длинные/короткие позиции не разрешены В настройках советника, во вкладке Общие не разрешен тип позиций Во вкладке Общие, при установке советника, есть выбор позиций, разрешенных к открытию

Заключение

Рассмотренные вспомогательные функции и несложные приемы позволяют заметно упростить и ускорить процесс обнаружения и исправления ошибок в коде торговых экспертов, написанных на языке программирования MQL4. Грамотное написание кода и функций для логирования и сопровождения работы советника существенно ускоряют процесс его разработки.

Тема на форуме

С уважением, Дмитрий аkа Silentspec
TradeLikeaPro.ru

Дообрый день! Имеется следующий код

#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <conio.h>

using namespace std;

double count(double, double, double, double);
void input(void);
void output(void);

int main()
{
	double a, b, c, d, y;

	input();
	y = count(a, b, c, d);
	output();

	double count (double a, double b, double c, double d) {
		return 2 * sqrt((sin(a) / fabs(tan(b - a)) + (log(c) / d)));
	}

	void input(void) {
		cout << "Enter a" << endl;
		cin >> a;
		cout << "Enter b" << endl;
		cin >> b;
		cout << "Enter c" << endl;
		cin >> c;
		cout << "Enter d" << endl;
		cin >> d;
	}

	void output(void) {
		cout << "Your y is " << y;
	}

	_getch();

	return 0;
}

При компиляции выскакивают ошибки:

Error C4700 uninitialized local variable ‘a’ used
Error C4700 uninitialized local variable ‘b’ used
Error C4700 uninitialized local variable ‘c’ used
Error C4700 uninitialized local variable ‘d’ used

Прдскажите, пожалуйста, в чем проблема.. не могу понять.. переменные же вроде инициализировала еще в самом начале функции main()

33 replies

When will be new version Mark? If You are talking about SQ4 then sometimes I even doubt in it’s existency! 😉 we talked last time that SQ4 should be at december 2014. We have July of 2015 😉 can You fix it in existing sq3?

btn_viewmy_160x33.png

It would be great to see another SQ3 release with the code fixed and a handful of other known bugs fixed.

@Mark – If we collected together a list of high priority known bugs, could you produce another SQ3 release with these in to tide us over until SQ4 is ready?

TIA

Mike

Mike, I’ll surely  consider it.

Please compile a list of bugs you think are high priority and should be fixed in the current version 3.

The best is to contact me by private message on forum or by support email then, so I’ll not miss it here on forum. 

Mark
StrategyQuant architect

The best is to contact me by private message on forum 

Really? 🙂

btn_viewmy_160x33.png

sorry, I didn’t know about this.

what issue is there with compiler exactly? it works fine for MT4.

code generator for MT5 will be only in the new version, it is quite a lot of work to do it twice.

Mark
StrategyQuant architect

Hard to say. Mql says only that it isnt done with compile strict. Please follow the website that I mentioned. Maybe it will help to solve the problem.

btn_viewmy_160x33.png

Any update on this, Mark?

btn_viewmy_160x33.png

Mike, I’ll surely  consider it.

Please compile a list of bugs you think are high priority and should be fixed in the current version 3.

The best is to contact me by private message on forum or by support email then, so I’ll not miss it here on forum. 

Hi Mark,

I am going to compile a list of bugs and issues I think would be simple to change for a final SQ3 release.  I wil then post it on the forum and send it to you. 

Many thanks,

Mike

Here’s some issues I think should be fixed and go into final SQ3 release.

I just want to let you know that we just released an autoupdate that fixes this. Your SQ should be updated next time you start it.

So ti is now possible to add #property strict to your EA and it will compile correctly.

Mark
StrategyQuant architect

Ok, I have updated SQ but I see no option to add #property strict.

Where can I find it?

btn_viewmy_160x33.png

there is no setting for it in SQ, what was changed was that SQ now generates code that can be compiled with #property strict.

You can add the line:

#property strict

to the beginning of generated EA file.

Mark
StrategyQuant architect

Will it work even if I load “old” strategies files and export again in mql?

btn_viewmy_160x33.png

yes, you can alway re-export old strategies in SQ and they should work as before.

MQL code was just cleaned up so that there are no errors when compiled with #property strict

Mark
StrategyQuant architect

#property strict in actual version SQ 3.8.1 is not. If I add line #property strict and compile to ex4 returns this errors. I instaled lasted SQ 3.8.1 and patches from august and september.

‘EURUSD_15M_21.320229.mq4    EURUSD_15M_21.320229.mq4    1    1
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    562    83
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    562    111
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    605    70
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    607    71
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    630    38
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    630    61
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    630    83
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    630    99
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    635    35
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    640    26
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    640    55
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    653    39
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    653    57
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    653    77
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    655    24
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    655    57
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    655    94
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    658    40
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    658    54
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    672    39
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    672    61
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    672    94
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    672    131
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    676    39
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    676    77
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    676    91
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    684    55
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    687    46
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    687    60
‘i’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1048    8
‘i’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1064    8
‘i’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1091    8
‘i’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1107    8
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1223    19
‘i’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1304    8
‘orderTime’ – undeclared identifier    EURUSD_15M_21.320229.mq4    1306    10
implicit conversion from ‘string’ to ‘number    EURUSD_15M_21.320229.mq4    1306    20
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1308    13
possible use of uninitialized variable ‘lotMM    EURUSD_15M_21.320229.mq4    1380    15
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1788    19
possible loss of data due to type conversion    EURUSD_15M_21.320229.mq4    1802    30
possible loss of data due to type conversion    EURUSD_15M_21.320229.mq4    1813    22
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1815    56
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1851    60
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    1851    87
possible loss of data due to type conversion    EURUSD_15M_21.320229.mq4    2117    11
implicit conversion from ‘number’ to ‘string    EURUSD_15M_21.320229.mq4    2118    17
possible loss of data due to type conversion    EURUSD_15M_21.320229.mq4    2140    65
possible loss of data due to type conversion    EURUSD_15M_21.320229.mq4    2141    70
6 error(s), 43 warning(s)        7    44
 

You must be logged in to reply to this topic.

Sign in

The analyzer has detected use of an uninitialized variable. Using uninitialized variables has unpredictable results. What is dangerous about such defects is that they may hide for years until chance gets suitable values gathered in uninitialized variables.

Consider the following simple example:

int Aa = Get();
int Ab;
if (Ab) // Ab - uninitialized variable
  Ab = Foo();
else
  Ab = 0;

Whether or not the Foo() function is called depends on a combination of various circumstances. Usually errors of using uninitialized variables occur through misprints. For example, it may appear that a different variable should be used in this place. This is the correct code:

int Aa = Get();
int Ab;
if (Aa) // OK
  Ab = Foo();
else
  Ab = 0;

It is not only using simple types that the V614 warning is generated. The analyzer may show the warning for variables of the class type which have a constructor and are initialized, as a matter of fact. However, using them without preliminary assignment doesn’t have sense. Smart pointers and iterators are examples of such classes.

Have a look at the following samples:

std::auto_ptr<CLASS> ptr;
UsePtr(ptr);

std::list<T>::iterator it;
*it = X;

This is the correct code:

std::auto_ptr<CLASS> ptr(Get());
UsePtr(ptr);

std::list<T>::iterator it;
it = Get();
*it = X;

It happens that the analyzer generates false V614 warnings. But sometimes it happens through the fault of programmers themselves who write tricky code. Have a look at a code sample taken from a real application:

virtual size_t _fread(const void *ptr, size_t bytes){
  size_t ret = ::fread((void*)ptr, 1, bytes, fp);
  if(ret < bytes)
    failbit = true;
  return ret;
}

int read32le(uint32 *Bufo, EMUFILE *fp)
{
  uint32 buf;
  if(fp->_fread(&buf,4)<4)   //  False alarm: V614
    return 0;
  ....
}

Note that the buffer reading the data from the file is declared as «const void *ptr». For the code to compile, the programmer uses an explicit conversion of the pointer to the type «(void*)». We don’t know what made the programmer write this code. The meaningless «const» qualifier confuses the analyzer: it thinks that the _fread() function will use the ‘buf’ variable only for reading. Since the ‘buf’ variable is not initialized, the analyzer generates the warning.

The code works, but it cannot be called smart. It should be rewritten: first, it will become shorter and clearer; second, it will stop triggering the V614 warning.

This is the fixed code:

virtual size_t _fread(void *ptr, size_t bytes){
  size_t ret = ::fread(ptr, 1, bytes, fp);
  if(ret < bytes)
    failbit = true;
  return ret;
}

There’s another situation where V614 may look like a false alarm. Look at the following synthetic example:

std::shared_ptr<foo> GetFoo()
{
  std::shared_ptr<foo> Bar;
  return Bar;                        // V614
}

In this code fragment, the ‘Bar’ smart pointer of the ‘std::shared_ptr’ type is created. The default constructor is called for this smart pointer. Thus, ‘Bar’ is always initialized with ‘nullptr’. The analyzer considers it dangerous to use smart pointers created by the default constructor. Still, we can write the code this way. There are several ways to suppress such analyzer warnings.

We can fix the code like this:

std::shared_ptr<foo> GetFoo()
{
  std::shared_ptr<foo> Bar { nullptr };
  return Bar;                           // no V614
}

This code fragment is more readable. We see that the ‘GetFoo’ function returns an object of the ‘std::shared_ptr’ type, which contains a null pointer. In this case, a reviewer will expect the ‘GetFoo’ function to return the null pointer. This code fragment also gives a sign to the analyzer that everything’s fine, and the null pointer is returned deliberately.

However, if the analyzer issues a lot of such warnings on the code and you don’t want to see them, you can use the following comment:

//-V614_IGNORE_SMART_POINTERS

This comment should be written to the header file included in all other files. For example, «stdafx.h» can be such a file. If you write this comment to the «*.c» or «*.cpp» file, the comment will apply only to this file.

Otherwise, you can suppress false positive warnings.

This diagnostic is classified as:

  • CWE-457
  • CWE-824
  • CERT-EXP33-C
  • CERT-EXP53-CPP

Everyone has to go through same process

Please understand: MetaQuotes has changed almost everything in MQL. They have tried to make MQL compatible with old versions but there are still points they did not make compatible intentionally. We host thousands of source code from clients and i would like to introduce you to common compiler problems in new Metatrader Builds. This may help you to adapt your code. This page will be updated continiously, plesae check this page regularly and post it to your friends.

Variable Names does not allow special characters and points

Statement from MetaQuotes about this subject is clear: “Now, variable names cannot contain special characters and points, and new MQL4 language keywords cannot be used as names. Old MQL4 programs can be recompiled with the new compiler in order to easily correct all such errors while following the compiler’s messages.” We see many such errors, fixing this kind of error is pretty easy. You open your source in MetaEditor and start replacing all variable names with specialchars (this also includes point) with names without specialchars. This is very easy and common compiler error in new builds. Compiler may throw “semicolor expected” error by this problem.

System Functions cannot be overwritten

New compiler is protecting System Functions. As example: if you had a function called “string StringReplace” in your code and Metatrader has introduced new function (they have introduced many new functions) with same name, this will collide and you will see error “override system function” in your compiler.

Cross References

int pos2 = pos2; This was possible in previous compiler now you will get “undeclared identifier”. New compiler is more strict but this was bad coding style anyways, so its good you fix such problems in your code. New compiler will throw error anyways. There is no way to ignore this error.

event handling function not found

This may have several reasons. Make sure you have read this page first to understand about event handling functions. They are basically start(), init(), deinit(), OnStart(), OnInit(), OnDeinit(), OnTick(), OnTrade() etc… Make sure you have at least OnInit() or init() and start() or OnStart() functions defined in your source code. If this does not solve your problem we have discovered strange behaviour in new compiler. Simply remove the start() or/and init() line in MetaEditor and type it once again and try to compile again. This is usually working and probably a bug on compiler. For Video Demonstratino check: Watch Video

Expressions are not allowed on a global scope

Normally every expression must be inside a function and out ouf functions you can only define new variables and define compiler settings. If you get this error make sure and find any expression outside of function. Here is very good example:

Fixing this error is easy as well, simply locate such lines and make sure you put them inside proper event function such as OnInit or OnStart. Of course you must know what you are doing to decide where it should be placed

Invalid index value

double Spread[0]; This is not allowed anymore. Arrays with 0 size does not exist. Its better you simply remove [0] tag if you dont use ArrayResize later. If you are using ArrayResize later start with a start index like “[10]” instead of “[0]”. You may also try to put “[1]” to fix this error. But depending on intention it may vary how to fix this error. You may also get “array required” error if you remove [0] index. This means that your source code requires an error. Try to put [10] for example.

Reserved words cannot be used as Variable Name

If you get “unexpected token” you may be using a reserved word as variable name:


bool long=false;

bool short=false;

As you know new compiler now supports new variable types long and short. These are reserved keywords for mql and they cannot be used in variable names anymore. There are dozenz of other keywords they have been introduced in new mql compiler. Make sure you change variable names simply. For example append an understore to fix this problem, of course you must change whole source code with this variable name, otherwise you will get big gargabe. This error may also throw “name expected” error in combination.

“comma expected” but problem somewhere else

If you have a code like this:


#property link "http://www.fx1.net"

#define link "http://www.metaquotes.net/"

Compiler shows you the error somewhere random! If you dobule click to compiler error, it brings you to nirvana. This is obviously a bug inside Compiler. This is caused by using “link” property also inside #define. There are many predefined properties. Finding this error is not very easy. Check all your #define lines if they contain any reserved property keyword!

Switch needs type of integer


Previous MQL compiler did not throw any error here but its different now. Try to fix this error by rewriting and re-thinking your algoritm. Non-integer values cannot be compared well without loosing precission, thats why MQL requires integer values. This is industry standard for switch expression. Please adapt your code regarding that.

Case value already used


case 1: Ls_4 = "no error"; break;

case 1: Ls_4 = "no error and no result"; break;

This is now allowed anymore. Please resolve this conflict. New switch cannot manage such a conflict and throws “case value already used” error

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Pos tempered ошибка терминала
  • Porte avg ouverte ошибка пежо 307