English Русский 中文 Deutsch 日本語 Português
Método para encontrar los errores en el código mediante comentarios

Método para encontrar los errores en el código mediante comentarios

MetaTrader 4Ejemplos | 20 abril 2016, 15:27
1 303 0
Eryomin Sergey
Eryomin Sergey

Introducción

Este artículo describe un algoritmo simple de búsqueda de errores en un código MQL. El problema durante la compilación debido a los errores en el código suelen producirse después de escribir un programa. Estos pueden ser todo tipo de errores, pero en cualquier caso es necesario reconocer rápidamente el bloque de código donde se ha cometido el error.

En la mayoría de casos, la gente dedica mucho tiempo y nervios a la búsqueda de algún corchete extraño. No obstante, hay un método para la localización rápida de errores que se basa en el uso de los comentarios. Por ello este es el método del que voy a hablar en este artículo.

El concepto

Escribir un código extenso sin errores es bastante placentero. Pero por desgracia esto no siempre ocurre. Hay incluso una broma según la cual no hay programas escritos sin errores. No voy a tener en cuenta los errores llevan a una ejecución incorrecta del código. Aquí la cuestión se centra en los errores que hacen que la compilación sea imposible.

Los errores más habituales son: insertar corchetes extraños en una condición compleja, falta de un corchete, no poner dos puntos, una coma (durante la declaración de las variables), etc. A menudo, podemos ver qué entrada contiene el error durante la compilación inmediatamente. Pero hay casos en los que encontrar este tipo de errores no es tan fácil. Ni el compilador ni un ojo avezado pueden ayudarnos a encontrar el error de inmediato. En este caso, los programadores novatos (y los que no lo son), por lo general, comienzan a revisar el código intentando detectar el error visualmente. Una y otra vez hasta que pierden los nervios y dicen: "¡Es más fácil escribirlo de nuevo!"

Sin embargo, MQL, al igual que otros lenguajes de programación, ofrece una increíble herramienta: los comentarios. Podemos "eliminar" y "deshabilitar" algunas partes del código usándolos. Normalmente, los comentarios se usan para insertar notas, a saber, o para deshabilitar las partes no usadas del código. El comentario puede usarse también con éxito para la búsqueda de errores.

Algoritmo de búsqueda de errores

La búsqueda de errores consiste por lo general en encontrar la parte del código donde se ha producido un error y luego este se busca visualmente. Creo que nadie dudará que es mucho más fácil y rápido examinar 5 a 10 entradas de código "a ojo" que 100 a 150 entradas.

El problema parece resolverse fácilmente cuando se usan los comentarios. En primer lugar, es necesario comentar distintas partes del código (algunas veces casi todo el código) "deshabilitándola", en consecuencia. Y luego se elimina el comentario de esta parte del código. Después de eliminar regularmente el comentario se realiza un intento de compilar el código. Si la compilación tiene éxito, el error no está en esa parte del código. Después de esto, se abre la siguiente parte del código y así sucesivamente. Cuando se encuentra la parte problemática del código, se busca visualmente y se soluciona. Se realiza de nuevo un intento de compilación. Si todo tiene lugar correctamente, se elimina el error.

En caso de que aparezcan nuevos errores, se repite el procedimiento hasta que sean eliminados. Este método es muy útil al escribir grandes programas y con frecuencia funciona cuando se escriben códigos relativamente pequeños.

Es muy importante determinar correctamente los bloques del código que deben comentarse. Si es una condición (u otra construcción lógica), esta debe comentarse completamente. Si comentamos un bloque en el que se declaran las variables, es importante no dejar abierto el bloque que alude a estas variables. Esto quiere decir que los comentarios deben usarse de acuerdo con la lógica de la programación. Incumplir este método provocará que aparezcan los mismos errores durante la compilación.

Ejemplo

Pondré un ejemplo de la búsqueda en la práctica de un error en el código. Supongamos que tenemos un código:

#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()
  {
//+--------------------------------------------------------------------------------------------------+
//|                                        search for opened orders by symbol
   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;   
  } 
 }
     
