Diskussion zum Artikel "Die Verwendung der Behauptung (assertions) bei der Entwicklung der Programme in MQL5" - Seite 3

 
Erläuterung. Zum Zeitpunkt der Abfassung dieses Artikels gab es in MQL5 keinen Mechanismus, mit dem das Programm einen Notstopp durchführen konnte. Als Alternative wurde runtime error ausgelöst, was den Absturz des Programms garantierte.
Das ist nicht richtig. Ein EA kann durch ExpertRemove() gestoppt werden, ein Indikator durch ChartIndicatorDelete(), und für ein Skript ist es trivial.
 
Alain Verleyen:
Das ist nicht wahr. Ein EA kann mit ExpertRemove() gestoppt werden, ein Indikator mit ChartIndicatorDelete(), und es ist trivial für ein Skript.

Bitte zeigen Sie mir ein Beispiel, wie man mit ExpertRemove() in einem Cicle aussteigen kann.

Zum Beispiel haben wir diesen Code:

#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()
  {
//---
   
  }

Wir müssen beenden, wenn i == 2, und alle anderen Schritte müssen nicht laufen. Im Journal müssen wir nur "0" und "1" sehen. Wie können wir das mit dieser Funktion erreichen?

Im Moment stoppt ExpertRemove() den EA nicht zum benötigten Zeitpunkt, alle Schritte laufen weiter, und danach wird der EA gestoppt. Aber das ist falsch für den Assertion-Mechanismus, wir müssen den EA zum richtigen Zeitpunkt stoppen. Und ja, wir können nicht nur "break" verwenden, denn wir brauchen ein universelles Makro oder eine Funktion für jeden Teil eines EA's.


Über Indikatoren - bitte zeigen Sie mir einen universellen Mechanismus zur Definition des Kurznamens von Indikatoren. Denn ohne diesen Mechanismus können wir diese Funktion nicht für Assertions verwenden. Ja, wir können den Kurznamen in unserem konkreten Indikator definieren (z.B. mit einer globalen Variable, wie es viele Leute tun, auch wenn es eine schlechte Praxis ist), aber wir haben zum Beispiel keine universelle Funktion "GetShortName()". Wir können also keinen universellen Mechanismus (ich meine irgendein Makro oder eine Funktion für absolut jeden Indikator, wo wir nur eine Zeile "assert(...)" hinzufügen können) mit ChartIndicatorDelete() machen.


Und bitte zeigen Sie mir eine "triviale" Variante für Sripts für beliebige Teile des Codes. Es muss eine (!) Funktion oder ein Makro für einen beliebigen Teil des Scripts sein:

1) Für Cicles
2) Für Funktionen mit beliebigem Rückgabetyp
3) Für Funktionen ohne Rückgabetyp (void).

Wir müssen also nur eine Zeile "assert(...)" in einem beliebigen Teil von Sript einfügen, etwa so:

#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.S. Entschuldigung für mein schlechtes Englisch.

 

Oder ein anderes Beispiel von EA mit ExpertRemove(), nicht mit Cicle :)

Zum Beispiel müssen wir die App stoppen, wenn das Volumen größer ist als wir es brauchen (es ist nur ein Beispiel, in der realen Situation sollten wir diese Situation anders behandeln):

#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;
}

Wir müssen EA an der benötigten Stelle des Codes kurzzeitig stoppen (das ist der Sinn von Assertions). Aber ExpertRemove() ist in diesem Fall nicht die richtige Variante, wir haben:

2015.12.06 10:53:22.253 Test EURUSD,H1: Volume > 1, stop EA!<br/ translate="no">2015.12.06 10:53:22.253 Test EURUSD,H1: ExpertRemove-Funktion aufgerufen
2015.12.06 10:53:22.253 Test EURUSD,H1: Position eröffnen ...


Also, bitte zeigen Sie mir, wie man die ExpertRemove() Funktion (ohne return, break etc, es muss universell für jeden Teil des Codes sein) für diese Obergrenze verwendet.

 
Sergey Eremin:

Bitte zeigen Sie mir ein Beispiel, wie man mit ExpertRemove() in einem Cicle beenden kann.

Wir haben zum Beispiel diesen Code:

Wir müssen beenden, wenn i == 2, und alle anderen Schritte müssen nicht laufen. Im Journal müssen wir nur "0" und "1" sehen. Wie können wir das mit dieser Funktion erreichen?

Im Moment stoppt ExpertRemove() den EA nicht zum benötigten Zeitpunkt, alle Schritte laufen weiter, und danach wird der EA gestoppt. Aber das ist falsch für den Assertion-Mechanismus, wir müssen den EA zum richtigen Zeitpunkt stoppen. Und ja, wir können nicht nur "break" verwenden, denn wir brauchen ein universelles Makro oder eine Funktion für jeden Teil eines EA's.

Sie müssen nicht ExpertRemove() in OnInit() verwenden, sondern nur return(INIT_FAILED);

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

         if(somethign wrong)
           {
            //ExpertRemove(); 
            return(INIT_FAILED);    //--- Keine Notwendigkeit der Verwendung von ExpertRemove() in OnInit()
           }
    ...
  }

in anderen Teilen des Codes, einfach return :

            ExpertRemove();
            return;           //--- Einfach zurückkehren, um den aktuellen Event-Handler zu beenden

or

            ExpertRemove();
            return(x);        //--- Einfach zurückkehren, um den aktuellen Event-Handler zu beenden

