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

Автор: lexy Вторник, Сентябрь 9th, 2014 Нет комментариев

Рубрика: Разное

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

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

Концепция

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

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

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

Алгоритм поиска ошибок

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

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

 

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

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

Пример

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

#property copyright ""
#property link      ""

extern int Level1=6;
extern int Level2=2;

extern double Lots=0.1;
extern int TP=7;
extern int SL=5000;
extern int Profit_stop=10;

int start()
  {
//+-----------------------------------------------------------------------------------------------------------+
//|                                        поиск открытых ордеров по паре                                     |
   int pos_sell=0;
 for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--)
 {
  if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break;
  if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL)&&(OrderComment()=="sar_ao"))
  {
   pos_sell=1;  break;  
  }
 }

   int pos_buy=0;
 for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--)
 {
  if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break;
  if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY)&&(OrderComment()=="sar_ao"))
  {
   pos_buy=1;  break;  
  }
 }

//|                                        поиск открытых ордеров по паре                                     |
//+-----------------------------------------------------------------------------------------------------------+  

//+-----------------------------------------------------------------------------------------------------------+
//|                                                стоп в безубыток                                           |
  double stop_open;
  for (int ia=OrdersTotal()-1; ia>=0; ia--)
  {
   if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break;
   if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao"))
   {
    stop_open=OrderOpenPrice();
    if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue;
    OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(),OrderExpiration(),CLR_NONE);  
   }
 if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao"))
   {
    stop_open=OrderOpenPrice();
    if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue;
    OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(),OrderExpiration(),CLR_NONE);      
   }
  }  
//|                                                стоп в безубыток                                           |
//+-----------------------------------------------------------------------------------------------------------+
   int i;  
   bool trend_UP=true,trend_DOWN=true;  
//+-------------------------------------------------------------------------------  
if(!pos_buy)
 {  
  for(i=Level1; i>=0; i--)
   {

    if(Open[i]<iSAR(NULL,0,0.02,0.1,i))
    {
     trend_UP=false; break;
    }

   }

   for(i=Level2*2; i>=0; i--)
   {    

    if(i>Level2)
    {
     if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i))    
     {
      trend_UP=false; break;
     }
    }

    if(i<Level2)
    {
     if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i))  
     {  
      trend_UP=false; break;
     }
    }          

   }
 }
 else
 {
  trend_UP=false;
 }
//***************************************************************************
if(!pos_sell)
 {
   for(i=Level1; i>=0; i--)
  {
   {
    if(Open[i]>iSAR(NULL,0,0.02,0.1,i))
    {
     trend_DOWN=false; break;
    }

   }

   for(i=Level2*2; i>=0; i--)
   { 

    if(i>Level2)
    {
     if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i))  
     {  
      trend_DOWN=false; break;
     }  
    }

    if(i<Level2)
    {
     if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i))    
     {
      trend_DOWN=false; break;
     }
    } 

   }

 }
  else
 {
  trend_DOWN=false;
 }  

  if(Open[0]>iSAR(NULL,0,0.02,0.2,0))
  {
    ObjectDelete("sell");
  }

  if(Open[0]<iSAR(NULL,0,0.02,0.2,0))
  {
    ObjectDelete("buy");
  } 

double MA_1;
MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0);  
   if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0)
   {  
     OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); 

     ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid);
     ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT);
     ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP);
     ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen);
   }

   if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0)
   {  
      OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red);   

      ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid);
      ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT);
      ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN);
      ObjectSet("sell", OBJPROP_COLOR, Red);  
   }

//+-------------------------------------------------------------------------------
//----
   return(0);
  }
//+------------------------------------------------------------------+

 

При попытке его компиляции мы видим сообщение об ошибке:

 

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

#property copyright ""
#property link      ""

extern int Level1=6;
extern int Level2=2;

extern double Lots=0.1;
extern int TP=7;
extern int SL=5000;
extern int Profit_stop=10;

