String Functions
The most common operation with string values, addition (concatenation), was discussed in the Operations and Expressions (Problem 3) section. In some cases, there is a need in performing other calculations related to string values. MQL4 has a number of string functions for working with the values of string type. Let's consider the usage of some of them through the example below.
|
Problem 35. Color the last 100 bars of the candlestick chart as follows: black candlesticks in red, white candlesticks in blue. |
A candlestick can be colored using two lines: a thin line must overlay a candlestick so that it covers all the shadows, whereas a thick line should fill out a candlestick body. In this case, we cannot use the lines of a custom indicator, because the displayed lines must be vertical, i.e., constructed using two coordinates (with the same time coordinates), while indicator arrays allow us to store only one value set in correspondence with each bar. So, the problem solution comes to displaying a series of single-type OBJ_TREND objects that differ in their coordinates and line style and color (see Graphical Objects) on a price chart.
In this case, the EA is used as an application program, but, in general, the algorithm can be implemented in a custom indicator. As a whole, the algorithm is clear. The chart must be colored for the first time, as soon as it is attached to the symbol window (during the execution of init()). The program must track possible changes in the location of graphical objects (user can accidentally move or delete one of them) with every tick coming, and restore them, if necessary. All objects created by the program must be deleted, as soon as the program finishes operating (deinit()).
A user can create other objects in a symbol window while the EA is working, for example, place the channel of standard deviations, Fibo levels, support lines, etc. So, the algorithm that allows us to distinguish user-created and program-created objects must be implemented in the program. This is particularly important when closing the program: it is necessary to remove only the program-created objects, while the user-created objects must remain unchanged. Each graphical object has its own properties that can generally coincide. The only identifying feature of any object is its unique name (the use of the same names is prohibited).
It's recommended to enter the useful information in the object's name while composing it, so it will be possible to detect the location and the properties of the object. For example, an object name may contain a prefix that differentiates a program-created object from others. In this case, it is "Paint_". Besides, it is necessary to differentiate the "user-defined" objects from any other, as well. The same time a simple numeration (Paint_1, Paint_2) cannot be used. Using this method of objects numeration, you cannot understand, at which bar the object Paint_73 should be displayed. The bar that has the Paint_73 index will get the Paint_74 index, when a new bar comes, Paint_75 index when another new bar comes, etc. In such a case, it would be necessary to delete and re-create all the objects on every new bar. This solution (although it is possible) is obviously very rough and expensive.
Every object created must have its time coordinates that correspond with the time of bar opening. Besides, two lines must be displayed on every bar - a thin line and a thick line. It is most comfortable to represent the names of a created objects by the program as follows:
Object name = Paint_2_2007.03.22 16:40, here:
Paint_ - prefix that differentiates the objects created by the program;
2_ - number of either objects that are displayed on a bar (value 1 or 2 is possible);
2007.03.22 16:40 - time coordinate that uniquely characterizes the bar the object is displayed on.
Paint_ and 2_ are the values of the variables Prefix and Nom_Lin, respectively. The time coordinate can be obtained for every bar by transformation a datetime value into a string value using the transforming functions:
TimeToStr() Function
string TimeToStr(datetime value, int mode=TIME_DATE|TIME_MINUTES)
The function transforms the values that contain time (in seconds) lapsed since 01.01.1970 (datetime value) into a string of the specified format (string value).
Parameters:
value - time in seconds lapsed since 00:00 of the 1st of January 1970;
mode - an additional mode of data output. It can be a single or a combined flag:
TIME_DATE obtains the result in the "yyyy.mm.dd" form;
TIME_MINUTES obtains the result in the "hh:mi" form;
TIME_SECONDS obtains the result in the "hh:mi:ss" form.
Let's consider the EA strings.mq4 that manages objects for coloring of candles and see how the TineToStr() is used in this program:
extern int Quant_Bars=100;
datetime Time_On;
string Prefix ="Paint_";
int init()
{
int Ind_Bar;
Time_On=Time [Quant_Bars];
for(Ind_Bar=Quant_Bars-1; Ind_Bar>=0; Ind_Bar--)
{
Create(Ind_Bar,1);
Create(Ind_Bar,2);
}
WindowRedraw();
return;
}
int start()
{
datetime T1, T2;
int Error,Ind_Bar;
double P1, P2;
color Col;
for(int Line=1; Line<=2; Line++)
{
string Nom_Lin =Line + "_";
for(Ind_Bar=0; ;Ind_Bar++)
{
datetime T_Bar= Time[Ind_Bar];
if (T_Bar < Time_On) break;
string Str_Time=TimeToStr(T_Bar);
string His_Name=Prefix+Nom_Lin+Str_Time;
T1=ObjectGet(His_Name,OBJPROP_TIME1);
Error=GetLastError();
if (Error==4202)
{
Create(Ind_Bar,Line);
continue;
}
T2 =ObjectGet(His_Name,OBJPROP_TIME2);
P1 =ObjectGet(His_Name,OBJPROP_PRICE1);
P2 =ObjectGet(His_Name,OBJPROP_PRICE2);
Col=ObjectGet(His_Name,OBJPROP_COLOR);
if(T1!=T_Bar || T2!=T_Bar ||
(Line==1 && (P1!=High[Ind_Bar] || P2!= Low[Ind_Bar])) ||
(Line==2 && (P1!=Open[Ind_Bar] || P2!=Close[Ind_Bar])) ||
(Open[Ind_Bar] Close[Ind_Bar] && Col!=Red) ||
(Open[Ind_Bar]==Close[Ind_Bar] && Col!=Green) )
{
ObjectDelete(His_Name);
Create(Ind_Bar,Line);
}
}
}
WindowRedraw();
return;
}
int deinit()
{
string Name_Del[1];
int Quant_Del=0; objects to be deleted
int Quant_Objects=ObjectsTotal();
ArrayResize(Name_Del,Quant_Objects);
for(int k=0; k<=Quant_Del; i++)
ObjectDelete(Name_Del[i]);
return;
}
int Create(int Ind_Bar, int Line)
{
color Color;
datetime T_Bar=Time [Ind_Bar];
double O_Bar=Open [Ind_Bar];
double C_Bar=Close[Ind_Bar];
double H_Bar=High [Ind_Bar];
double L_Bar=Low [Ind_Bar];
string Nom_Lin =Line + "_";
string Str_Time=TimeToStr(T_Bar);
string His_Name=Prefix+Nom_Lin+Str_Time;
if (O_Bar < C_Bar) Color=Blue;
if (O_Bar >C_Bar) Color=Red;
if (O_Bar ==C_Bar) Color=Green;
switch(Line)
{
case 1:
ObjectCreate(His_Name,OBJ_TREND,0,T_Bar,H_Bar,T_Bar,L_Bar);
break;
case 2:
ObjectCreate(His_Name,OBJ_TREND,0,T_Bar,O_Bar,T_Bar,C_Bar);
ObjectSet( His_Name, OBJPROP_WIDTH, 3);
}
ObjectSet( His_Name, OBJPROP_COLOR, Color);
ObjectSet( His_Name, OBJPROP_RAY, false);
ObjectSetText(His_Name,"Object is created by the EA",10);
return;
}
In order to create graphical objects, the user-defined function Create() (blocks 10-11) is used in the program. The variable Ind_Bar that indicates the index of bar the object should be created on, and Line, the object number (line 1 or 2), are used as the assignable parameters in this function.
Three components are used when forming the name of the object to be created:
string His_Name = Prefix+Nom_Lin+Str_Time;
The value of the Prefix variable is specified by the programmer in the head part of the program and it is not changed during the program execution:
string Prefix = "Paint_";
The value of the Nom_Lin variable is obtained as a result of calculations:
string Nom_Lin = Line + "_";
Here the value of the integer variable (during calculation in the first part of expression) is transformed into the type of the higher priority, namely, into the string type. As a result, the Nom_Lin receives "1_" or "2_" values depending on the value of the Line variable.
In order to calculate the value of the Str_Time variable the TimeToStr() function of data transformation is used:
string Str_Time = TimeToStr(T_Bar);
Please note that the TimeToStr() function has default values. In this case, these are these values that are necessary: "yyyy.mm.dd hh:mi";
there is no need to use seconds additionally, because the minimum timeframe is equal to 1 minute.
We could also apply the following method of Str_Time calculation to be used in the object name:
string Str_Time = T_Bar;
In this case, the Str_Time would obtain a value equal to the number of seconds lapsed since 01.01.1970. In order to see the difference, we can develop a program that contains the following code:
int init()
{
string String_Time = TimeToStr(Time[0]);
string String_Sec = Time[0];
Alert("String_Time = ",String_Time," String_Sec = ",String_Sec);
return;
}
The following message (according to the time of zero bar opening) will be displayed on the screen as a result of the program execution:
String_Time = 2007.03.22 19:10 String_Sec = 1174590600 |
The first alternative that is implemented in the
strings.mq4 EA is a bit more informative, so the preference is given to it, in this case (the alternatives are equivalent in terms of composing an algorithm).
The object named His_Name is created in the subsequent lines of the user-defined function Create(). It contains the information about the bar opening time with the parameters that correspond to the number of the "Line" line and also the color depending on bar characteristics. The value of the text description is specified for every object, "Object is created by EA", as well.
The Create() function is called in the program from two places: from the special function init() for the initial creation of objects, and from the special function start() to re-create the object, if necessary, in case it was deleted or modified by the user. The object names in start() (blocks 4-6) are formed in the same way as in other parts of the program.
The first coordinate of the considered object is defined in block 6-7. If the object is not found at this time, it will be created by the Create() function. And if the object exists, its other coordinates will be determined and the matching of its parameters with the bar properties will be checked (block 7-8). The object will be deleted and re-created (with the same name) with the correct properties, if any mismatch is detected.
Another problem is solved during the execution of the deinit() function: it is necessary to delete only the objects that have been created by the program from the aggregate of all objects in the symbol window. This is performed in two stages: at the first stage, the names of all objects that should be deleted are memorized to the Name_Del[] array, and then they will be deleted in an individual cycle. The total number of objects in the window (including those created by the program and placed manually by the user) is calculated using the ObjectsTotal() function:
int Quant_Objects=ObjectsTotal();
The number of bars to be colored is set by the user in an external variable, i.e., it is unknown in advance how many objects should be deleted. So the string array that contains the names of the objects to be deleted is declared with the number of elements equal to 1. Further, its size is programmatically changed - the number of elements is increased to the total number of objects.
ArrayResize(Name_Del,Quant_Objects);
In order to select the objects that have been created by the EA, the deinit() function contains the cycle 'for' that analyzes the names of all objects.
string Obj_Name = ObjectName(k);
The attribute that differentiates "our" objects from all the others is the "Paint_" prefix, with which the name of each program-created object starts. To analyze an object name, we should extract the first part (in this case, 6 symbols) from the string variable being the unique name of the object; then we should compare this value with that of the Prefix variable. If they match, this object should be deleted. If not, it should no be deleted.
StringSubstr() Function
string StringSubstr(string text, int start, int length=0)
The function extracts the substring from the text line starting from the specified position. The function returns the copy of the extracted substring. Otherwise, an empty string is returned.
Parameters:
text - the line the substring should be extracted from;
start - the initial position of the substring. It can range from 0 to StringLen(text)-1;
length - the length of the substring to be extracted. If the value of this parameter is less than or equal to 0 or it is not even specified then the substring will be extracted from the specified position till the end of the line.
In the considered example, the substring is extracted from the object name as follows:
string Head=StringSubstr(Obj_Name,0,6);
In this case, the first 6 symbols are extracted from the Obj_Name string variable starting with the zero one. Please note that the count of all indexes (bars, arrays), entries in the orders list and also the number of the position in the line starts with 0, whereas the quantified count starts with 1.
The extracted substring (a string value) is assigned to the string variable Head. If the object name (and in the object itself) is created by the considered EA, the value of the extracted substring will be "Paint_". If another name is analyzed, then the desired value will be different. For example, the value of the extracted substring from the "StdDev
Channel 23109" object name will be the following: "StdDev", and for the object named "Fibo 22800" it will be "Fibo 2".
In the subsequent lines, the value of the variable Head is compared to that the variable Prefix:
if (Head == Prefix)
{
If these values are equal to each other, then the analyzed name of the object will be placed to the array Name_Del[] for the names of objects to be deleted. In the next "for" cycle, all the objects, the names of which are contained by the array, will be deleted (it should be noted separately that it is impossible to delete all the objects during the first cycle, because, in this case, the total number of objects and their numeration will be changed each time the object is deleted, which will result in the omission of some object names).
The price chart will have the following appearance during the execution of the
strings.mq4 EA:
Рис. 142. Price chart colored using graphical objects (strings.mq4).
Besides the groups of objects that cover the price chart, two other objects placed manually by the user are displayed, as shown in Fig. 142; they are regression channel and Fibo levels. The objects created by the EA will be deleted, as soon as its execution is finished, and the objects created by the user will remain in the symbol window. This result is obtained due to the use of string functions in the program. They allow to create and analyze string values, including graphical object names.
String Functions
Function |
Short Description
|
StringConcatenate |
It forms a string from the given parameters and returns it. The parameters can be of any type. The number of parameters cannot exceed 64. |
StringFind |
Substring searching. It returns the number of the position in the line the desired substring starts with, or -1, in case the substring is not found. |
StringGetChar |
It returns the value of the symbol that is located at the specified position of the line. |
StringLen |
It returns the number of symbols in the line. |
StringSetChar |
It returns the copy of the line with the modified value of the symbol at the specified position. |
StringSubstr |
It extracts the substring that starts at the specified position in the text line. The function returns the copy of the extracted substring, if possible. Otherwise, an empty string is returned. |
StringTrimLeft |
The function cuts the carriage return characters, spaces and tabulation symbols from the left part of the string. The function returns the copy of the modified string, if possible. Otherwise, an empty string is returned. |
StringTrimRight |
The function cuts the carriage return characters, spaces and tabulation
symbols from the right part of the string. The function returns the copy
of the modified string, if possible. Otherwise, an empty string is
returned. |
Data Transformation Functions
Function |
Summary Info
|
CharToStr |
Transformation of the symbol code into a single-symbol string. |
DoubleToStr |
Transformation of the numeric value into a text string that contains the symbolic representation of the number with the specified accuracy format. |
NormalizeDouble |
Rounding off the number with the floating point to the specified accuracy. The calculated StopLoss, TakeProfit and also the open prcie of pending orders values must be normalized according to the accuracy that is stored in the defined Digits variable. |
StrToDouble |
Transformation of the string that contains the symbolic representation of the number into the number of "double" type (double-accuracy format with the floating point). |
StrToInteger |
Transformation of the string that contains the symbolic representation into the number of the "int" type (integer). |
StrToTime |
Transformation of the string that contains time and/or date in the "yyyy.mm.dd [hh:mi]" format into the number of the "datetime" type (number of seconds passed since 01.01.1970). |
TimeToStr |
Transformation of the value that contains the time expressed in seconds passed since 01.01.1970 into the string of the "yyyy.mm.dd hh:mi" format. |
To get the detailed information about these and other functions take a look at the Documentation at MQL4.community, at MetaQuotes Ltd. website or at the "Help" section of MetaEditor.