Über Indikatoren - bitte zeigen Sie mir einen universellen Mechanismus zur Definition des Kurznamens von Indikatoren. Denn ohne diesen Mechanismus können wir diese Funktion nicht für Assertions verwenden. Ja, wir können den Kurznamen in unserem konkreten Indikator definieren (z.B. mit einer globalen Variable, wie es viele Leute tun, auch wenn es eine schlechte Praxis ist), aber wir haben zum Beispiel keine universelle Funktion "GetShortName()". Wir können also keinen universellen Mechanismus (ich meine irgendein Makro oder eine Funktion für absolut jeden Indikator, wo wir nur eine Zeile "assert(...)" hinzufügen können) mit ChartIndicatorDelete() erstellen.

Was ist das Problem? Sie arbeiten an Ihrem Indikator, es ist Ihr Code, also kennen Sie die Kurzbezeichnung.

Mit meinem Beitrag wollte ich sagen, dass es nicht richtig ist, dass es keine Möglichkeit gibt, ein Programm sofort zu beenden. Es liegt an Ihnen, eine Lösung für Ihr Assertion-Projekt zu finden.

Es ist absolut keine schlechte Praxis, globale Variablen in einem Indikator zu verwenden. Wenn Sie natürlich selbst eine neue Einschränkung mit der Behauptung "es ist schlechte Praxis" schaffen wollen, werden Sie eine Menge unmöglicher Dinge finden.

Und bitte zeigen Sie mir eine "triviale" Variante für Sripts für beliebige Teile des Codes. Es muss eine (!) Funktion oder ein Makro für einen beliebigen Teil des Scripts sein:

1) Für Cicles
2) Für Funktionen mit beliebigem Rückgabetyp
3) Für Funktionen ohne Rückgabetyp (void).

Wir müssen also nur eine Zeile "assert(...)" in einem beliebigen Teil von Sript einfügen, etwa so:

Dasselbe wie bei EA.

Dateien:
 
Alain Verleyen:

Mit meinem Beitrag wollte ich sagen, dass es nicht richtig ist, dass es keine Möglichkeit gibt, ein Programm sofort zu beenden. Es liegt an Ihnen, eine Lösung für Ihr Assertion-Projekt zu finden.

Es ist absolut keine schlechte Praxis, eine globale Variable in einem Indikator zu verwenden. Natürlich, wenn Sie selbst eine neue Einschränkung mit dieser Behauptung "es ist schlechte Praxis" schaffen wollen, werden Sie eine Menge unmöglicher Dinge finden.

Ok, ich habe Sie verstanden. Danke, Sie haben Recht.

Aber in meinem Artikel meine ich Lösungen für Assertions: universeller Mechanismus zum Anhalten von MQL4/5-Anwendungen an jeder Stelle des Codes (einschließlich OnInit und Cicles). Einfach eine Zeile in einem beliebigen Teil hinzufügen und fertig. So wie es in jedem Assertions-Mechanismus in vielen Programmiersprachen funktioniert ;)

Ja, Ihre Varianten sind richtig. Aber nicht für meine Vision von Assertions, weil es keine universelle Lösung für jeden Teil des Codes ist.

Vielen Dank für Ihr Beispiel von EA.

 
Sergey Eremin:

Ok, ich habe Sie verstanden. Danke, du hast recht.

Aber in meinem Artikel meine ich Lösungen für Assertions: universeller Mechanismus zum Anhalten von MQL4/5-Anwendungen an jeder Stelle des Codes (einschließlich OnInit und Cicles). Einfach eine Zeile in einem beliebigen Teil hinzufügen und fertig. So wie es in jedem Assertions-Mechanismus in vielen Programmiersprachen funktioniert ;)

Ja, Ihre Varianten sind richtig. Aber nicht für meine Vision von Assertions, weil es keine universelle Lösung für jeden Teil des Codes ist.

Vielen Dank für Ihr Beispiel von EA.

Ich weiß, was Sie tun wollen, und es ist durchaus machbar, Sie müssen nur den von mir bereitgestellten Code verallgemeinern.

Indem Sie den Aufrufkontext in Ihren Makros analysieren, erkennen, ob es sich um einen EA oder einen Indikator handelt, und __FUNCSIG__ analysieren.

Es liegt an Ihnen, dies zu einem universellen Mechanismus zu machen.

 
Alain Verleyen:

Ich weiß, was Sie tun wollen, und es ist durchaus machbar, Sie müssen nur zu Code verallgemeinern ich zur Verfügung gestellt.

Indem Sie den aufrufenden Kontext in Ihren Makros analysieren, erkennen, ob es sich um einen EA oder einen Indikator handelt, und __FUNCSIG__ parsen.

Es liegt an Ihnen, dies zu einem universellen Mechanismus zu machen.

Ja, zuerst habe ich über solche Dinge nachgedacht, aber schließlich habe ich es so gemacht, wie wir es im Artikel sehen :)

Vielen Dank für Ihre Kommentare!

 

Falls jemand diesen Code verwenden möchte, beachten Sie bitte folgenden Punkt: Das folgende Skript

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

führt zu der Meldung "Never executed" aus dem else-Zweig.

Um assert korrekt verwenden zu können, sollten Sie es korrigieren, zum Beispiel in dieser Form:

#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

(das Makro im #else-Zweig ist ebenfalls korrigiert: es gibt eine leere Zeichenkette zurück (anstelle von ";").

In dieser Variante sollten Sie ";" nach assert(...) einfügen.