Operations with Charts
In his or her practical work, a trader usually opens in a symbol window several subwindows that display indicators. There are no limitations on placing indicators, they can be attached in any sequence. The amount of subwindos in a symbol window is not limited either. Each subwindow has its number.
The main window containing a price chart is always available, its number being
0. Each indicator subwindow has a number, as well. The subwindows are numbered in a simple sequence - they are numbered by their displaying in the symbol window from top to bottom: the indicator subwindow closest to the main window has number 1, the next lower one has number 2, the next one has number 3, etc.
Fig. 140. Subwindow locations in the symbol window.
The amount of subwindows can be easily calculated using the following function:
The function returns the amount of indicator subwindows located in the chart, including the main chart window. The largest number (of the lowest subwindow) is always 1 less than the total amount of subwindows (including the main window numbered as 0) in the symbol window. If, in the situation shown in Fig. 140, we call for execution the function WindowsTotal() from any application, the returned value will be equal to
3, while the largest number (of the lowest subwindow) is 2.
The numbering sequence described above is kept, if a new indicator subwindow is added to or an existing subwindow is deleted from the
symbol window. If you add a new subwindow, it will be displayed below all other subwindows and its number is 1 more than that of the last window above it. If you delete a subwindow from the symbol window, all subwindows below it will be automatically renumbered
- the number of each of them will be decreased by 1.
In MQL4, it is possible to create graphical objects (and change their properties)
in any of the existing subwindows. For this purpose, in the function ObjectCreate() the parameter 'window' is provided, according to which an object is created in the given subwindow
of the symbol window. The current number of the subwindow can be calculated using the following function:
int WindowFind(string name)
The function returns the number of the chart subwindow that contains the indicator named as 'name', if it has been found. Otherwise, it returns -1. The function will also return -1, if a custom indicator searches for itself during initialization init().
name - short name of the indicator.
The amount of subwindows in a symbol window can change at any moment, if the user deletes an indicator. This is why the algorithm of an application that supports monitoring of graphical objects must continuously track the numbers of windows, in which the indicators are displayed.
||Problem 34. Using graphical objects, display the messages informing about data received from two indicators.
If the corresponding indicator is attached to the symbol window, display the graphical object in the indicator window. Otherwise, display it in the main window.
To solve the problem, let's choose indicators RSI and Momentum. The general algorithm of building an Expert Advisor comes down to this. In the function init(), you can specify texts to be displayed on the screen according to the indicator readings, i.e., make the calculations to be executed only once in the program. In the function start(), you should calculate the indicator readings, detect the availability of necessary subwindows and their numbers, and then, according to the situation, display one or another message in one or another subwindow.
At the execution of the function deinit(), it is necessary to delete all graphical objects created during the work of your program. Below is the EA named charts.mq4 that controls graphical objects in the subwindows of a symbol window.
Text= "RSI(14) is below 30. Buy";
Text= "RSI(14) is above 70. Sell";
Text= "RSI(14) is between 30 and 70";
Text= "Momentum(14) is growing";
Text= "Momentum(14) is sinking";
if(RSI < 30)Ind_RSI=0;
if(RSI > 70)Ind_RSI=1;
if(Mom_0 < Mom_1)Ind_Mom=4;
int Create_RSI(int Win)
ObjectCreate("Obj_RSI",OBJ_LABEL, Win, 0,0);
ObjectSet("Obj_RSI", OBJPROP_CORNER, 0);
ObjectSet("Obj_RSI", OBJPROP_XDISTANCE, 3);
int Create_Mom(int Win)
ObjectCreate("Obj_Mom",OBJ_LABEL, Win, 0,0);
ObjectSet("Obj_Mom", OBJPROP_CORNER, 0);
ObjectSet("Obj_Mom", OBJPROP_XDISTANCE, 3);
Prior to considering the code above, we should explain the specifics of the program operation. A graphical object once created (in this case, one displaying a text) is supposed to be present in the screen continuously. Its textual description is supposed to characterize the situation. The content of the textual description must be changed at the execution of the function start(), at every tick. At the same time, when switching between timeframes for the window, to which the EA is attached, the program goes through the following stages: deinit(), init(), (awaiting a tick), and start(). If the object is first time created during the execution of start(), then, every time when switching to another timeframe, a certain period of time will lapse before the object appears, the time period being equal to that of awaiting the next tick. This is very inconvenient, particularly, when timeframes are often switched between.
In a properly built program, the necessary messages are displayed on the screen at the moment of attaching the program to the symbol window or at the moment of timeframe switching (i.e., before a new tick incomes). For this purpose, as a rule, it is necessary to perform all actions to be performed at every tick at the launching of the special function start() at the stage of the execution of the special function init(). In order not to repeat the same program code in different special functions, the code can be organized as a separate function. For this purpose, the EA contains the user-defined function Main(). It is called to be executed once at the stage of initialization (block
2-3) and at every tick during the further work of the EA (block 3-4).
In the program (block 11-13), there are two more user-defined functions - Create_RSI()
and Create_Mom() intended for creation and modification of the object properties. At the execution of the function init(), the necessary objects are created using these functions. The call to the function Main() results in giving necessary properties to the objects (the objects with the desired description of the desired color are displayed in the desired window).
Let's consider the function Main() (block 5-11) in more details. In block 6-7, the readings of the indicator RSI are calculated. Depending on whether the end of the indicator line is above 70, below 30, or within the range between these indexes, one or another value will be assigned to the variable Ind_RSI. Then this value is used as an index of arrays
Color and Text (in block 7-8) to change the properties of the graphical object of the name
Block 7-8. The number of RSI window is calculated in the line:
Win_RSI_new = WindowFind("RSI(14)");
The string value RSI(14) is used as the transferred parameter. This is the short name of the indicator, the number of which should be detected. In this case, the entire sequence of characters in the given line, including parentheses and digits, composes the name.
It must be noted that, in general case, there can be several indicators of the same type in the symbol window, for example, RSI(14), RSI(21) and RSI(34). Each subwindow displaying these indicators has its own number. This is why technical indicators are developed in such a way that each of them forms its short name according to the preset values of adjustable parameters. The short name of each technical indicator coincides with that shown in the upper left corner of its subwindow (the short name of a custom indicator may be created by the programmer using the function IndicatorShortName()).
If the searched indicator is not placed in the symbol window, the variable
Win_RSI_new (the number of the subwindow, in which this object must be displayed at the current moment) will take the value of -1, i.e., non-existing window. In this case, the program implies displaying of the graphical object in the main chart window, the number of which is always 0:
if(Win_RSI_new == -1) Win_RSI_new=0;
During his or her operations, the user may place a missing indicator or delete an existing one. In order to find out about what actions should be performed, the program uses global variables Win_RSI_old and Win_Mom_old. The value of each variable is the number of the subwindow, in which the object has previously been created. If the values of the variables Win_RSI_new and Win_RSI_old don't coincide, this means that the indicator window is either added (it didn't exist before) or deleted (it was available on the previous tick).
In both cases, the previously created object must be deleted, and a new one must be created in the desired window:
After the object has been created in the window numbered as Win_RSI_new, the value equal to the number of this window is assigned to the variable Win_RSI_old, i.e., the program remembers the number of window, in which the graphical object was created:
Win_RSI_old = Win_RSI_new;
If the values of the variables Win_RSI_new and Win_RSI_old coincide, it means that it is sufficient to assign a textual description to the object (that is now placed in the necessary window).
It must also be done, in case of creating a new object:
Similar calculations are made for the other subwindow, that of indicator Momentum (blocks
8 - 10). At the end of the function Main(), all available graphical objects are redrawn as a result of the execution of WindowRedraw().
It's easy to see that programmed control over graphical objects in subwindows implies using global variables (you can also use 'static'). In such cases, when coding a program, you should pay a special attention to what values can be taken by global variables in different situations and what this can result in. In the program considered above, global variables are zeroized in the function init():
Win_RSI_old = 0;
Win_Mom_old = 0;
These lines are included into the program due to the fact that global variables
lose their values, only if the user has stopped the execution of the application program in the symbol window. However, if the user has adjusted external variables or switched the timeframe, the program undergoes deinitialization and the consequent initialization, the values of global variables being saved.
Let's consider the operations of the program that doesn't contain these lines. Suppose, both indicators with the subwindow
numbers 1 and 2, respectively, have been placed in the symbol window by the moment when the user switches the timeframe. In the considered example, when deinitializing the program, the graphical objects are deleted. At the execution of the special function init(), the objects are created in zero window. Then, at the execution of the function Main(), in blocks 7-8 and 9-10, the program compares the obtained number of the window, in which the objects must be placed, and the number of the window, in which the objects were at the preceding tick. In fact, the object has already been placed in zero window, but the values of global variables will say for other result: their numbers will be 1 and 2. As a result, the graphical objects will remain in the main window, until the user deletes and reattaches the corresponding indicators. As to prevent these undesirable developments, the program implies nulling of global variables at the execution of the function init().
Thus, the values of these variables are made correspond with the situation.
As a result of the execution of EA charts.mq4, the following combinations of windows and graphical objects displayed can appear:
Fig. 141. Displaying graphical objects in the subwindows of a symbol window.
If there are both indicators in the symbol window, the corresponding graphical objects will be shown in their subwindows. If no one of these indicators is placed, then both objects will be created by the program in the main window. Adding or deletion of either indicator, the name of which is processed in the program, will result in moving of the corresponding graphical object into the necessary window. Adding or deletion of other indicators from the symbol window will not entail any consequences.
It must be noted separately that the alternative of deleting a graphical object by the user is not considered in this program. A program used in your practical trading must contain the analysis of such situation with the subsequent restoring of the object (see the solution of Problem 33).
Functions Used in Operations with Charts
||The function puts a flag of hiding the indicators called by the Expert Advisor. At the opening the chart after testing, the indicators marked with the hiding flag will not be shown in the test graph. Before each call, the indicator is marked with the currently set hiding flag (only the indicators that are directly called from the EA under test can be displayed in the test graph).
||It returns the value of the amount of the period minutes for the current chart.
||Updating data in the predefined variables and timeseries arrays. This function is used, when an EA or a script has been calculating for a long time and needs updated data. It returns TRUE, if the data updating succeeds. Otherwise, it returns FALSE. The data may remain outdated only if they correspond with the current state of the client terminal.
||It returns a text line with the name of the current symbol.
||The function returns the amount of bars fitting in the window of the current chart.
||It returns the name of the executing EA, script, custom indicator or library, depending on the MQL4 program, from which this function has been called.
||It returns the number of the chart subwindow that contains the indicator with the given name 'name' if it has been found. Otherwise, it returns -1. WindowFind() returns -1, if the custom indicator is searching for itself during initialization init().
||The function returns the number of the first visible bar in the window of the current chart. You should consider that price bars are numbered in a reversed order, from the last to the first one.
The current bar, which is the last in the price array, has index 0. The oldest bar has index Bars-1. If the number of the first visible bar is 2 or more less than the amount of visible bars in the chart, this means that the chart window is not full and there is a space to the right.
||It returns the window handle for the window that contains the given chart.
If no chart with symbol and timeframe is opened at the moment of function call, it returns
||It returns TRUE, if the chart subwindow is visible. Otherwise, it returns FALSE. The chart subwindow
chan be hidden due to the visibility properties of the indicator attached to it.
||It returns the index of window, in which the EA, a script or a custom indicator has been dropped. This value will be true, only if the EAs, custom indicators and scripts are attached using a mouse (the technology of 'drag and drop').
For custom indicators being initialized (call from the function init()), this index is not defined. The returned index is the number of the window (0 is the main chart window, indicator subwindows are numbered starting with 1), in which the custom indicator is working. During initialization, a custom indicator can create its won new subwindow, and its number will differ from that of the window, in which the indicator has really been dropped.
||It returns the maximum value of the vertical scale of the given subwindow of the current chart (0 is the main chart window, indicator subwindows are numbered starting with 1). If the subwindow index is not specified, the maximum value of the price scale of the main chart window will be returned.
||It returns the minimum value of the vertical scale of the given subwindow of the current chart
(0 is the main chart window, indicator subwindows are numbered starting with 1). If the subwindow index is not specified, the minimum value of the price scale of the main chart window will be returned.
||It returns the price value at a chart point, at which an EA or a script have been dropped.
The value will be true, only if the EA or the script have been moved using a mouse (the technology of 'drag and drop'). This value is not defined for custom indicators.
||It redraws the current chart forcibly. The function is usually used after the object properties have been changed.
||It saves the display of the current chart in a GIF file. If it fails to make a screenshot, it returns
||The function returns the time value at a chart point, at which an EA or a script have been dropped.
The value will be true, only if the EA or the script have been moved
using a mouse (the technology of 'drag and drop'). This value is not
defined for custom indicators.
||The function returns the amount of indicator windows in the chart, including the main chart window.
||It returns the value of X coordinate in pixels for the point in the chart window client area, where an EA or a script have been dropped. The value will be true, only if the EA or the script have been moved
using a mouse (the technology of 'drag and drop').
||It returns the value of Y coordinate in pixels for the point in the
chart window client area, where an EA or a script have been dropped. The value will be true, only if the EA or the script have been moved
using a mouse (the technology of 'drag and drop').
For the detailed description of these and other functions, please refer to Documentation at MQL4.community, MetaQuotes Software Corp. website or to "Help" section in MetaEditor.