MetaTrader 5 herunterladen

Grundlagen der Programmierung in MQL5: Globale Variablen des Terminals

13 Juni 2016, 10:07
Dennis Kirichenko
0
288

Einleitung

Es gibt in der MQL4/5-Umgebung ein interessantes Instrument - die globalen Variablen des Client-Terminals. Mit ihm kann man für alle Programme des Terminals einen gemeinsam nutzbaren Datenspeicherungsbereich anlegen. Darüber hinaus endet die Lebensdauer dieses Bereichs nicht, wenn das Terminal geschlossen wird. Dieser Beitrag schlägt die Verwendung von Objekt-orientierten Programmierungs-Tools vor, um eine klare Vorstellung davon zu bekommen, was die globalen Variablen des Terminals eigentlich sind.

Im weiteren Verlauf des Beitrags heißen die globalen Variablen des Client-Terminals immer "globale Variablen", es sei denn anders angegeben.


1. Globale Variablen, Funktionen

Vom Standpunkt eines Programmierers, ist eine globale Variable ein benannter Speicherbereich, auf den alle Arbeitsprogramme des Handelsterminals Zugriff haben. Neulinge unter den Programmierern sollten beachten, dass, wenn mehrere Terminals zeitgleich arbeiten, jedes Arbeitsprogramm seinen eigenen, unabhängigen Speicherbereich für globale Variablen hat. Sie werden sich auch nicht überlappen.

Die Sprachentwickler geben in der Dokumentation an, dass es 11 Funktionen gibt, die für die Arbeit mit globalen Variablen verwendet werden.

Diesbezügliche Theorie findet sich im Abschnitt "GlobaleVariablen" des MQL4-Leitfaden.

Im nächsten Abschnitt verwende ich die Objekt-orientierten Programmierungsinstrumente zur Implementierung der gesetzten Aufgaben.


2. CGlobalVar Klasse

Im Sinne der Gedanken des Objekt-orientierten Programmierens, erzeugen wir die CGlobalVar Klasse, die direkt für das Objekt einer globalen Variable zuständig ist.

//+------------------------------------------------------------------+
//| Class CGlobalVar                                                 |
//+------------------------------------------------------------------+
class CGlobalVar : public CObject
  {
   //--- === Data members === --- 
private:
   string            m_name;
   double            m_value;
   //---
   datetime          m_create_time;
   datetime          m_last_time;
   //--- flag for temporary var
   bool              m_is_temp;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CGlobalVar(void);
   void              CGlobalVar(const string _var_name,const double _var_val,
                                const datetime _create_time);
   void             ~CGlobalVar(void){};
   //--- create/delete
   bool              Create(const string _var_name,const double _var_val=0.0,
                            const bool _is_temp=false);
   bool              Delete(void);
   //--- exist
   bool              IsGlobalVar(const string _var_name,bool _to_print=false);

   //--- set methods
   bool              Value(const double _var_val);
   bool              ValueOnCondition(const double _var_new_val,const double _var_check_val);

   //--- get methods
   string            Name(void) const;
   datetime          CreateTime(void) const;
   datetime          LastTime(void);
   template<typename T>
   T                 GetValue(T _type) const;
   bool              IsTemporary(void) const;
   //---
private:
   string            FormName(const string _base_name,const bool _is_temp=false);
  };

Was muss eine Klasse alles umfassen? Für eine Mindestauflistung an Merkmalen würde ich folgende Eigenschaften auswählen:

  • Name einer Variable;
  • Wert einer Variable;
  • Zeit der Erzeugung;
  • Zeit des letzten Aufrufs;
  • Merkmal einer temporären Variable.

Was die Methoden angeht, sie sehen folgendermaßen aus:

  • Erzeugung;
  • Löschung;
  • Prüfung auf Vorhandensein;
  • Einrichten eines neuen Werts;
  • Einrichten eines neuen Werts nach Bedingung;
  • Empfang eines Namens;
  • Empfang eines Werts;
  • Empfang eines temporären Variablen-Markers.