int start()
  {
  /*
//+-----------------------------------------------------------------------------------------------------------+
//|                                        поиск открытых ордеров по паре                                     |
   int pos_sell=0;
 for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--)
 {
  if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break;
  if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL)&&(OrderComment()=="sar_ao"))
  {
   pos_sell=1;  break;  
  }
 }

   int pos_buy=0;
 for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--)
 {
  if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break;
  if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY)&&(OrderComment()=="sar_ao"))
  {
   pos_buy=1;  break;  
  }
 }

//|                                        поиск открытых ордеров по паре                                     |
//+-----------------------------------------------------------------------------------------------------------+  
*/

/*
//+-----------------------------------------------------------------------------------------------------------+
//|                                                стоп в безубыток                                           |
  double stop_open;
  for (int ia=OrdersTotal()-1; ia>=0; ia--)
  {
   if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break;
   if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao"))
   {
    stop_open=OrderOpenPrice();
    if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue;
    OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(),OrderExpiration(),CLR_NONE);  
   }
 if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao"))
   {
    stop_open=OrderOpenPrice();
    if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue;
    OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(),OrderExpiration(),CLR_NONE);      
   }
  }  
//|                                                стоп в безубыток                                           |
//+-----------------------------------------------------------------------------------------------------------+
*/

/*
   int i;  
   bool trend_UP=true,trend_DOWN=true;  
//+-------------------------------------------------------------------------------  
if(!pos_buy)
 {  
  for(i=Level1; i>=0; i--)
   {

    if(Open[i]<iSAR(NULL,0,0.02,0.1,i))
    {
     trend_UP=false; break;
    }

   }

   for(i=Level2*2; i>=0; i--)
   {    

    if(i>Level2)
    {
     if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i))    
     {
      trend_UP=false; break;
     }
    }

    if(i<Level2)
    {
     if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i))  
     {  
      trend_UP=false; break;
     }
    }          

   }
 }
 else
 {
  trend_UP=false;
 }
 */
//***************************************************************************

/*
if(!pos_sell)
 {
   for(i=Level1; i>=0; i--)
  {
   {
    if(Open[i]>iSAR(NULL,0,0.02,0.1,i))
    {
     trend_DOWN=false; break;
    }

   }

   for(i=Level2*2; i>=0; i--)
   { 

    if(i>Level2)
    {
     if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i))  
     {  
      trend_DOWN=false; break;
     }  
    }

    if(i<Level2)
    {
     if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i))    
     {
      trend_DOWN=false; break;
     }
    } 

   }

 }
  else
 {
  trend_DOWN=false;
 }  

 */

 /*
  if(Open[0]>iSAR(NULL,0,0.02,0.2,0))
  {
    ObjectDelete("sell");
  }

  if(Open[0]<iSAR(NULL,0,0.02,0.2,0))
  {
    ObjectDelete("buy");
  }
  */
double MA_1;
MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); 

/*
   if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0)
   {  
     OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); 

     ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid);
     ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT);
     ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP);
     ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen);
   }
  */

  /*
   if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0)
   {  
      OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red);   

      ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid);
      ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT);
      ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN);
      ObjectSet("sell", OBJPROP_COLOR, Red);  
   }

*/
//+-------------------------------------------------------------------------------
//----
   return(0);
  }
//+------------------------------------------------------------------+

Легко можно убедиться, что такой код компилируется без проблем. Значит, участок кода, где допущена ошибка «скрыт». По очереди открываем участки кода /* … */, пытаемся откомпилировать.

Компиляция будет происходить благополучно, пока мы не дойдём до участка кода:

//***************************************************************************

if(!pos_sell)
 {
   for(i=Level1; i>=0; i--)
  {
   {
    if(Open[i]>iSAR(NULL,0,0.02,0.1,i))
    {
     trend_DOWN=false; break;
    }

   }

   for(i=Level2*2; i>=0; i--)
   { 

    if(i>Level2)
    {
     if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i))  
     {  
      trend_DOWN=false; break;
     }  
    }

    if(i<Level2)
    {
     if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i))    
     {
      trend_DOWN=false; break;
     }
    } 

   }

 }
  else
 {
  trend_DOWN=false;
 }

Следовательно, ошибка именно в этой логической конструкции. При детальном «осмотре» данного участка кода, можно увидеть, что поставлена лишняя фигурная скобка в данной конструкции:

 

   for(i=Level1; i>=0; i--)
  {
   {
    if(Open[i]>iSAR(NULL,0,0.02,0.1,i))
    {
     trend_DOWN=false; break;
    }

   }

 

Если убрать её, код благополучно откомпилируется.

Убрав оставшиеся комментарии, мы убедимся в том, что других ошибок в коде нет. Значит, цель достигнута — ошибка в коде была найдена достаточно оперативно.

 

Заключение

На практическом примере было показано, как именно используется данный алгоритм поиска ошибок. В данном примере используется весьма немаленький код (194 строки), и на его «обход» могло бы уйти достаточно много времени. Именно возможность комментирования экономит достаточно много времени у многих программистов, которые сталкиваются с задачей поиска ошибок.

 

Источник: mql4.com

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты