Changing the External Parameters of MQL4 Programs without Restarting

Alexey Koshevoy | 8 September, 2008

Introduction


Everybody who had ever launched an EA or an indicator for execution, faced the possibility to preliminarily set up external parameters that often underlay the success of the program. There is a possibility to change parameters during the program operation. But how can that be done without initialization? In some cases, this may affect managing the previously opened orders. In this article, we try to solve this problem as flexibly as possible.

Problem Statement

We will consider this problem for Expert Advisors rather than for indicators. For indicators, this problem is not so acute, although the methods are universal and you can apply them to any programs.

In the classical EA writing, the context must be created at every tick. There can be two kinds of contexts - the context of status and trading context. The context of status contains the current states of indicators and other elements underlying the decision making on opening/closing/modifying orders. Trading context contains the information about open orders, their statuses and quantities. After trading context has been analyzed, traders make decisions about what to do with their orders. Contexts are divided by types conditionally. This classification has been introduced for convenience.

If the context can be restored at each tick, the problem doesn't arise. You can freely change external parameters, and your EA will continue operating according to its logic. First, there will be initialization, then the EA will calculate the values of indicators, "take up" open orders and perform a number of operations according to the information collected. Everything is easy and transparent.

Now let's consider situation where a more precise parameter changing technology is necessary that won't result in the full program restart.

Example 1.
Among our open orders, there are some processed for in a special way. I.e., we need to find them among other orders opened by our EA. For this purpose, we can use some parameters: Ticket, Magic Number, Currency, Comment. Magic Number is used to separate our orders for others opened in the system by other EAs or manually. 'Currency', in addition to 'Magic Number', allows us to use the same EA for different currency pairs. There remain only two parameters that can be unique for each order. 'Comment' is the most suitable one, it can contain any textual information, but has a disadvantage – it can be modified on the server side, for example, at partial closing. 'Ticket' is unique for each order, but the ticket number alone is not sufficient to divide orders by classes, so the tickets of orders must be compared to some other information. As we can see, in this situation, it would be most convenient to use the 'Ticket' parameter and store the tickets according to the order classes. Accordingly, at restart, the array containing tickets will get lost, so we will not be able to restore information about the virtual classes of orders.

Example 2.
A universal mechanism is developed that allows us to analyze the changes in the statuses of orders. I.e., we have two contexts of order statuses. The first list is at the current tick, while the second one is at the previous tick. On analyzing the information, we can make the conclusions about which order has been opened/modified/closed and about the reasons for such operations. This method is very comfortable for both EA debugging and trading logic developing. However, its disadvantage is that it is necessary to save the order statuses at the preceding tick. Correspondingly, this data will get lost at the EA restart.

Example 3.
An EA is receiving external data. It doesn't matter in what way or from where the data is arriving. It is important that, if we need to accumulate this data for processing and cannot request its history, then we will have to create context during the entire work of the EA. Changing external parameters will result in restarting the system and we will have to accumulate data from an external source again.

Example 4.
An MQL4 program is distributed as a compiled file. Thus, the users cannot change its code or see your algorithms. It is a great protection of your intellectual property. However, the program may have some external variables, and it is not very comfortable to change them each time instead of making it once and compile with the new values. Although this example does not directly concern the problem of context storage, is very typical in light of the problem to be solved here.

When creating EAs, you should construct your logic in such a way that to avoid storing the context during operations. Such development may be much more complicated, in this case, but the system will be as stable as possible. If, however, we cannot avoid storing the context, the method under consideration will help us to flexibly manage the EA settings without losing the data at changing its parameters.

Application

To solve the problems in the above examples, let's develop a complex that would manage the external parameters of MQL4 programs. What can be done using such a system?

By definition, we can change the external parameters of all types:

• Integer
• Bool
• Double
• String
• Datetime

However, we shouldn't be satisfied with what has already been achieved. To realize the whole potential of this approach, we should consider the operation principles of the system on a very simple example.

The complex works as follows. At the stage of initialization, the MQL4 program saves all values that can be changed by the user into the corresponding file. The external program opens this file, reads the data, places it on the screen, and then the user starts working. As soon as the user changes one of the parameters in the external program, the file is modified. I.e., the new value set by the user will be written instead of the old one. Then the MQL4 program, at function 'start' call, will check the data file for changed values and, if any changes have been found, call to the corresponding functions. Functions processing the changes in external values execute some preset algorithms. In most cases, it will be sufficient just to assign the new values to the variable. This is how one cycle of the external parameters changing complex approximately works.