Die CGlobalVar::GetValue Methode verdient es, extra erwähnt zu werden, da sie eine Template-Methode ist. Sie liefert den Datentyp für den Variablenwert, den ein Anwender als Begründung einrichtet.

Das Problem hier ist, dass in MQL eine Funktion nur nach Parametern typenspezifiziert werden kann. Deshalb müssen wir einen fingierten Parameter hinzufügen.

Erzeugen wir also das Test-Script Globals_test1.mq5, in dem wir mir den Objekten des CGlobalVar Typs arbeiten werden.

#include "CGlobalVar.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVar gVar1;
//--- create a temporary global var
   if(gVar1.Create("Gvar1",3.123456789101235,true))
     {
      Print("\n---=== A new global var ===---");
      PrintFormat("Name: \"%s\"",gVar1.Name());
      PrintFormat("Is temporary: %d",gVar1.IsTemporary());

      //--- Get the value 
      //--- double type
      double d=0.0;
      double dRes=gVar1.GetValue(d);
      PrintFormat("Double value: %0.15f",dRes);
      //--- float type
      float f=0.0;
      float fRes=gVar1.GetValue(f);
      PrintFormat("Float value: %0.7f",fRes);
      //--- string type
      string s=NULL;
      string sRes=gVar1.GetValue(s);
      PrintFormat("String value: %s",sRes);

      //--- Set a new value 
      double new_val=3.191;
      if(gVar1.Value(new_val))
         PrintFormat("New value is set: %f",new_val);

      //--- Set a new value on condition
      new_val=3.18;
      if(gVar1.ValueOnCondition(3.18,3.191))
         PrintFormat("New value on conditionis set: %f",new_val);
     }
  }

Und so wird die globale Variable erzeugt:

gVar1.Create("Gvar1",3.123456789101235,true)

Die erste Begründung ist die Basiskomponente des zukünftigen Variablennamen ("Gvar1"), die zweite Begründung ist der Wert von (3,123456789101235) und die dritte ist das Merkmal, das anzeigt, dass die Variable vorläufig sein wird (true).

Der Name der Variable wird durch Hinzufügen des Programmnamens und -typs an die Basiskomponente erzeugt.

In meinem Fall also:

  1. Gvar1 - die Basiskomponente;
  2. prog_Globals_test1 - das Programm, in dem die Variable erzeugt wurde (ihr Name ist Globals_test1);
  3. Programmtyp ist - scr (Script).

Wenn Sie 'F3' drücken, sollte in der Liste mit den globalen Variablen im MetaTrader 5 Fenster der folgende Eintrag erscheinen:

Abb. 1 Wert der Test_temp_var1_prog_Globals_test1_scr Vriable = 3,18

Abb. 1 Wert der Test_temp_var1_prog_Globals_test1_scr Vriable = 3,18

Bei erfolgreichem Start und erfolgreicher Implementierung, werden die folgenden Einträge in das "Experts" Logbuch gedruckt:

KP      0       10:20:20.736    Globals_test1 (AUDUSD.e,H1)     ---=== A new global var ===---
EH      0       10:20:21.095    Globals_test1 (AUDUSD.e,H1)     Name: "Gvar1_temp_prog_Globals_test1_scr"
LF      0       10:20:21.876    Globals_test1 (AUDUSD.e,H1)     Is temporary: 1
MO      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     Double value: 3.123456789101235
KG      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     Float value: 3.1234567
OP      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     String value: 3.123456789101235
RH      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     New value is set: 3.191000
DJ      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     New value on conditionis set: 3.180000

In das Logbuch werden unterschiedliche Datentypen des Variablenwerts gedruckt.

Wird das MetaTrader 5 Terminal neu gestartet, verschwindet die Gvar1_temp_prog_Globals_test1_scr Variable aus der Liste der globalen Variablen. Und das geschieht deswegen, weil die Variable vorläufig war und nur solange "lebte", wie das Terminal offen war.

