Discusión sobre el artículo "Aserciones en los programas MQL5" - página 3

 
Explicación. En el momento de escribir este artículo en MQL5 no existía ningún mecanismo para que el programa realizara una parada de emergencia. Como alternativa, se disparaba el runtime error, lo que garantizaba el crash del programa.
Eso no es cierto. Un EA puede ser detenido por ExpertRemove(), un indicador por ChartIndicatorDelete(), y es trivial para un script.
 
Alain Verleyen:
Eso no es verdad. Un EA puede ser detenido por ExpertRemove(), un indicador por ChartIndicatorDelete(), y es trivial para un script.

Por favor, muéstrame un ejemplo, cómo salir con ExpertRemove() en un ciclo.

Por ejemplo, tenemos este código:

#property version   "1.00"
#property strict

int OnInit()
  {
   for(int i = 0; i < 100; i++)
   {
      if(i == 2)
      {
         ExpertRemove();
      }
      Print(i);
   }
      
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }

Necesitamos salir si i == 2, y todos los otros pasos no deben correr. En el diario debemos ver sólo "0" y "1". ¿Cómo podemos hacerlo con esta función?

En este momento ExpertRemove() no detiene el EA en el momento necesario, todos los pasos se ejecutarán, y después de esto el EA se detendrá. Pero esto es incorrecto para el mecanismo de aserción, debemos detener el EA momentáneamente. Y sí, no podemos utilizar sólo "break", porque necesitamos macro universal o función para cualquier parte de cualquier EA.


Acerca de los indicadores - por favor, muéstreme mecanismo universal para la definición ShortName de los indicadores. Porque sin este mecanismo no podemos utilizar esta función para las afirmaciones. Sí, podemos definir ShortName en nuestro indicador concreto (por ejemplo, con una variable global, como mucha gente lo hace, incluso si es una mala práctica), pero no tenemos, por ejemplo, la función universal "GetShortName()". Asi que no podemos hacer un mecanismo universal (me refiero a alguna macro o funcion para absolutamente cualquier indicador, donde podamos agregar solo una linea "assert(...)") con ChartIndicatorDelete().


Y por favor muéstrenme una variante "trivial" para Sripts para cualquier parte del código. Debe ser una (!) función o macro para cualquier parte del Script:

1) Para ciclos
2) Para funciones con cualquier tipo de retorno
3) Para funciones sin tipo de retorno (void).

Así que sólo debemos añadir una línea "assert(...)" en cualquier parte de Sript, así:

#property version   "1.00"
#property strict

void OnStart()
  {
   assert(...);

  }

double SomeDouble()
  {
   assert(...);
   return 0.0;
  }

color SomeColor()
  {
   assert(...);
   return clrNONE;
  }

string SomeString()
  {
   assert(...);
   return "";
  }

void SomeVoid()
  {
   assert(...);
   return;
  }

void SomeCicle()
  {
   while(!IsStopped())
     {
      assert(...);
     }
  }

P.D. perdón por mi mal inglés.

 

O otro ejemplo de EA con ExpertRemove(), no con cicle :)

Por ejemplo, debemos detener la aplicación si el volumen es mayor de lo que necesitamos (es sólo un ejemplo, en la situación real debemos manejar esta situación de manera diferente):

#property version   "1.00"
#property strict

int OnInit()
  {
   OpenTrade();
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }
bool OpenTrade()
{
   double volume = GetVolume();
   
   if(volume > 1)
   {
      Print("Volume > 1, stop EA!");
      ExpertRemove();
   }
   
   Print("Opening position ...");
   
   return true;
}

double GetVolume()
{
   return 999.0;
}

Debemos detener EA momentáneamente en el lugar necesario del código (en este sentido es de aserciones). Pero ExpertRemove() en este caso no variante correcta, tenemos:

2015.12.06 10:53:22.253 Prueba EURUSD,H1: Volumen > 1, parada EA!<br/ translate="no">2015.12.06 10:53:22.253 Prueba EURUSD,H1: ExpertRemove función llamada
2015.12.06 10:53:22.253 Prueba EURUSD,H1: Posición de apertura ...


Por lo tanto, por favor, muéstreme cómo utilizar ExpertRemove() función (sin retorno, romper, etc, debe ser universalmente para cualquier parte del código) para este ceil.

 
Sergey Eremin:

Por favor, muéstrame un ejemplo, cómo salir con ExpertRemove() en un ciclo.

Por ejemplo, tenemos este código:

Necesitamos salir si i == 2, y todos los otros pasos no deben correr. En el diario debemos ver sólo "0" y "1". ¿Cómo podemos hacerlo con esta función?

En este momento ExpertRemove() no detiene el EA en el momento necesario, todos los pasos se ejecutarán, y después de esto el EA se detendrá. Pero esto es incorrecto para el mecanismo de aserción, debemos detener el EA momentáneamente. Y sí, no podemos utilizar sólo "break", porque necesitamos macro universal o función para cualquier parte de cualquier EA.

Usted no tiene que utilizar ExpertRemove() en OnInit(), sólo tiene que utilizar return(INIT_FAILED);

int OnInit()
  {
//---
    ...

         if(somethign wrong)
           {
            //ExpertRemove(); 
            return(INIT_FAILED);    //--- No es necesario usar ExpertRemove() en OnInit()
           }
    ...
  }

en otra parte del codigo, solo return :

            ExpertRemove();
            return;           //--- Solo regresa para terminar el manejador del evento actual

or

            ExpertRemove();
            return(x);        //--- Solo regresa para terminar el manejador del evento actual

Acerca de los indicadores - por favor muéstreme el mecanismo universal para definir el ShortName de los indicadores. Porque sin este mecanismo no podemos utilizar esta función para Assertions. Sí, podemos definir ShortName en nuestro indicador concreto (por ejemplo con la variable global, como mucha gente lo hace, incluso si es una mala práctica), pero no tenemos, por ejemplo, la función universal "GetShortName()". Asi que no podemos hacer un mecanismo universal (me refiero a alguna macro o funcion para absolutamente cualquier indicador, donde podamos añadir solo una linea "assert(...)") con ChartIndicatorDelete().

¿Cuál es el problema? Estás trabajando en tu indicador, es tu código, así que conoces el nombre corto.

Mi post era para decirte que no tienes razón al decir que no hay forma de terminar un programa inmediatamente. Es a usted para encontrar la solución para su proyecto Assertion.

No es en absoluto una mala práctica utilizar una variable global en un indicador. Por supuesto si quieres crear tu mismo una nueva limitación con tal afirmación "es una mala práctica", encontrarás un montón de cosas imposibles.

Y por favor muéstrame una variante "trivial" para Sripts para cualquier parte del código. Debe ser una (!) función o macro para cualquier parte del Script:

1) Para ciclos
2) Para funciones con cualquier tipo de retorno
3) Para funciones sin tipo de retorno (void).

Así que sólo debemos añadir una línea "assert(...)" en cualquier parte de Sript, así:

Igual que para EA.

Archivos adjuntos:
 
Alain Verleyen:

Mi post era para decir que no tienes razón al decir que no hay manera de terminar un programa inmediatamente. Te toca a ti encontrar la solución para tu proyecto de Assertion.

No es en absoluto una mala práctica usar variables globales en un indicador. Por supuesto, si usted quiere crear su propia nueva limitación con tal afirmación "es una mala práctica", usted encontrará un montón de cosas imposibles.

Ok, te he entendido. Gracias, tienes razón.

Pero en mi articulo me refiero a soluciones para Assertions: un mecanismo universal de parar aplicaciones MQL4/5 en cualquier parte del codigo (incluyendo OnInit y cicles). Solo hay que añadir una linea en cualquier parte y listo. Como funciona en cualquier mecanismo de Assertions en muchos lenguajes de programación ;)

Si, tus variantes son correctas. Pero no para mi visión de Assertions, porque no es una solución universal para cualquier parte de cualquier código.

Gracias por tu ejemplo de EA.

 
Sergey Eremin:

Vale, te he entendido. Gracias, tienes razón.

Pero en mi artículo me refiero a soluciones para Assertions: universalmente mechamism de detener MQL4/5 aplicaciones en cualquier lugar del código (incluir OnInit y ciclos). Basta con añadir una línea en cualquier parte y listo. Como funciona en cualquier mecanismo de Assertions en muchos lenguajes de programación ;)

Si, tus variantes son correctas. Pero no para mi visión de Assertions, porque no es una solución universal para cualquier parte de cualquier código.

Gracias por tu ejemplo de EA.

Sé lo que quieres hacer, y es perfectamente factible, sólo tienes que generalizar al código que he proporcionado.

Analizando el contexto de llamada en tu(s) macro(s), detectando si es un EA o un indicador, y analizando __FUNCSIG__.

Depende de ti convertirlo en un mecanismo universal.

 
Alain Verleyen:

Sé lo que quieres hacer, y es perfectamente factible, sólo tienes que generalizar a código que he proporcionado.

Analizando el contexto de llamada en tu(s) macro(s), detectando si es un EA o un indicador, y analizando __FUNCSIG__.

Depende de ti convertirlo en un mecanismo universal.

Sí, al principio pensé en esas cosas, pero al final lo hice como vemos en el artículo :)

¡Gracias por tus comentarios!

 

Si alguien va a utilizar este código, tenga en cuenta este punto: el siguiente script

   if(true)
      assert(1==1, "")
   else
      Print("Never executed");

lleva al mensaje "Nunca ejecutado" de la rama else.

Para poder utilizar assert correctamente, debería corregirlo, por ejemplo, de esta forma:

#define  assert(condition, message) \
       do if(!(condition)) \
        { \
         string fullMessage= \
                            #condition+", " \
                            +__FILE__+", " \
                            +__FUNCSIG__+", " \
                            +"line: "+(string)__LINE__ \
                            +(message=="" ? "" : ", "+message); \
         \
         Alert("Assertion failed! "+fullMessage); \
         double x[]; \
         ArrayResize(x, 0); \
         x[1] = 0.0; \
        } while(false)
#else
#define  assert(condition, message) 
#endif

(la macro de la rama #else también está corregida : devuelve una cadena vacía (en lugar de ";").

En esta variante, deberías poner ";" después de assert(...)