Designing MQL programs of various types

The program type is a fundamental property in MQL5. In contrast to C++ or other general-purpose programming languages, where any program can be developed in arbitrary directions, for example, by adding a graphical interface or uploading data from a server over the network, MQL programs are divided into certain groups according to their purpose. For example, technical timeseries analysis with visualization is implemented via indicators, but they are not able to trade. In turn, the trading API functions are available to Expert Advisors, but they lack indicator buffers (arrays for drawing lines).

Therefore, when solving a specific applied problem, the developer should decompose it into parts, and the functionality of each part should fit into the specialization of a separate type. Of course, in simple cases, a single MQL program is enough, but sometimes the optimal technical solution is not obvious. For example, how would you implement the plotting of a Renko chart: as an indicator, as a custom symbol generated by the service, or can as specific calculations directly in the trading Expert Advisor? All options are possible.

The type of MQL program is characterized by several factors.

First, each type of program has a separate folder in the MQL5 working directory. We have already mentioned this fact in the introduction to Part 1 and listed the folders. So, for indicators, Expert Advisors, scripts, and services, the designated folders are Indicators, Experts, Scripts, and Services, respectively. The Libraries subfolder is reserved for libraries in the MQL5 folder. In each of them, you can organize a tree of nested folders of arbitrary configuration.

The binary file (the finished program with the extension ex5) — which is a result of compiling the mq5 file — is generated in the same directory as the source mq5 file. However, we should also mention projects in MetaEditor (files with the extension mqproj), which we will analyze in the chapter Projects. When a project is developed, a finished product is created in a directory next to the project. When creating a program from the MQL5 Wizard in MetaEditor (command File -> New), the source file is placed by default in the folder corresponding to the program type. If you accidentally copy a program to the wrong directory, nothing terrible will happen: it will not turn, for example, from an Expert Advisor into an indicator, or vice versa. It can be moved to the desired location directly in the editor, inside the Navigator window, or in an external file manager. In the Navigator, each program type is displayed with a special icon.

The location of a program within the MQL5 directory in a subfolder dedicated to a particular type does not determine the type of this particular MQL program. The type is determined based on the contents of the executable file, which, in turn, is formed by the compiler from property directives and statements in the source code.
 
The hierarchy of folders by program types is used for convenience. It is recommended to stick to it, except when it comes to a group of related projects (with programs of different types), which are more logical to store in a separate directory.

Second, each type of program is characterized by support for a limited, specific set of system events that activate the program. We will see an Overview of event-handling functions in a separate section. To receive events of a specific type in a program, it is necessary to describe a handler function with a predefined prototype (name, list of parameters, return value).

For example, we have already seen that in scripts and services, work is started in the OnStart function, and since it is the only one there, it can be called the main "entry point" through which the terminal transfers control to the application code. In other types of programs, the situation is somewhat more complicated. In general, we note that a program type is characterized by a certain set of handlers, some of which may be mandatory and some are optional (but at the same time, unacceptable for other types of programs). In particular, an indicator requires the OnCalculate function (without it, an indicator will not compile and the compiler will generate an error). However, this function is not used in Expert Advisors.

Third, some types of programs require special #property directives. In the chapter General properties of programs, we have already seen directives that can be used in all types of programs. However, there are other, specialized directives. For example, in tasks with services, that we mentioned, we met the #property service directive, which makes the program a service. Without it, even placing the program in the Services folder will not allow it to run in the background.

Similarly, the #property library directive plays a defining role in the creation of libraries. All such directive properties will be discussed in the sections for the corresponding types of programs.

The combination of directives and event handlers is taken into account when establishing an MQL program type in the following order (top to bottom until the first match):

  • indicator: the presence of the OnCalculate handler
  • library: #property library
  • script: the presence of the OnStart  handler and the absence of #property service
  • service: the presence of the OnStart handler and #property service
  • Expert Advisor: the presence of any other handler

An example of what effect these properties have on the compiler will be given in the section Overview of event handling functions.

For all of the above points, one more point should be taken into account. The program type is determined by the main compiled module: a file with the mq5 extension, where other sources from other directories can be included using the #include directive. All functions included in this way are taken into consideration on the same level as those that are present directly in the main mq5 file.
 
On the other hand, #property directives have an effect only when placed in the main compiled mq5 file. If the directives occur in files included in the program using #include, they will be ignored.

The main mq5 file does not have to literally contain event handler functions. It is perfectly acceptable to place part or all of the algorithm in mqh header files and then include them in one or more programs. For example, we can implement the OnStart handler with a set of useful actions in an mqh file and use it via #include inside two separate programs: a script and a service.

Meanwhile, let's note that the presence of common event handlers is not the only motive for separating common algorithm fragments into a header file. You can use the same calculation formula, for example, in an indicator and in an Expert Advisor, leaving their event handlers in the main program modules.

Although it is customary to refer to include files as header files and give them the mqh extension, this is not technically necessary. It is quite acceptable (although not recommended) to include another mq5 file or, for example, a txt file in one mq5 file. They may contain some legacy code or, let's say, initialization of certain arrays with constants. The inclusion of another mq5 file does not make it the main one.
 
You should make sure that only the event-handling functions characteristic of the specific program type get into the program, and that there are no duplicates among them (as you know, functions are identified by a combination of names and a list of parameters: function overload only allowed with a different set of parameters). This is usually achieved using various preprocessor directives. For example, by defining the macro #define OnStart OnStartPrevious before including a third-party mq5 script file in some of our programs, we will actually turn the OnStart function described in it into OnStartPrevious, and we can call it as usual from our own event handlers.
 
However, this approach makes sense only in exceptional cases when the source code of the included mq5 file cannot be modified due to some reason, in particular, when it cannot be structured with the selection of algorithms of interest into functions or classes in separate header files.

According to the principle of interaction with the user, MQL programs can be divided into interactive and utilitarian ones.

Interactive programs — indicators and Expert Advisors — can process events, which occur in the software environment in response to user actions, such as pressing buttons on the keyboard, moving the mouse, changing the window size, as well as many other events, for example, related to receiving quote data or to timer actions.

Utility programs — services and scripts — are guided only by input variables set at the time of launch, and do not respond to events in the system.

Apart from all types of programs are libraries. They are always executed as part of another type of MQL program (one of the four main ones), and therefore do not have any distinctive characteristics or behavior. In particular, they cannot directly receive events from the terminal and do not have their own threads (see next section). The same library can be connected to many programs, and this happens dynamically at the time of the launch of each parent program. In the section on libraries, we'll learn how to describe a library's exported API and import it into a parent program.