From the example above, we can see that the creation of stable dialog between the MQL4 program and an external program is most important for the complex to work successfully. Now we have to choose the means and methods to organize the dialog. However, even for a simplest approach without using DLLs, we can allow ourselves more than only changing external parameters.

Let's consider some examples that reveal additional features of this approach. Since we have a bilateral dialog, the MQL4 program can reply to the request from an external program.

For example, a user changes the value of a variable. The external program writes to file the new value of the variable and changes the status of this variable for "waiting for an action from the MQL4 program". When processing the file, the MQL4 program considers only variables that have this status, other ones were not changed. At processing the found variable, it changes the status for "changes accepted". Thus, in an external program, we can see when the change has been performed directly in the MQL4 program. It's a useful function for monitoring.

Let's try to realize the function of "action". We need that changing a variable in an external program does not result in changing the corresponding variable in an MQL4 program, but in executing a certain action only once. This can be realized as follows. The variable is changed in an external program. The variable can takes the values of 0 and 1. If the value is 1, the MQL4 program executes a certain action and assigns the value of 0 to the variable. Now this action can be performed again from an external program. This is more than just changing variables. Using the actions, we can realize many useful functions. The actions are very much the same as MQL4 scripts, but have a significant difference. A script can be executed at any moment of the MetaTrader4 client terminal operation, whereas an action can only be performed as soon as the 'start' function is called, i.e., at the moment of the current price changing.

At the end, we can consider an example of how to use the method for transferring data from an external source into an MQL4 program. Suppose we don't need to change any external variables, but an MQL4 program, or rather an EA, must be managed from an external source. The external source processes the data, makes calculations, and, basing on the obtained results, makes a decision about opening/closing orders. To open an order, it is necessary to pass the main parameters and the opening command to the program. The order parameters have the "waiting" status, since their changing should not force the program to execute the actions. In this example, it is the action variable that is the event for reading the order opening parameters.

We considered three aspects in using the complex. The first one is passing parameters with the statuses in one direction from an external program into an MQL4 program. In this case, the dialog is realized through changing the value of the status. The second one is the request for performing certain actions. In the dialog, both the value of the variable and the value of status are changed. The third and the simplest aspect is extracting the event information stored in the file. No dialog is used.

Developing the Complex

To develop the complex, we should solve a number of problems. First of all, we should develop the document structure for transferring information between programs. Then we should select a protocol to transfer this document. Finally, we should write libraries for working with the system using MQL4 or any other programming language suitable for a specific external program.

Developing the Document Structure
Developing the document structure is one of the most important tasks for the complex. The document must reflect all aspects described above.

For information storage, using the XML technology would be the most universal approach. However, there rises a number of problems. First of all, MQL4 doesn't have any embedded means to work with XML. Second, if we use working with XML through DLLs, then the entire system will become several times more complicated. So let's use a standard text file and our own structure of data representation.

The main objective of the document is a variable or a value. The value has a well-defined structure consisting of the following elements:

• Title
• Type
• Status
• Value

Let's consider them one by one:

Title – the name of the variable. It is used by programs to identify the object.

Type – the type of the variable. According to the variable type, the processing logic will change. The types are specified by numeric values.

Type Description Analog in MQL Value
0Boolean or logical
bool0 – false, 1 - true
1StringstringA set of characters.
2Integer characterintBoundary values correspond with the MQL4 rules.
3Real characterdoubleBoundary values correspond with the MQL4 rules. Delimiter is the point.
4DatedatetimeThe format of recording corresponds with the MQL4 rules.
5Actionno equivalent0 – no execution is required, 1 - execution is required.


Status – a status variable. It is specified by a numeric value. Let's consider a table of possible variations:

Value Description
0Waiting. No processing is required.
1Request for changing. The MQL4 program must response to this status value.
2No processing is required. It is a value for variables that must be processed for an event other than direct changing the variable.

Value – the value of the variable. The rules of recording the value depend on the variable type.
Parameters interaction.

External program. Changing the value.

If Status=0, then for changing the value of 'Value' the value of Status=1.
If Status=1, then for changing the value of 'Value' the value of 'Status' does not change.
If Status=2, then for changing the value of 'Value' the value of 'Status' does not change.

External program. Canceling changing the value.

There are situations where a value is changed by mistake or replaced with a wrong value, or the user changed his/her mind towards changing the value after having confirmed the changes. Let's consider the possibility to cancel this procedure. However, it must be taken into consideration that, if the MQL4 program has already processed the file containing changes, nothing can be conceled