//|                                        search for opened orders by symbol                       |
//+-------------------------------------------------------------------------------------------------+  
 
//+-------------------------------------------------------------------------------------------------+
//|                                                stop for break-even
  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);       
   } 
  }   
//|                                                stop for break-even                              |
//+-------------------------------------------------------------------------------------------------+ 
   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);
  }
//+------------------------------------------------------------------+

Vemos el siguiente mensaje de error durante la compilación:


Es imposible detectar rápidamente el bloque donde se ha producido el error. Volvemos de nuevo al comentario. Comentamos todas las construcciones lógicas:

#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()
  {
  /*
//+-----------------------------------------------------------------------------------------------+
//|                                        search for opened orders by symbol                     |
   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;   
  } 
 }
     
//|                                        search for opened orders by symbol                    |
//+----------------------------------------------------------------------------------------------+  
*/
 
/*
//+----------------------------------------------------------------------------------------------+
//|                                                stop for break-even                           |
  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);       
   } 
  }   
//|                                                stop for break-even                          |
//+---------------------------------------------------------------------------------------------+ 
*/
 
 
/*
   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);
  }
//+------------------------------------------------------------------+

Podemos estar seguros fácilmente de que este código puede compilarse sin problemas. Esto significa que la parte del código donde estaba el error está "oculta". Abrimos las partes del código /* ... */ sucesivamente e intentamos compilarlas.

La compilación tendrá éxito hasta que alcancemos el siguiente bloque del código:

//***************************************************************************
 
 
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; 
 }

Por tanto, el error está en esta construcción lógica. Podemos ver que ahí hay un paréntesis extraño en la construcción durante el examen detallado de esta parte del código:

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

Si la eliminamos, el código se compilará correctamente.

Nos aseguramos de que no hay otros errores en el código eliminando los restantes comentarios. Esto significa que logramos nuestro objetivo: encontramos el error en el código con la suficiente rapidez.

Conclusión

Se ha mostrado a través de un ejemplo práctico cómo usar este algoritmo para la búsqueda de errores. Se usó un código no muy pequeño (194 entradas) en este ejemplo, por lo que su "investigación" podría haber llevado un largo tiempo. La posibilidad de comentar permite ahorrar el tiempo suficiente a los programadores que se encuentran con el problema de la búsqueda de errores.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1547

Interfaces gráficas III: Botones simples y multifuncionales (Capítulo 1) Interfaces gráficas III: Botones simples y multifuncionales (Capítulo 1)
Vamos a comenzar el análisis del control como el botón. Vamos a mostrar los ejemplos de varias clases para la creación de un botón simple, un botón con funcionalidad ampliada (“botón con imagen” y “botón de división”), así como los botones interconectados (grupos de botones y “botones de opción”). Aparte de eso, vamos a introducir algunas adiciones en las clases ya existentes de los controles con el fin de ampliar sus posibilidades.
La inacción es el estímulo para el progreso o cómo trabajar con gráficos de forma interactiva La inacción es el estímulo para el progreso o cómo trabajar con gráficos de forma interactiva
Un indicador para el trabajo interactivo con líneas de tendencia, niveles Fibo e iconos impuestos manualmente en un gráfico. Nos permite dibujar las zonas coloreadas de niveles Fibo, muestra los momentos de cruce del precio sobre la línea de tendencia y gestiona el objeto "Price label" (etiqueta del precio).
Interfaces gráficas III: Grupos de botones simples y multifuncionales (Capítulo 2) Interfaces gráficas III: Grupos de botones simples y multifuncionales (Capítulo 2)
El primer capítulo de la tercera pare de la serie estaba dedicada a los botones simples y multifuncionales. En el segundo capítulo hablaremos de los grupos de botones interconectados que permiten crear los controles, cuando el usuario puede elegir una opción de un determinado conjunto (grupo).
Como escribir Zig Zags rápido sin redibujado Como escribir Zig Zags rápido sin redibujado
Se propone un método bastante universal de escribir indicadores del tipo Zig Zag. El método incluye una parte considerable de los Zig Zags ya descritos y nos permite crear otros nuevos con relativa facilidad.