Русский 中文 Español Deutsch 日本語 Português
MQL5 Programming Basics: Global Variables of the  MetaTrader 5 Terminal

MQL5 Programming Basics: Global Variables of the MetaTrader 5 Terminal

MetaTrader 5Examples | 25 November 2016, 13:11
27 279 5
Dmitry Fedoseev
Dmitry Fedoseev

Contents

Introduction

Global variables of the terminal (Fig. 1) are the unique feature of MetaTrader and MQL language.


Fig. 1. Code fragment with the global variables

Be sure not to confuse terminal global variables with well-known program global variables (Fig. 2) trying to find their counterparts in other programming languages.


Fig. 2. MovingAverage EA code fragment from the terminal examples. The program global variables are highlighted in red

Since the terminal global variables do not have exact matches in other programming languages, they are not popular among MQL5 novice learners. Perhaps they simply have no idea how and why they can be used or their application seems too complicated due to rather cumbersome function names: GlobalVariableSet(), GlobalVariableGet(), GlobalVariableCheck(), etc.

The main feature of the terminal global variables is that they retain their values even after the terminal is closed. That is why they provide very convenient and fast means for storing important data and are almost indispensable when developing reliable EAs involving complex interaction between orders. After you master the global variables, you will no more be able to imagine developing EAs on MQL5 without them.

The article provides practical examples allowing you to learn all functions for working with global variables, examine their features and application methods, as well as develop a class that significantly simplifies and accelerates working with them.

The functions for working with the global variables can be found in the MQL5 Documentation here

Viewing global variables in the terminal

While in the terminal, execute the following command: Main menu — Tools — Global Variables. The Global Variables window appears (Fig. 3).

 
Fig. 3. The Global Variables window in the terminal 

Basically, all works with global variables are performed programmatically. However, this window might be useful when testing EAs. It allows you to view all the terminal global variables as well as edit names and values. To change a variable, click on the field with its name or value. Also, the window allows creating new variables. To do this, click Add in the upper right corner. Delete button is used to delete the global variables. Before deletion, click on the necessary variable to make the button active. Practice in creating, changing and deleting the global variables. Note: if the window already contains some variables when you open it, leave them intact since they may be necessary for an EA launched at your account.

A global variable has three attributes: name, value and time. The Time field displays when the variable was last accessed. Upon expiration of four weeks after the last access, the variable is deleted automatically. However, if the variable stores important data, it should be accessed periodically to extend its lifetime.  

Creating a global variable of the terminal

The variable is generated automatically when a value is assigned to it. If the variable with the given name already exists, its value is updated. The GlobalVariableSet() function is used to assign a value to the variable. The two parameters are passed to the function: variable name (string) and its value (double type). Let's try to create a variable. Open MetaEditor, create a script and write the following code to its OnStart() function:

GlobalVariableSet("test",1.23);

 Execute the script and open the global variables window from the terminal. The window should contain a new variable named "test" and the value of 1.23 (Fig. 4).

 
Fig. 4. Fragment of the global variables window with the new "test" variable

The code of the example can be found in the sGVTestCreate script.  

Receiving a value of a global variable

After the script from the previous example completes its work, the variable still exists. Let's look at its value. The GlobalVariableGet() function is used to receive the value. There are two function call methods. When applying the first one, only a name is passed to the function. The function returns the double type value:

double val=GlobalVariableGet("test");
Alert(val);

When running the code, a window with the value of 1.23 is opened. The example can be found in the sGVTestGet1 script attached below.

When applying the second method, the two parameters – name and double variable for the value (the second parameter is passed by the reference) – are passed to the function that in turn returns true or false depending on the results:

double val;
bool result=GlobalVariableGet("test",val);
Alert(result," ",val);

The window with the message "true 1.23" is opened as a result.

If we try to receive the value of a non-existent variable, the function returns false and 0. Let's change a bit the previous code sample: assign 1.0 to the 'val' variable when declaring and try receiving the value of the non-existent "test2" variable:

double val=1.0;
bool result=GlobalVariableGet("test2",val);
Alert(result," ",val);

The window with the message "false 0.0" is opened as a result. The example can be found in the sGVTestGet2-2 script attached below.

When calling the function using the first method, we also obtain 0.0 in case of a non-existent variable. However, the error is received as well. By using the first function call method and error check, we may obtain the analog of the second function method:

ResetLastError();
double val=GlobalVariableGet("test2");
int err=GetLastError();
Alert(val," ",err);

As a result of the code operation (the example can be found in the sGVTestGet1-2 script), the message "0.0 4501" is opened. 0.0 is a value, 4501 is an error code — "Global variable of the client terminal not found". This is not a critical error, but rather notification. You can refer to a non-existent variable if the algorithm permits that. For example, if you want to track the maximum equity:

GlobalVariableSet("max_equity",MathMax(GlobalVariableGet("max_equity",AccountInfoDouble(ACCOUNT_EQUITY)));

The code works correctly even if the "max_equity" variable does not exist. First, the MathMax() function selects the maximum value between the actual equity and the one previously saved in the "max_equity" variable. Since the variable does not exist, we receive the actual equity value.

Global variable names

As we can see, the global variable name is a string. There are no restrictions on the characters for symbol names and their order. Any characters that can be typed on the keyboard can be used in names, including spaces and characters that are forbidden in file names. However, I recommend selecting simple and easily readable names, including characters, numbers and underscore similar to common variables.

There is only one significant limitation, which requires accuracy when selecting names for global variables — name length: no more than 63 characters.

Checking the existence of a variable

The GlobalVariableCheck() function is used to check if the variable exists. A single parameter is passed to the function — the variable name. If the variable exists, the function returns true, otherwise, false. Let's check if the "test" and "test2" variables exist:

bool check1=GlobalVariableCheck("test");
bool check2=GlobalVariableCheck("test2");
Alert(check1," ",check2);

This example can be found in the sGVTestCheck script attached below. "true false" message is received as a result of the script operation — the "test" variable exists, while the "test2" one does not.

Sometimes, the check for a variable existence is necessary, for example, when tracking a minimum equity. If we replace the MathMax() functions with the MathMin() ones in the above example related to tracking the maximum equity, it will work incorrectly and the variable will always contain 0.

In this case, the check for a variable existence can help:

if(GlobalVariableCheck("min_equity")){
   GlobalVariableSet("min_equity",MathMin(GlobalVariableGet("min_equity"),AccountInfoDouble(ACCOUNT_EQUITY)));
}
else{
   GlobalVariableSet("min_equity",AccountInfoDouble(ACCOUNT_EQUITY));

If the variable exists, select the smallest value using the MathMin() function. Otherwise, assign the equity value right away.

Time of a global variable

The global variable time we have already seen on Fig. 3 can be obtained using the GlobalVariableTime() function. A single parameter is passed to the function — the variable name. The function returns the datetime type value:

datetime result=GlobalVariableTime("test");
Alert(result);

The code can be found in the sGVTestTime script attached below. The variable time attribute value is changed only when accessing it, i.e. no other functions can change the variable time value when using the GlobalVariableSet() and GlobalVariableGet() functions. If we manually change the variable via the Global Variables window, its time is changed as well (regardless of whether we change its value or name).

As I have already said, the variable exists four weeks since the last access to it and is automatically deleted by the terminal afterwards. 

Viewing all global variables

Sometimes, we need a global variable not knowing its exact name. We may remember the beginning but not the end, for example: gvar1, gvar2, etc. In order to find such variables, we need to iterate all global variables of the terminal and check their names. To do this, we need the GlobalVariablesTotal() and GlobalVariableName() functions. The GlobalVariablesTotsl() function returns the total number of global variables. The GlobalVariableName() one returns the variable name by its index. A single int type parameter is passed to the function. First, let's have a look at all variables and display their names and values in the message box:

   Alert("=== Start ===");
   int total=GlobalVariablesTotal();
   for(int i=0;i<total;i++){
      Alert(GlobalVariableName(i)," = ",GlobalVariableGet(GlobalVariableName(i)));
   }

The window with all variable names and values is opened as a result (Fig. 5). The code can be found in the sGVTestAllNames script attached below.

 
Fig. 5. The message window containing all global variables of the terminal

Let's add a new check in order to view the variables with certain attributes in names. The following example illustrates a check for variable names to begin with "gvar" (this example can be found in the sGVTestAllNames2 script attached below):

   Alert("=== Start ===");
   int total=GlobalVariablesTotal();
   for(int i=0;i<total;i++){
      if(StringFind(GlobalVariableName(i),"gvar",0)==0){
         Alert(GlobalVariableName(i)," = ",GlobalVariableGet(GlobalVariableName(i)));
      }
   }

The check is performed using the StringFind() function. If you want to improve your skills in working with string functions, read the article MQL5 Programming Basics: Strings.

Deleting global variables

The GlobalVariableDel() function for deleting one global variable receives a single parameter — variable name. Delete the previously created "test" variable (sGVTestDelete script attached below):

GlobalVariableDel("test");

In order to check the operation results, you may use sGVTestGet2-1 or sGVTestGet2-2 script or open the global variables window.

Removal of a single variable is simple, but most often you want to delete more than one variable. The GlobalVariablesDeleteAll() function is used for that. Two optional parameters are passed to the function. If we call the function without parameters, all global variables are deleted. Usually, it is necessary to delete only a group of variables having the same prefix (beginning of a name). The first function parameter is used for specifying the prefix. Let's experiment with this function. First, we should create a number of variables with different prefixes:

   GlobalVariableSet("gr1_var1",1.2);
   GlobalVariableSet("gr1_var2",3.4);   
   GlobalVariableSet("gr2_var1",5.6);
   GlobalVariableSet("gr2_var2",7.8);  

The code creates four variables: the two ones having gr1_ prefix, as well as another two ones with the _gr2 prefix. The code can be found in the sGVTestCreate4 script attached below. Examine the script operation results by launching the sGVTestAllNames script (Fig. 6).

 
Fig. 6. Variables created by the sGVTestCreate4 script

Now, let's delete the variables beginning with gr1_ (sGVTestDeleteGroup script attached below):

GlobalVariablesDeleteAll("gr1_");

After executing the code, view all the variables once again using the sGVTestAllNames script (Fig. 7). We will again see the list of all variables except for the two ones beginning with gr1_.

 
Fig. 7. Variables beginning with gr1_ have been deleted

The second parameter of the GlobalVariableDeleteAll() function is used if you need to delete old variables only. The date is specified in this parameter. If the date of the last access to the variable is less than the specified one, the variable is deleted. Please note that only the variables with a lesser time are deleted, while the ones with a lesser or equal time remain. The variables can be additionally selected by prefix. If selection by prefix is not needed, the default NULL value is set as the first parameter:

GlobalVariablesDeleteAll(NULL,StringToTime("2016.10.01 12:37"));

In reality, deletion of variables by time can be necessary only for solving some very rare and unusual tasks, therefore let me not dwell too much on that topic.

GlobalVariablesFlush function

When closing the terminal, the global variables are automatically saved to the file to be read again by the terminal during its launch. There is no need to know all the subtleties of the process (file name, data storage format, etc.) when using global variables.

In case of the terminal's emergency shutdown, the global variables may be lost. The GlobalVariableFlush() function helps you to avoid this. The function forcibly saves the global variables. After the values are set by the GlobalVariableSet() function or the variables are deleted, simply call the GlobalVariableFlush() function. The function is called without parameters: 

   GlobalVariableSet("gr1_var1",1.2);
   GlobalVariableSet("gr1_var2",3.4);   
   GlobalVariableSet("gr2_var1",5.6);
   GlobalVariableSet("gr2_var2",7.8);   
   
   GlobalVariablesFlush();

The code can be found in the attached sGVTestFlush file. 

It would be good to illustrate the operation of the GlobalVariableFlush() function, but unfortunately, I failed to make the global variables disappear during the terminal's emergency shutdown. The terminal operation was interrupted via the Processes tab of the Task Manager. Perhaps, the global variables may disappear in case of a PC blackout. An unexpected PC blackout happens rarely nowadays, since the vast majority of users have laptops, while desktop PCs usually feature uninterruptible power supply devices. If a terminal works on a dedicated server, then protection against power supply failure is even more significant. Therefore, global variables are quite reliable means for saving data even without the GlobalVariableFlush() function.    

Temporary variable, GlobalVariableTemp function

The GlobalVariableTemp() function creates a temporary global variable (that exists till the terminal is stopped). In a few years that I develop EAs on MQL5, I have never faced the need for such a variable. Moreover, the very concept of a temporary global variable contradicts the basic principle of their application — long-term data storage not affected by the terminal relaunches. But since the function exists in MQL5 language, we should pay it some attention in case you need it.

When calling the function, a single parameter — the variable name — is passed to it. If the variable with such a name does not exist, a temporary variable with the value of 0 is created. After that, use the GlobalVariableSet() function to assign a value to it so that it can be used as usual. If the variable already exists (created by the GlobalVariableSet() function earlier), it is not converted into a temporary one:

   GlobalVariableSet("test",1.2); // set the value variable to make sure the variable exists
   GlobalVariableTemp("temp"); // create a temporary variable
   Alert("temp variable value right after creation - ",GlobalVariableGet("temp"));
   GlobalVariableSet("temp",3.4); // set the temporary variable value
   GlobalVariableTemp("test"); // attempt to convert the "test" variable into a temporary one

This example can be found in the sGVTestTemp file attached below. After launching the script, open the global variables window. It should contain the "temp" variable with the value of 3.4 and "test" with the value of 1.2. Close the global variables window, relaunch the terminal and open the window again. The "test" variable is saved, while "temp" is no more there.

Changing a variable by condition, GlobalVariableSetOnCondition function

Now, it is finally the time to consider the last and, in my opinion, the most interesting function: GlobalVariableSetOnCondition(). Three parameters are passed to the function: name, new value and test value. If the variable value is equal to the test one, it receives a new value and the function returns true, otherwise it returns false (the same happens if the variable does not exist).

In the terms of the operation principles, the function is similar to the following code:

   double check_value=1;
   double value=2;

   if(GlobalVariableGet("test")==check_value){
      GlobalVariableSet("test",value);
      return(true);
   }
   else {
      return(false);
   }

If the "test" global variable is equal to check_value, the value is assigned to it and true is returned, otherwise — false. The check_value variable has the default value of 1, so that false is returned in case the "test" global variable does not exist.

The main objective of the GlobalVariableSetOnCondition() function is to provide consistent execution of several EAs. Since present-day operating systems are multi-task programs, while each EA can be considered a separate thread, no one can guarantee that all EAs will be able to perform all their tasks one after another.

If you have some experience in working with MetaTrader 4, you may remember busy trade flows. Now, several EAs may send trade requests to the server simultaneously and they will be executed, unlike previous times when only one EA was able to send a request at a given moment. If there were several EAs in the terminal, busy trade flow error occurred quite often when executing market operations. When opening and closing orders, the error was more like a nuisance since good EAs were able to repeat their attempts to close or open a position. Besides, different EAs opening or closing positions at the same point in time were quite a rare occasion. However, if a trailing stop function (built into an EA rather than the terminal) was activated at several EAs, only one of them was able to modify its stop loss per tick which was a problem already. Despite the fact there can be no such issue now, there can still be tasks requiring sequential execution of some EAs. 

The mentioned global variable is used to ensure the consistent work of the group of EAs. At the start of the OnTick() function execution, assign value to the variable, so that other EAs can see that some EA is working already and they should either interrupt their OnTick() function or enter the waiting cycle. After the EA completes all necessary actions, we assign check_value to the variable, and now another EA is able to execute its OnTick() function, etc.

The code displayed above is suitable for solving the task but we cannot be sure that the line:

if(GlobalVariableGet("test")==check_value){

will be immediately followed by the line: 

GlobalVariableSet("test",value);

Another EA may interpose between them and start working after detecting check_value. After its task is partially executed, the first EA may continue its operation. Thus, two EAs may work simultaneously. The GlobalVariableSetOnCondition() function solves this issue. As noted in the documentation, "function provides atomic access to the global variable". Atomic means "indivisible". Thus, no other program can interpose during a variable value verification and assigning a new value to it.

The only drawback of the function is that it does not create a variable if the latter does not exist. This means we should carry out an additional check (preferable during the EA initialization) and generate the variable. 

Let's write the two EAs in order to perform an experiment. Both EAs are completely identical. The window with "EA1 start" message appears at the start of the OnTick() function followed by a three-second pause (the Sleep() function). "EA1 end" message appears in the end:

void OnTick(){
   Alert("EA1 start");   
   Sleep(3000);   
   Alert("EA1 end");
}

The second EA is similar, though the messages are different: "EA2 start" and "EA2 end". The attached EAs are named eGVTestEA1 and eGVTestEA2. Open two identical charts in the terminal and attach EAs to them. The message window shows that EAs start and end their work simultaneously (Fig. 8).


Fig. 8. EA messages about the OnTick() function execution start and end

Now, let's apply the GlobalVariableSetOnCondition() function to provide consistent EAs' operation. The inserted changes are identical for both EAs, therefore let's write a code in the included file. The file is called GVTestMutex.mqh (attached below).

Now, let's examine the GVTestMutex.mqh file functions. Check if the global variable exists during the EA initialization and create it if necessary (the Mutex_Init() function). A single parameter — variable name — is passed to the function:

void Init(string name){
   if(!GlobalVariableCheck(name)){
      GlobalVariableSet(name,0);
   }
}

The second function (Mutex_Check()) is used for verification. A cycle waiting for the global variable release is executed in the function. As soon as the variable is released, the function returns true, and the EA goes on executing its OnTick() function. If the variable is not released within a specified time, the function returns false. The OnTick() function execution should be interrupted in that case:

bool Mutex_Check(string name,int timeout){   
   datetime end_time=TimeLocal()+timeout; // waiting end time
   while(TimeLocal()<end_time){ // cycle within a specified time
      if(IsStopped()){
         return(false); // if an EA is removed from a chart
      }
      if(GlobalVariableSetOnCondition(name,1,0)){ 
         return(true);
      }
      Sleep(1); // small pause
   }   
   return(false); // failed to wait for a release
}

The global variable name and waiting time in seconds are passed to the function.

The third function is Mutex_Release(). It sets the value of 0 for the global variable (release) so that other EAs are able to start their work:

void Mutex_Release(string name){
   GlobalVariableSet(name,0);
}

Make a copy of one EA, include a file and add a function call to it. The variable name is "mutex_test". Let's call the Mutex_Check() function with a 30-second timeout. The full EA code is displayed below:

#include <GVTestMutex.mqh>

int OnInit(){
   Mutex_Init("mutex_test");
   return(INIT_SUCCEEDED);
}

void OnTick(){

   if(!Mutex_Check("mutex_test",30)){
      return;
   }

   Alert("EA1 start");
   Sleep(3000);
   Alert("EA1 end");

   Mutex_Release("mutex_test");

}

Let's make a copy of the EA and change the text of displayed messages. The attached EAs are named eGVTestEA1-2 and eGVTestEA2-2. Launch the EAs on two similar charts to make sure they now work in turns (Fig. 9).

 
Fig. 9. The EAs are working in turns

Note the time-out parameter: set the time that exceeds the operation time of all EAs in the group. It may happen that some EA is removed from a chart during the OnTick() function execution but the Mutex_Release() function is not executed. In this case, not a single EA will be able to wait for its turn. Therefore, for the case of time-out expiration, we should set the global variable to 0 or find out some other way to track it. This depends on a specific task. Sometimes, simultaneous EAs' operation may be acceptable, while in some other cases, they should run in turns.

Class for easy work with global variables

Pay attention to the following points in order to work with global variables more conveniently.

  1. Unique variable names are necessary for each EA copy.
  2. Names of the variables used in the tester should be different from the ones used on the account.
  3. If an EA works in the tester, the EA should delete all variables it has created during the test upon completion of each single test run.
  4. Provide more convenient call of functions for working with global variables to make function names shorter.
When using global variables in an EA, it is possible to roughly divide them into two types: common ones and the ones bound to orders. The common ones are used for storing some common data related to the EA operation: for example, a time of some event, maximum profit of a group of positions, etc. Variables bound to orders contain additional data related to a single order (or position): for example, order index in the lot progression series, Open price in a request, etc. Every order has its own unique index — ticket. Therefore, we only need to form a name from the order ticket and the part defining the name of the data saved in the variable (for example, "index", "price"). The order ticket is a ulong type variable with the maximum length of 20 characters, while the maximum variable length is 63 characters meaning that we still have 43 characters.

The situation is a little more complicated when forming names for common variables. Let's make a rough estimation of a possible variable length. The first attribute that we can use to separate the variables of one EA from another is an EA name consisting of, say, 20 characters. The same EAs may work on different symbols. This means that the second unique feature is a symbol (4 more characters). EAs working on a single symbol have different order IDs — magic numbers of ulong types (maximum length — 20 characters). It is possible to switch between accounts from a single terminal. An account number is a long type variable (maximum length — 19 characters). Totally, we receive 63 characters, which comprises the entire permitted variable length, and we have reached only the prefix length!

This means we have to sacrifice something. Let's follow the rule: one terminal only works with one account. If you have multiple accounts, set a terminal instance for each. This means we can rid of the account number, with the maximum prefix size reducing to 43 characters and freeing 20 characters. We may add yet another rule: do not use long magic numbers. Finally, it would be reasonable to pay attention to EA names giving them shorter names. A global variable name formed from the name of an EA, symbol and magic number can be considered acceptable. Perhaps, you will be able to come up with more convenient way of forming names but let's stick to this method in the article.

Let's start writing a class. The class is named CGlobalVariables, the file itself is called CGlobalVariables.mqh and attached below. Declare two variables for prefixes in the 'private' section: the first one — for common variables, the second one — for the ones bound to orders:

class CGlobalVariables{
   private:
      string m_common_prefix; // prefix of common variables
      string m_order_prefix; // prefix of order variables
   public:
      // constructor
      void CGlobalVariables(){}
      // destructor
      void ~CGlobalVariables(){}
}

Let's create the Init() method in the 'public' section. The method is to be called during an EA initialization. The two parameters — symbol and magic number — are to passed to it. Prefixes are to be formed in this method. The prefixes of order variables are simple, as you only need to separate EA variables working on the account from an EA working in the tester. Thus, order variables on the account start from "order_", while the tester ones — from "tester_order_". Only "t_" can be added to the prefix of common variables in the tester (since they are unique, besides we should use characters sparingly). Old global variables should also be deleted during initialization in the tester. Of course, they should be deleted during deinitialization as well, but we cannot be sure in test results as the variables may remain. For now, let's create the DeleteAll() method and call it. I recommend placing the method to the 'private' section. The code for it will be added later. The Init() method code is displayed below:

void Init(string symbol,int magic){
   m_order_prefix="order_";
   m_common_prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"+symbol+"_"+IntegerToString(magic)+"_";
   if(MQLInfoInteger(MQL_TESTER)){
      m_order_prefix="tester_"+m_order_prefix;
      m_common_prefix="t_"+m_common_prefix;
      DeleteAll();
   }         
}

Let's add the method returning the prefix of common variables as it may be useful for some special work involving global variables:

string Prefix(){
   return(m_common_prefix);
} 

Add the basic methods: for checking, setting, receiving values and deleting separate variables. Since we have two prefixes, we should have two methods with name overloading for each function (two functions with he same name but different set of parameters). Only one parameter — variable name — is to be passed to one group of methods. These are the methods for common variables. A ticket and a variable name are passed to another group of functions. These are the methods for order variables:

// for common variables
bool Check(string name){
   return(GlobalVariableCheck(m_common_prefix+name));
}
void Set(string name,double value){
   GlobalVariableSet(m_common_prefix+name,value);      
}      
double Get(string name){
   return(GlobalVariableGet(m_common_prefix+name));
} 
void Delete(string name){
   GlobalVariableDel(m_common_prefix+name); 
}
// for order variables
bool Check(ulong ticket,string name){
   return(GlobalVariableCheck(m_order_prefix+IntegerToString(ticket)+"_"+name));
}
void Set(ulong ticket,string name,double value){
   GlobalVariableSet(m_order_prefix+IntegerToString(ticket)+"_"+name,value);      
}      
double Get(ulong ticket,string name){
   return(GlobalVariableGet(m_order_prefix+IntegerToString(ticket)+"_"+name));
} 
void Delete(ulong ticket,string name){
   GlobalVariableDel(m_order_prefix+IntegerToString(ticket)+"_"+name); 
} 

Let's go back to the DeleteAll() method and write a code for deleting variables by prefixes:

GlobalVariablesDeleteAll(m_common_prefix);
GlobalVariablesDeleteAll(m_order_prefix);  

Deletion can be performed in the tester after testing, so let's add the Deinit() method that is to be called during an EA deinitialization:

 void Deinit(){
    if(MQLInfoInteger(MQL_TESTER)){
        DeleteByPrefix();
    }
 }

In order to improve reliability of the global variables, we should use the GlobalVariablesFlush() function. Let's add yet another method with the function. It is much easier to call the method class rather than write the long name of the function (fulfilling the requirements stated in point 4):

void Flush(){
   GlobalVariablesFlush();
} 

Sometimes, you may need to combine common variables in groups by adding additional prefixes to them and then delete these groups during an EA operation. Let's add yet another DeletByPrefix() method:

void DeleteByPrefix(string prefix){
   GlobalVariablesDeleteAll(m_common_prefix+prefix);
}

As a result, we have obtained sufficient class functionality allowing us to solve 95% of tasks when working with global variables.

In order to use the class, include the following file to an EA:

#include <CGlobalVariables.mqh>

Create an object:

CGlobalVariables gv;

Call the Init() method during an EA initialization by passing a symbol and magic number to it:

gv.Init(Symbol(),123);

Call the Deinit() method during deinitialization to delete the variables from the tester:

gv.Deinit();

After that, all we have to do when developing an EA is to use the Check(), Set(), Get() and Delete() methods passing them a unique part of the variable name only, for example:

   gv.Set("name1",123.456);
   double val=gv.Get("name1");

As a result of the EA operation, the variable named eGVTestClass_GBPJPY_123_name1 appears in the list of the global variables (Fig. 10).

 
Fig. 10. Fragment of the global variables window with the variable created using the CGlobalVariables class

The variable length is 29 characters meaning that we are relatively free in selecting variable names. For order variables, we need to pass an order ticket with no need to constantly form a full name and call the IntegerToSTring() function to convert a ticket into a line, thus greatly simplifying the use of global variables. An example of the class use is available in the eGVTestClass EA attached below.

It is also possible to slightly change the class to simplify its usage even further. Now, it is time to improve the class constructor and destructor. Let's add the Init() method call to the constructor with the appropriate parameters and the Deinit() method call to the destructor:

void CGlobalVariables(string symbol="",int magic=0){
   Init(symbol,magic);
}
// destructor
void ~CGlobalVariables(){
   Deinit();
}

After that, there is no need to call the Init() and Deinit() methods. Instead, we only need to specify a symbol and a magic number when creating a class instance:

CGlobalVariables gv(Symbol(),123);

Conclusion

In this article, we have examined all functions for working with the terminal global variables, including the GlobalVariableSetOnCondition() function. We have also created the class significantly simplifying the use of global variables when creating EAs. Of course, the class does not include all features related to working with global variables but it still has the most necessary and frequently used ones. You can always improve it or develop your own one if necessary. 

Attachments

  • sGVTestCreate — creating a variable.
  • sGVTestGet1 — first method of receiving a value.
  • sGVTestGet2  — second method of receiving a value.
  • sGVTestGet1-2 — first method of receiving a value of a non-existent variable.
  • sGVTestGet2-2 — second method of receiving a value of a non-existent variable.
  • sGVTestCheck — checking the existence of a variable.
  • sGVTestTime — receiving a variable time.
  • sGVTestAllNames — receiving the list of names of all variables.
  • sGVTestAllNames2 — receiving the list of names with a specified prefix.
  • sGVTestDelete — deleting a variable.
  • sGVTestCreate4 — creating the four variables (two groups with two variables each).
  • sGVTestDeleteGroup — deleting one group of variables.
  • sGVTestFlush — forced saving of the variables.
  • sGVTestTemp — creating a temporary variable.
  • eGVTestEA1, eGVTestEA2 — demonstrating a simultaneous EAs' operation.
  • GVTestMutex.mqh — functions for Mutex development.
  • eGVTestEA1-2, eGVTestEA1-2 — demonstrating EAs working in turns.
  • CGlobalVariables.mqh — CGlobalVariables class for working with global variables.
  • eGVTestClass — EA demonstrating how to use the CGlobalVariables class.



Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/2744

Attached files |
files.zip (10.44 KB)
Last comments | Go to discussion (5)
Alain Verleyen
Alain Verleyen | 25 Nov 2016 at 23:00

Good articles for beginners.

The GlobalVariableTemp() function creates a temporary global variable (that exists till the terminal is stopped). In a few years that I develop EAs on MQL5, I have never faced the need for such a variable. Moreover, the very concept of a temporary global variable contradicts the basic principle of their application — long-term data storage not affected by the terminal relaunches.

That's not the only usage of Global Variables of the Terminal. They can also be used to exchange information between different EAs or indicators. So in such case it could be a feature to have data in memory only and not kept of terminal restart.

The mutex part is very interesting, I have one question and one remark.

It may happen that some EA is removed from a chart during the OnTick() function execution but the Mutex_Release() function is not executed.

How an EA could be removed and the Mutex_Release() function not executed ? If you remove an EA from a chart in a normal way (close chart, remove EA, or close terminal), it will never stop the execution flow. I am missing something ?

So my remark, the only way Mutex_Release() could not be executed is with an "hard" stop, power or hardware failure etc..., so that makes your mutex global variables a perfect candidate to be created as a temp using GlobalVariableTemp().

Marcel Fitzner
Marcel Fitzner | 13 Oct 2018 at 10:43

Do global variables work during Strategy Testing?

For example, when an indicator stores values to a GV and an EA reads them, will the Strategy Tester fetch the values during simulation on time?

Keith Watford
Keith Watford | 13 Oct 2018 at 10:47
Admiral Thrawn:

Do global variables work during Strategy Testing?

For example, when an indicator stores values to a GV and an EA reads them, will the Strategy Tester fetch the values during simulation on time?

Yes

Shephard Mukachi
Shephard Mukachi | 14 Mar 2022 at 19:27

Hi  Dmitry,

I realise your article is a few years old, but I thought I might share something and hopefully also ask a question!

So you mention that you have not found use of the Temp Global Var.  I'm developing something that requires that exactly.  I was racking my head trying to figure a way to implement sharing IO Completion Port handle through Global Variables, in particular on crash, or normal restart.  I'm designing an order handling system using Windows IO Completion Ports. Since we can create Win32 threads from MQL5, I cannot create a thread pool while creating the IOCP Server, so my workaround using Services is;

  1. Create an IOCP Server, instead of creating threads(which we cannot), I save the IOCP Handle to a Global Var
  2. I then open at least 2 other Services, which act as Worker Threads, and they read the IOCP Handle from Global Var, and register themselves to the IOCP

In the event of the terminal restarting, abnormally or otherwise, I want that IOCP Handle to have disappeared on terminal start, so I can create a new IOCP Handle for a fresh start. It is makes for a much cleaner implementation.

I was also wondering, how fast are Global Variables, and how reliable are they?

Thanks for the great article.  It was a great read,

Shep


revert_meany
revert_meany | 1 Jan 2023 at 09:14
MetaQuotes:

New article MQL5 Programming Basics: Global Variables of the Terminal has been published:

Author: Dmitry Fedoseev

This what the Python integration needs to send data to and from Python to MLQ EA's. Then an EA developed in Python could be tested in the Strategy Tester, unless there is some impossibility I don't know about.
The 'Turtle Soup' trading system and its 'Turtle Soup Plus One' modification The 'Turtle Soup' trading system and its 'Turtle Soup Plus One' modification
The article features formalized rules of two trading strategies 'Turtle Soup' and 'Turtle Soup Plus One' from Street Smarts: High Probability Short-Term Trading Strategies by Linda Bradford Raschke and Laurence A. Connors. The strategies described in the book are quite popular. But it is important to understand that the authors have developed them based on the 15...20 year old market behavior.
Graphical Interfaces X: The Standard Chart Control (build 4) Graphical Interfaces X: The Standard Chart Control (build 4)
This time we will consider the Standard chart control. It will allow to create arrays of subcharts with the ability to synchronize horizontal scrolling. In addition, we will continue to optimize the library code to reduce the CPU load.
LifeHack for Trader: A comparative report of several tests LifeHack for Trader: A comparative report of several tests
The article deals with the simultaneous launch of Expert Advisor testing on four different trading instruments. The final comparison of four testing reports is provided in a table similar to how goods are represented in online stores. An additional bonus is that distribution charts will be automatically created for each symbol.
MQL5 Programming Basics: Files MQL5 Programming Basics: Files
This practice-oriented article focuses on working with files in MQL5. It offers a number of simple tasks allowing you to grasp the basics and hone your skills.