Im Moment Erhalts der Daten zur globalen Variable, gibt es in MQL4/5 keine Möglichkeit herauszufinden, ob die Variable vorläufig ist oder nicht. Die vielleicht leichteste Möglichkeit eine vorläufige Variable zu erkennen, ist durch Hinzufügen eines Schlüssels an den Namen der Variable. Das kann z.B. das Suffix "temp" am Variablennamen sein. Die Notwendigkeit, das Erstellen des Namens der globalen Variable zu kontrollieren zu müssen, ist jedoch ein klarer Nachteil dieses Ansatzes, vor allem dann, wenn derartige Variablen von anderen Programmierern angelegt werden, die nicht mit der CGlobalVar Klasse arbeiten.

Irgendwann wollte ich dann wissen, wie viele globale Variablen man erstellen kann und wie rasch.

Dazu habe ich das vorherige Script leicht abgeändert und es in Globals_test2.mq5 umbenannt und es dann mit einer anderen Anzahl von Durchläufen gestartet. Bei jedem Durchlauf habe ich das Terminal neu gestartet, um Variablen zu löschen.

#property script_show_inputs
//---
#include "CGlobalVar.mqh"

input uint InpCnt=10000; // Number of variables
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- start value
   uint start=GetTickCount();
//---
   for(uint idx=0;idx<InpCnt;idx++)
     {
      CGlobalVar gVar;
      //--- Create a temporary global var
      if(!gVar.Create("Test_var"+IntegerToString(idx+1),idx+0.15,true))
         Alert("Error creating a global variable!");
     }
//--- finish value
   uint time=GetTickCount()-start;
//--- to print
   PrintFormat("Creation of %d global variables took %d ms",InpCnt,time);
  }

Und das ist das Ergebnis (Abb. 2).

Abb. 2 Zur Erstellung vorläufiger globaler Variablen benötigte Zeit

Abb. 2 Zur Erstellung vorläufiger globaler Variablen benötigte Zeit

Abb. 3 zeigt das Ergebnis eines ähnlichen Tests für komplette globale Variablen. Und ihre Erstellung hat nicht viel länger gedauert.

Das liegt daran, dass diese Variablen in der gvariables.dat-Datei, die sich im Order Profile befindet, auf der Festplatte gespeichert werden.

Abb. 3 Zur Erstellung kompletter globaler Variablen benötigte Zeit

Abb. 3 Zur Erstellung kompletter globaler Variablen benötigte Zeit

Ich glaube übrigens nicht, dass man so viele globale Variablen erstellen muss. Ich habe dies einfach ausprobiert und gemacht, weil ich neugierig war.

Im nächsten Abschnitt, beginnen wir mit dem Set an globalen Variablen zu arbeiten.


3. Die CGlobalVarList Klasse

Um die Arbeit mit globalen Variablen regeln zu können, erzeugen wir nun eine Listenklasse von globalen Variablen des Typs CGlobalVarList. Dieser Listentyp ist ein Nachkomme der Standard-Listenklasse CList.

Die Klassendeklarierung kann so dargestellt werden:

//+------------------------------------------------------------------+
//| Class CGlobalVarList                                             |
//+------------------------------------------------------------------+
class CGlobalVarList : public CList
  {
   //--- === Data members === --- 
private:
   ENUM_GVARS_TYPE   m_gvars_type;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CGlobalVarList(void);
   void             ~CGlobalVarList(void){};
   //--- load/unload
   bool              LoadCurrentGlobals(void);
   bool              KillCurrentGlobals(void);
   //--- working with files
   virtual bool      Save(const int _file_ha);
   virtual bool      Load(const int _file_ha);
   //--- service
   void              Print(const int _digs);
   void              SetGvarType(const ENUM_GVARS_TYPE _gvar_type);
   //---
private:
   bool              CheckGlobalVar(const string _var_name);
  };

Wenn Objekte, die mit den aktuellen globalen Variablen verknüpft sind, in eine Liste des Typs CGlobalVarList mit eingeschlossen werden sollen, wird dazu die CGlobalVarList::LoadCurrentGlobals Methode verwendet.