If Status=1, then the 'Value' is changed for the previous one, and Status=0.
If Status=2, then the 'Value' is changed for the previous one, but the value of 'Status' does not change.

MQL4 program. Processing changes.

MQL4 program considers changes only if variable 'Status' is equal to 1. By definition, it doesn't matter what variable type has been changed, since we are calling to the processing function for each change. The difference is only in where the 'Value' will have a value or not, i.e., whether the variable change is a change or a request for execution of an action. Let's consider this in details.

If Status=1 and 'Type' ranges from 0 to 4, then use 'Value' and change the 'Status' for 0.
If Status=1 and Type=5, then execute an action and change the 'Status' for 0 and change the 'Value' for 0.
If in the course of executing the action we use additional values with Status=2, then the value of 'Status' does not change after use.

Let's consider some examples.

Example 1. Changing a Variable.
Let's have variable Var1 of the Integer type with the value of 10. The variable is in the "waiting" status.

Title=Var1
Type=2
Status=0
Value=10

In the external program, change the value of Var1 for 30. Now we have:
Title=Var1
Type=2
Status=1
Value=30

The value of 'Value' has changed, as well as the value of the 'Status' has changed for "request for changes processing".

The MQL4 program detects the changes, calls to the necessary function, and modifies the document:
Title=Var1
Type=2
Status=0
Value=30

The value of 'Value' has been accepted and the value of the 'Status' has changed for "waiting".

Example 2. Executing an action.
Let's have variable Var2 of the Action type. The variable is in the "waiting" status.

Title=Var2
Type=5
Status=0
Value=0

In the external program, change the value of Var2 for 1. Looking a bit ahead, we can say that, in order to avoid errors at assigning a wrong value to the action variable in the external program, we use a button, not an input field. Now we have:
Title=Var2
Type=5
Status=1
Value=1

The value of 'Value' has been changed, as well as the value of the 'Status' has changed for "request for changes processing".

The MQL4 program detects the changes, calls to the necessary function, and modifies the document:
Title=Var2
Type=5
Status=0
Value=0

The value of the 'Value' has changed for 0, while the value of the 'Status' has changed for "waiting".
We can see that, at executing an action, both the value of 'Status' and the value of 'Value' will change. If the variable is changed, only the value of the 'Status' will change, too, while the value of the variable remains the same.

Choosing a Transfer Protocol
Among many means of data transferring between an MQL4 program and an external program, we choose file. Using a file does not require the development of additional libraries for MT 4. The method is rather universal, small-footprint, and simple in its realization. It has a number of disadvantages that can be easily eliminated and has no critical limitations.

MQL4 program can response to the changes in the file of variables only upon a certain event, namely: upon changing of the current price on the current currency pair.

We can initiate checking the file of variables from an external program at any time. We should select optimal time intervals for checking, in order not to overload the resources of our PC and not to occupy the file for a long period of time, since it can be simultaneously used by the MQL4 program. The changes in the external program are mainly made by man, i.e., not so quickly as by a computer, so it would be enough to check the file not frequently than once half second to track the situation. This parameter, of course, must be adjustable, and you should empirically choose the time interval for yourself.

During the attempt to open the file with the MQL4 program, it can be opened by the external program for writing. Therefore, we should foresee such a situation and realize several attempts to call to the file within one processing, in order not to waste our time waiting for a new price change. The same relates to the external program: If the file is used by the MQL4 program, you should take several attempts to call to the file by certain time intervals.

Adaptation to MQL4

Variables

int    ExVH_VarCnt;
string ExVH_FileName;
string ExVH_Project;
 
string ExVH_Title[];
string ExVH_Type[];
string ExVH_Status[];
string ExVH_Value[];

Functions for User

bool ExVH_Open(string FileName)
{
   bool Result=true;
   ExVH_FileName=FileName;
   if (!ExVH_i_Load())
      Result=false;
   if (Result)
      if (!ExVH_i_GetVarCnt())
         Result=false;
   if (Result)
      ExVH_i_Disassemble();
   return(Result);
}
 
int ExVH_Close()
{
   ExVH_i_Assemble();
   ExVH_i_Save();
 
}
 
int ExVH_GetStatus(int Id)
{
   if ((Id<1)||(Id>ExVH_VarCnt))
      return(-1);
   else
      return(StrToInteger(ExVH_Status[Id-1]));
}
 