//+------------------------------------------------------------------+
//| Load current global vars                                         |
//+------------------------------------------------------------------+
bool CGlobalVarList::LoadCurrentGlobals(void)
  {
   ENUM_GVARS_TYPE curr_gvar_type=this.m_gvars_type;
   int gvars_cnt=GlobalVariablesTotal();
//---
   for(int idx=0;idx<gvars_cnt;idx++)
     {
      string gvar_name=GlobalVariableName(idx);
      if(this.CheckGlobalVar(gvar_name))
         continue;

      //--- gvar properties
      double gvar_val=GlobalVariableGet(gvar_name);
      datetime gvar_time=GlobalVariableTime(gvar_name);
      CGlobalVar *ptr_gvar=new CGlobalVar(gvar_name,gvar_val,gvar_time);
      //--- control gvar type 
      if(CheckPointer(ptr_gvar)==POINTER_DYNAMIC)
        {
         if(curr_gvar_type>GVARS_TYPE_ALL)
           {
            bool is_temp=ptr_gvar.IsTemporary();
            //--- only full-fledged
            if(curr_gvar_type==GVARS_TYPE_FULL)
              {if(is_temp)continue;}
            //--- only temporary
            else if(curr_gvar_type==GVARS_TYPE_TEMP)
              {if(!is_temp)continue;}
           }
         //--- try to add
         if(this.Add(ptr_gvar)>-1)
            continue;
        }
      //---
      return false;
     }
//---
   return true;
  }

Sie liest alle vorhandenen globalen Variablen und nimmt sie in die Liste auf.

Das m_gvars_type Merkmal kontrolliert den Typ der mit aufgenommenen globalen Variable und ist eine Aufzählung des Typs ENUM_GVARS_TYPE:

//+------------------------------------------------------------------+
//| Enumeration for gvars type                                       |
//+------------------------------------------------------------------+
enum ENUM_GVARS_TYPE
  {
   GVARS_TYPE_ALL=-1,  // all global
   GVARS_TYPE_FULL=0,  // only full
   GVARS_TYPE_TEMP=1,  // only temporary
  };

Nehmen wir, dass vor der Initialisierung der CGlobalVarList Liste ein Set globaler Variablen, so wie in Abb. 4 gezeigt, vorhanden waren.

Abb. 4 Ungefähres Set an globalen Variablen

Abb. 4 Ungefähres Set an globalen Variablen

Wir prüfen nun, ob dieses Set korrekt durch die Liste verarbeitet wird. Und dazu müssen wir das Globals_test3.mq5 Test-Script erstellen.

#include "CGlobalVarList.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVarList gvarList;
   gvarList.LoadCurrentGlobals();   
   PrintFormat("Number of variables in the set: %d",gvarList.Total());
  }

Nach dem Start des Scripts tauchten neue globale Variablen auf (in gelb unterlegt), was eigentlich nicht passieren sollte (Abb. 5).

Abb. 5 Neues Set globaler Variablen

Abb. 5 Neues Set globaler Variablen

Ein String wurde gedruckt als:

2014.10.21 11:35:00.839       Globals_test3 (AUDUSD.e,H1)              Number of variables in the list: 10

Dies passierte, weil es in der Deklarierung der CGlobalVarList::LoadCurrentGlobals Methode einen Verweis auf die CGlobalVar::Create Methode gibt.

Das bedeutet, dass im String eine neue globale Variable erzeugt wird:

if(ptr_gvar.Create(gvar_name,gvar_val))

Zusätzlich dazu verändern sich die Indices der globalen Variablen, sobald neue Variablen auftauchen. Und das ist der Grund für die Verwirrung.

Daher empfehle ich, die CGlobalVar::Create Methode durch eine weniger aktive Methode zu ersetzen. Die CGlobalVar Klasse muss dazu durch einen Konstruktor mit Parametern ergänzt werden, damit die Variable in der Liste berücksichtigt werden kann.

Nach der Veränderung sieht die CGlobalVarList::LoadCurrentGlobals Methode so aus:

//+------------------------------------------------------------------+
//| Load current global vars                                         |
//+------------------------------------------------------------------+
bool CGlobalVarList::LoadCurrentGlobals(void)
  {
   int gvars_cnt=GlobalVariablesTotal();
//---
   for(int idx=0;idx<gvars_cnt;idx++)
     {
      string gvar_name=GlobalVariableName(idx);
      double gvar_val=GlobalVariableGet(gvar_name);
      datetime gvar_time=GlobalVariableTime(gvar_name);
      CGlobalVar *ptr_gvar=new CGlobalVar(gvar_name,gvar_val,gvar_time);
      if(CheckPointer(ptr_gvar)==POINTER_DYNAMIC)
         if(this.Add(ptr_gvar)>-1)
            continue;
      //---
      return false;
     }
//---
   return true;
  }

Und nach der Veränderung der Methode funktioniert das Script jetzt auch korrekt. Der folgende Eintrag wird gedruckt:

2014.10.21 11:38:04.424      Globals_test3 (AUDUSD.e,H1)              Number of variables in the list: 6

Anschließend fügen wir noch Merkmale hinzu, mit denen man eine Liste löschen und drucken kann.

Das Globals_test3.mq5 Script sieht jetzt so aus:

//---
#include "CGlobalVarList.mqh"
//---
input ENUM_GVARS_TYPE InpGvarType=GVARS_TYPE_FULL; // Set gvar type
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVarList gvarList;
//--- delete gvars
   gvarList.SetGvarType(InpGvarType);
//--- load current gvars  
   gvarList.LoadCurrentGlobals();
   Print("Print the list before deletion.");
   gvarList.Print(10);
//--- delete gvars
   if(gvarList.KillCurrentGlobals())
     {
      Print("Print the screen after deletion.");
      gvarList.Print(10);
     }
  }

Machen wir unsere Aufgabe noch ein bisschen komplizierter und erzeugen jetzt 10 unterschiedliche, globale Variablen (Abb. 6).

Abb. 6 Unterschiedliche globale Variablen

Abb. 6 Unterschiedliche globale Variablen

In unserer gvarList Liste sollen nur komplette Variablen aufgenommen werden, die. später dann gelöscht werden.

Das "Expert" Logbuch enthält dann folgendes:

MG      0       11:05:01.113    Globals_test3 (AUDUSD.e,H1)     Print the list before deletion.
KL      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     
OI      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     ---===Local list===---
QS      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Global variable type: GVARS_TYPE_FULL
RI      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Total number of global variables: 10
EG      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Number of global variables in current list: 5
RN      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #1, name - gVar10_prog_test1_scr, value - 16.6400000000
KP      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #2, name - gVar2_prog_test1_scr, value - 4.6400000000
GR      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #3, name - gVar4_prog_test1_scr, value - 7.6400000000
RD      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #4, name - gVar6_prog_test1_scr, value - 10.6400000000
LJ      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #5, name - gVar8_prog_test1_scr, value - 13.6400000000
EH      0       11:06:18.675    Globals_test3 (AUDUSD.e,H1)     Print the list after deletion.
FS      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     
JJ      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     ---===Local list===---
HN      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Global variable type: GVARS_TYPE_FULL
KH      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Total number of global variables: 5
QP      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Number of global variables in the current list: 0

Die Liste, die jetzt nur komplette, globale Variablen enthält, wurde korrekt angelegt.

Dann wurde sie geleert, sodass nur noch 5 vorläufige Variable im Terminal verbleiben (Abb. 7).

Abb. 7 Vorläufige globale Variablen

Abb. 7 Vorläufige globale Variablen

Wir haben das, was wir uns vorgenommen haben, erreicht.

In der CGlobalVarList Klasse wurden zudem auch Methoden zur Datenspeicherung und zum Download von Daten aus der Datei implementiert.


4. Praktische Anwendung

Wir wir alle wissen, ist MQL4/5 eine spezielle Programmiersprache, die zur Programmierung von Handelsstrategien erfunden wurde. Und daher kann man jedes Tool dieser Sprache als ein Mittel zur Formalisierung einer bestimmten Handelsidee betrachten.

Auf der MQL 5 Plattform gibt es genügend Beispiele für eine Verknüpfung von Expert Advisors mit globalen Variablen. Diesmal schlage ich vor, sich die Situation genauer anzusehen, in der eine Kontrolle der Programmimplementierung erforderlich ist.