int ExVH_SetStatus(int Id, int Status)
{
   int Result;
   if ((Id<1)||(Id>ExVH_VarCnt))
      Result=-1;
   else
   {
      Result=1;
      ExVH_Status[Id-1]=Status;
   }
   return(Result);
}
 
string ExVH_GetValue(int Id)
{
   if ((Id<1)||(Id>ExVH_VarCnt))
      return("N/A");
   else
      return(ExVH_Value[Id-1]);
}

Function for Internal Use

bool ExVH_i_Load()
{
   bool Result=true;
   ExVH_Project="";
   int i=0;
   int FS=0;
   int handle;
   int Buf[];
   handle=FileOpen(ExVH_FileName,FILE_BIN|FILE_READ);
   if(handle>0)
   {
      FS=FileSize(handle);
      ArrayResize(Buf,FS);
      while(!FileIsEnding(handle)) 
      {
         Buf[i] = FileReadInteger(handle, CHAR_VALUE);
         i++;
      }
      
      FileClose(handle);
      string Str="";
      for (i=0;i<FS;i++)
         Str=Str+CharToStr(Buf[i]);  
      ExVH_Project=Str;
   } else 
      Result=false;
   return(Result);
}
 
bool ExVH_i_Save()
{
   bool Result=true;
   int handle=FileOpen(ExVH_FileName,FILE_BIN|FILE_WRITE);
   if(handle>0)
   {
      FileWriteString(handle,ExVH_Project,StringLen(ExVH_Project));
      FileClose(handle);
   } else
      Result=false;
   return(Result);
}
 
bool ExVH_i_GetVarCnt()
{
   bool Result=true;
   string Value=ExVH_i_GetVarValue("Var_Cnt");
   if (Value=="N/A")
      Result=false;
   else
      ExVH_VarCnt=StrToInteger(Value);
   return(Result);
}
 
void ExVH_i_Disassemble()
{
   int i;
   ArrayResize(ExVH_Title, ExVH_VarCnt);
   ArrayResize(ExVH_Type, ExVH_VarCnt);
   ArrayResize(ExVH_Status, ExVH_VarCnt);
   ArrayResize(ExVH_Value, ExVH_VarCnt);
   
   for (i=0;i<ExVH_VarCnt;i++)
   {
      ExVH_Title[i]=ExVH_i_GetVarValue("Var"+(i+1)+"_Title");
      ExVH_Type[i]=ExVH_i_GetVarValue("Var"+(i+1)+"_Type");
      ExVH_Status[i]=ExVH_i_GetVarValue("Var"+(i+1)+"_Status");
      ExVH_Value[i]=ExVH_i_GetVarValue("Var"+(i+1)+"_Value");
   } 
}
 
void ExVH_i_Assemble()
{
   ExVH_Project="[ExVH 1.0]\r\n\r\n";
   ExVH_Project=ExVH_Project+"Var_Cnt="+ExVH_VarCnt+"\r\n\r\n";
 
   int i;
   for (i=0;i<ExVH_VarCnt;i++)
   {
      ExVH_Project=ExVH_Project+"Var"+(i+1)+"_Title="+ExVH_Title[i]+"\r\n";
      ExVH_Project=ExVH_Project+"Var"+(i+1)+"_Type="+ExVH_Type[i]+"\r\n";
      ExVH_Project=ExVH_Project+"Var"+(i+1)+"_Status="+ExVH_Status[i]+"\r\n";
      ExVH_Project=ExVH_Project+"Var"+(i+1)+"_Value="+ExVH_Value[i]+"\r\n\r\n";
   } 
}
 
string ExVH_i_GetVarValue(string VarName)
{
   string Result="N/A";
   int Start,Stop;
   VarName=VarName+"=";
   Start=StringFind(ExVH_Project,VarName,0);
   if (Start!=-1)
   {
      Start=Start+StringLen(VarName);
      Stop=StringFind(ExVH_Project,CharToStr('\n'),Start);
      if (Stop!=-1)
      {
         Stop=Stop-1;
         Result=StringSubstr(ExVH_Project,Start,Stop-Start);
      }
   }
   return(Result);
}

Adaptation for C++

The project was written in C++ Builder 2007. The archive of source codes named ExVH_CPP.zip is attached to the article.

Testing

Let's realize a small demonstrative example that will show most possibilities.
Thus, let's create a test document:


[ExVH 1.0]

Var_Cnt=5