Nehmen wir mal an, es gibt einen Code des "Globals_test_EA" Handelsroboters auf Grundlage des modularen Ansatzes:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   return INIT_SUCCEEDED;
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Main();
  }

wo das Hauptmodul so aussieht:

//+------------------------------------------------------------------+
//| Main module                                                      |
//+------------------------------------------------------------------+
void Main(void)
  {
//--- set flags for all modules
   for(int idx=0;idx<GVARS_LIST_SIZE;idx++)
      SetFlag(idx,false);

//--- Check the trade possibility and connectivity
//--- permission to trade
   if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
      //--- connection to the trading server
      if(TerminalInfoInteger(TERMINAL_CONNECTED))
         //--- permission to trade for the launched EA
         if(MQLInfoInteger(MQL_TRADE_ALLOWED))
           {
            //--- 1) opening module
            Open();
            //--- 2) closing module
            Close();
            //--- 3) Trailing Stop module
            Trail();
           }
  }

Dieses Modul umfasst also 3 Bestandteile:

  1. Eröffnungsmodul;
  2. Schließungsmodul;
  3. Trailing Stop-Modul.

Jetzt müssen wir nur noch globale Variablen zur Kontrolle der Etappen der Programmausführung erstellen.

Es gibt drei Phasen in Form von Modulen. In jeder Phase werden zwei Kontrollpunkte verwendet. Der erste Kontrollpunkt kontrolliert den Anfang der Arbeit des Moduls und der zweite das Ende seiner Arbeit.

Kontrollpunkte werden in Form globaler Variablen implementiert.

Wir brauchen daher sechs globale Variablen mit den folgenden Namen:

//--- global variables: names
string gVar_names[6]=
  {
   "gvarOpen_start","gvarOpen_finish",
   "gvarClose_start","gvarClose_finish",
   "gvarTrail_start","gvarTrail_finish"
  };

Marker für alle Module werden am Anfang der Main() Funktion eingerichtet und in jedem separaten Modul dann geleert. Ich brauche wohl nicht extra erwähnen, dass wir hier ausschließlich von "eigenen" Markern sprechen. Beispiel: das Open() Modul:

//+------------------------------------------------------------------+
//| Open module                                                      |
//+------------------------------------------------------------------+
void Open(void)
  {
   Comment(curr_module+__FUNCTION__);
//---
   if(!IsStopped())
     {
      //--- clear the module start flag
      SetFlag(0,true);

      //--- assume that the module operates for approximately 1.25 s
        {
         Sleep(1250);
        }
      //--- clear the module finish flag
      SetFlag(1,true);
     }
  }

Bei Ausführung des Moduls, erscheint im Chartfenster ein Kommentar, dass das Programm im Open() Block arbeitet.

Wenn dann kein Schließen des Programms erzwungen wurde, wird die Kontrolle an die Funktion übertragen, die einen entsprechenden Marker setzt/löscht. Sollte ein Marker in einem der Kontrollpunkte nicht gelöscht werden können, wird das so interpretiert, dass das Modul seine Arbeit nicht abgeschlossen hat.

Abb. 8 zeigt ein Muster der Rückverfolgungsphasen der Arbeit des Moduls mit globalen Variablen.

Abb. 8 Muster der Abfolge der verarbeitenden Marker

Abb. 8 Muster der Abfolge der verarbeitenden Marker

So ist z.B. der "Globals_test_EA" Expert Advisor an den Chart angehängt und funktioniert normal.

Als ich jedoch den Expert Advisor vom Chart gelöscht habe, zeigte mir das Logbuch den folgenden Eintrag:

2014.10.22 20:14:29.575 Globals_test_EA (EURUSD.e,H1)   Program forced to terminate before execution: <<Open_finish>>

Das heißt also, dass die Beendigung des Expert Advisors im Open(). Modul stattfand.

Durch Drücken von "F3" (Abb. 9) öffnen Sie die Liste der globalen Variablen.

Abb. 9 Globale Variablen für den "Globals_test_EA" Expert Advisor

Abb. 9 Globale Variablen für den "Globals_test_EA" Expert Advisor

Wenn wir uns diese Liste ansehen, erkennen wir, dass der Marker, der für den Anfang der Arbeit des Open() Moduls verantwortlich war, genullt wurde.

Es hat den Anschein, als könnten Fehler im Zusammenhang mit der Eröffnung, dem Schließen und der Beibehaltung von Positions möglicherweise bereits bei einer gescheiterten Ausführung des Befehls entdeckt werden.

Nach einem Neustart des Roboters auf dem gleichen Chart, wird im Logbuch die folgende Information angezeigt:

RQ      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Open_finish>>
CL      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Close_start>>
DH      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Close_finish>>
ES      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Trail_start>>
RS      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Trail_finish>>

Auf diese Weise erhalten wir eine Warnung über einen Misserfolg der Programmphasen - was uns zu einer anderen Frage führt: Was kann man machen, wenn die Phasen fehlschlagen? Doch das ist eine ganz andere Geschichte.


Fazit

In diesem Beitrag habe ich die Objekt-orientierten Fähigkeiten der MQL5-Sprache zur Erzeugung von Objekten aufzuzeigen versucht, die die Arbeit mit den globalen Variablen des Terminals immens erleichtern.

Als Beispiel diente der Fall, in dem globale Variablen als Kontrollpunkte zur Implementierung der Programmphasen hergenommen werden.

Ich freue mich wie immer über Kommentare, Vorschläge und konstruktive Kritik.


Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/1210

Beigefügte Dateien |
globals_test1.mq5 (3.67 KB)
globals_test2.mq5 (2.92 KB)
globals_test3.mq5 (2.59 KB)
cglobalvar.mqh (20.52 KB)
cglobalvarlist.mqh (18.74 KB)
globals_test_ea.mq5 (13.01 KB)
Statistik-Cookbook für Händler: Hypothesen Statistik-Cookbook für Händler: Hypothesen

Dieser Beitrag beschäftigt sich mit Hypothesen - einem der Grundkonzepte mathematischer Statistik. Es werden dabei verschiedene Hypothesen untersucht und anhand von Beispielen mit Hilfe mathematischer Statistikmethoden überprüft. Die tatsächlichen Daten werden mittels nicht parametrischer Methoden verallgemeinert. Zur Verarbeitung der Daten werden das Statistica-Paket und die übertragene ALGLIB MQL5 numerische Analyse-Library verwendet.

Programmierung von EA-Modi mit Hilfe des Objekt-orientierten Ansatzes Programmierung von EA-Modi mit Hilfe des Objekt-orientierten Ansatzes

Dieser Beitrag erklärt das Konzept des Programmierens eines Mulit-Modus Handelsroboters in MQL5. Jeder Modus wird mittels des Objekt-orientierter Ansatzes implementiert. Instanzen von sowohl Modus-Klassenhierarchie als als auch Klassen zum Testen werden angeboten. Das Programmieren in mehreren Modi von Handelsrobotern soll alle Besonderheiten jedes betrieblichen Modus eines in MQL5 geschriebenen EA berücksichtigen. Funktionen und Aufzählung werden zur Identifizierung des Modus erzeugt.

Liquid-Chart Liquid-Chart

Würden Sie auch sehr gerne einen stündlichen Chart sehen, der zwischen der zweiten und der fünfte Minute Balken öffnet? Wie sieht ein neu entworfener Chart aus, wenn sich die Balkenöffnungszeit jede Minute ändert? Welche Vorteile bietet solch ein Chart beim Trading? Antworten auf diese und einige weitere Fragen werden Sie im vorliegenden Artikel finden.

Auf Fraktalen basiertes Zeichnen von Trendlinien mithilfe von MQL4 und MQL5 Auf Fraktalen basiertes Zeichnen von Trendlinien mithilfe von MQL4 und MQL5

Dieser Artikel widmet sich dem automatischen Zeichnen von Trendlinien via MQL4 und MQL5 basierend auf dem Fraktale-Indikator. Die Struktur des Artikels ist so angelegt, dass sie einen vergleichenden Blick auf zwei Sprachen werfen wird. Das Zeichnen von Trendlinien basiert dabei auf den beiden letzten bekannten Fraktalen.