Var1_Title=Boolean test
Var1_Type=0
Var1_Status=2
Var1_Value=0

Var2_Title=String test
Var2_Type=1
Var2_Status=2
Var2_Value=Hello world!

Var3_Title=Integer test
Var3_Type=2
Var3_Status=0
Var3_Value=12345

Var4_Title=Double test
Var4_Type=3
Var4_Status=0
Var4_Value=123.45

Var5_Title=Action test
Var5_Type=5
Var5_Status=0
Var5_Value=0

Let's save the document as ExVH.evh in folder [MetaTrader]/experts/files/.

Signature [ExVH 1.0] allows us to recognize the document when opening the file and informs about the version of the document structure used. If the document structure changes, the signature must be changed, too. This will allow us to avoid mixing, considering that the document file extension will remain unchanged.

Var_Cnt=5. This record informs us about that the document contains 5 variables.

Then the records of the same type follow that contain the information of each variable. The records are made according to the above specifications.

VarX_Title=
VarX_Type=
VarX_Status=
VarX_Value=

Thus, we have two variables (Var1 and Var2) that must be read as soon as an action appears (Var5), and two variables (Var3 and Var4), the changes of which must be considered independently.
The MQL4 program must display the corresponding message on the screen as soon as changes are made in the variables.


Test MQL4 Code

int init()
{
   return(0);
}
 
int deinit()
{
   return(0);
}
 
int start()
{
   if (!ExVH_Open("ExVH.evh"))
      return(0);
   
   // Checking for action status
   if (ExVH_GetStatus(5)==1)
   {
      Alert("Actioned!");
      string VarValue;
      if (ExVH_GetValue(1)=="1")
         VarValue="true";
      else 
         VarValue="false";
      
      // Boolean variable value
      Alert("Boolean test variable="+VarValue);
      
      // String variable value
      Alert("String test variable="+ExVH_GetValue(2));
      
      ExVH_SetStatus(5,0);
   }
   
   // Integer variable value
   if (ExVH_GetStatus(3)==1)
   {
      Alert("Integer test variable has been changed. New value="+ExVH_GetValue(3));
      ExVH_SetStatus(3,0);
   }
   
   // Double variable value
   if (ExVH_GetStatus(4)==1)
   {
      Alert("Double test variable has been changed. New value="+ExVH_GetValue(4));
      ExVH_SetStatus(4,0);
   }
   
   ExVH_Close();
   return(0);
}


Launching and Testing
It doesn't matter what part of the complex is launched first. Let it be MetaTrader 4, in this case. Preliminarily copy file ExVH_Demo.mq4 into folder [MetaTrader]/experts/ and then start Terminal. Document ExVH.evh has already been written in the program code. Launch the EA. Nothing should happen since the EA will be waiting for changes in the file.

Launch ExVH.exe preliminarily installed on the PC.


General View of the Program



Open the 'Project' and select the 'Open' item…


Opening the Document



The program loads variables and now we can change them.

In the 'Status' column, two values are reflected: idle (waiting) and Changed by ExVH (changes were made in an external program). This is how the screen looks after we have activated our 'Action'.


General View of the Program with Activated 'Action'



Changes for different types of variables are made in different ways.

For a boolean variable, the program gives one of the two messages:





For 'Action' activation, it give this:





For all other types of variables, a unified separate form.


Form for Changing the Values of Variables



After a number of changes, the 'Alert' window in the terminal may appear as follows:


Example Message Box during the Program Operation


Disadvantages

Any good idea may have its advantages and disadvantages.


• This method cannot be actively used for back-testing.
• Changing the parameters can contradict the logic of your EA. You should process the changes in variables very carefully. It's rather a feature than a disadvantage.
• Execution of commands is only possible on the arrival of a new tick.

What Else Can Be Done

The functionality of the system can be enhanced in various directions. The field of action is practically boundless.

• Changing parameters according to different scenarios. For example, for passwords, you can have a possibility to hide the information entered.
• Storage of the file enciphered to be able to hide passwords.
• You can change the data transferring protocol making it more reliable and secured.

Conclusion


We considered the ways of changing the values of internal variables in MQL programs. Now we have an opportunity to manage external and other variables without restarting the program.

Files Attached to the Article

File Description
ExVH_Demo.mq4Test EA
ExVH_Project.zipPrepared project file
ExVH_CPP.zipSource codes of the external program
ExVH_Install.zipExternal program installer

Note. ExVH_Install was made using the demo version of the Advanced Installer program.