Строковые функции
Наиболее часто встречающаяся операция для строковых значений - сложение (конкатенация) -
рассматривалась в Операции и выражения (Задача
3). В некоторых случаях возникает необходимость выполнить другие вычисления, связанные
со строковыми значениями. Для работы со значениями типа string в MQL4 имеется ряд
строковых функций. Рассмотрим, как могут быть использованы некоторые из них на примере.
|
Задача 35. Раскрасить 100 последних баров свечного графика: чёрные свечи - красным
цветом, а белые - синим. |
Раскраска свечи может быть выполнена двумя линиями: тонкая линия должна накладываться
на свечу так, чтобы полностью накрыть тени, а широкая линия должна заполнить тело
свечи. Применить для решения задачи линии пользовательского индикатора в данном
случае не представляется возможным, потому что отображаемые линии должны быть вертикальными,
т.е. построенными по двум координатам цены (при совпадающих координатах времени),
а индикаторные массивы позволяют хранить только одно значение, поставленное в соответствие
каждому бару. Поэтому решение задачи сводится к отображению на ценовом графике
серии однотипных графических объектов - OBJ_TREND, отличающихся координатами, стилем
и цветом линий (см. Графические объекты).
В данном случае в качестве прикладной программы используется эксперт, хотя в общем
случае алгоритм может быть реализован и в пользовательском индикаторе. В целом
алгоритм программы понятен. При присоединении эксперта к окну финансового инструмента
(при исполнении init()) график должен быть раскрашен первый раз. На каждом тике
(при исполнении start()) программа должна отслеживать возможные изменения в положении
каждого из созданных ею графических объектов (пользователь может случайно удалить
или переместить любой из них) и при необходимости восстановить его. А в период
завершения программы (deinit()) все созданные программой графические объекты должны
быть удалены.
В период практической работы с экспертом пользователь может вручную создать в окне
финансового инструмента и другие объекты, например, установить канал стандартных
отклонений, уровни Фибоначчи, линии поддержки и пр. Поэтому в программе должен
быть реализован алгоритм, позволяющий отличать объекты, созданные программой, от объектов, установленных пользователем. Это особенно важно
при завершении программы: необходимо удалить только "свои" объекты, а
"пользовательские" оставить без изменения. Каждый графический объект
обладает определёнными свойствами, которые, в общем случае, могут совпадать. Единственным
отличительным признаком любого объекта является его уникальное имя (одинаковые имена не допускаются).
При составлении имени каждого из создаваемых объектов желательно ввести в имя объекта
полезную информацию, по которой можно было бы судить о местоположении и свойствах
объекта. Например, имя объекта может содержать префикс, отличающий объект, созданный
этой программой, от всех других. В нашем случае это строковое значение "Paint_".
Кроме того, необходимо отличать и "свои" объекты между собой. При этом
простая нумерация (Paint_1, Paint_2 и т.д.) не может быть использована. Используя
такой способ именования имён объектов, невозможно понять: на каком баре должен
быть отображён, например, объект Paint_73. Тот бар, который имел индекс 73, с появлением
нового бара получит индекс 74, при следующем новом баре 75 и т.д. При таком решении
пришлось бы удалять и вновь создавать все объекты на каждом новом баре. Понятно,
что это решение (хотя и осуществимо), является очень грубым и затратным.
Каждый из создаваемых объектов должен иметь координаты времени, совпадающие со временем
открытия бара. Кроме того, на каждом баре необходимо отображать 2 линии - тонкую
и широкую. Наиболее удобно представить имена создаваемых программой объектов в
таком виде:
Имя объекта = Paint_2_2007.03.22 16:40, здесь:
Paint_ - префикс, отличающий объекты, созданные программой;
2_ - номер одного из двух объектов, отображаемых на баре (возможные значения 1 и
2);
2007.03.22 16:40 - координата времени, однозначно характеризующая бар, на котором
отображается объект.
Paint_ и 2_ - это значения переменных Prefix и Nom_Lin. Координату времени для
каждого бара можно получить путём преобразования значения типа datetime в значение
типа string с помощью функции преобразования данных:
Функция TimeToStr()
string TimeToStr(datetime value, int mode=TIME_DATE|TIME_MINUTES)
Функция преобразовывает значение, содержащее время в секундах, прошедших с 01.01.
1970 (значение типа datetime), в строку заданного формата (значение типа string).
Параметры:
value - время в секундах от 00:00 1 января 1970;
mode - дополнительный режим вывода данных. Может быть одним или комбинированным флагом:
TIME_DATE получает результат в форме "yyyy.mm.dd";
TIME_MINUTES получает результат в форме "hh:mi";
TIME_SECONDS получает результат в форме "hh:mi:ss".
Рассмотрим эксперт strings.mq4, управляющий графическими объектами
для раскраски свечей, и проследим как функция TimeToStr() используется в этой программе:
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;
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,"Объект создан экспертом",10);
return;
}
Для создания графических объектов в программе имеется пользовательская функция Create()
(блок 10-11). В качестве передаваемых параметров в этой функции используются переменная
Ind_Bar, указывающая индекс бара, на котором необходимо создать объект, и Line
- номер объекта (1я или 2я линия).
При формировании имени создаваемого объекта His_Name используются три составляющих:
string His_Name = Prefix+Nom_Lin+Str_Time;
Значение переменной Prefix задано программистом в головной части программы и при
выполнении программы не изменяется:
string Prefix = "Paint_";
Значение переменной Nom_Lin получено в результате вычислений:
string Nom_Lin = Line + "_";
Здесь значение целой переменной (при вычислении выражения в правой части выражения)
преобразуется к типу, имеющему более высокий приоритет, а именно, к типу string.
В результате, в зависимости от значения переменной Line, переменная Nom_Lin получает
значение "1_"или "2_".
Для вычисления значения переменной Str_Time используется функция преобразования
данных TimeToStr():
string Str_Time = TimeToStr(T_Bar);
Обратите внимание, функция TimeToStr() имеет умолчательные значения. В данном случае
именно такие значения параметра mode и требуются: "yyyy.mm.dd hh:mi";
использовать дополнительно секунды нет необходимости, потому что минимальный таймфрейм
равен 1 минуте.
Для использования в имени объекта можно было бы применить и такой способ вычисления
Str_Time:
string Str_Time = T_Bar;
В этом случае переменная Str_Time получила бы значение, равное количеству секунд,
прошедших с 01.01.1970. Чтобы увидеть разницу, можно выполнить программу, содержащую
такой код:
int init()
{
string String_Time = TimeToStr(Time[0]);
string String_Sec = Time[0];
Alert("String_Time = ",String_Time," String_Sec = ",String_Sec);
return;
}
В результате исполнения этой программы (в зависимости от времени открытия нулевого
бара) на экран будет выведено сообщение:
String_Time = 2007.03.22 19:10 String_Sec = 1174590600 |
Первый вариант, реализованный в эксперте
strings.mq4, несколько более информативен, поэтому в данном случае предпочтение отдано ему
(с точки зрения алгоритма, реализованного в программе, эти варианты равнозначны).
В последующих строках пользовательской функции Create() создаётся объект с вычисленным
именем His_Name, содержащим сведения о времени открытия бара, и со свойствами,
соответствующими номеру линии Line, а также с цветом в зависимости от характеристик
бара. Для каждого объекта указывается также значение текстового описания: "Объект
создан экспертом".
Вызов функции Create() осуществляется в программе в двух местах - из специальной
функции init() для первоначального создания объектов, и из специальной функции
start(), в случае необходимости ещё раз создать объект, случайно удалённый или
изменённый пользователем. Имена объектов в функции start() (блоки 4-5-6) формируются
так же, как и в других местах программы.
В блоке 6-7 определяется первая координата исследуемого объекта. Если при этом объект
не найден, то он создаётся с помощью Create(). А если объект существует, то определяются
другие его координаты и вычисляется, соответствуют ли его свойства характеристикам
бара (блок 7-8). При обнаружении любого несоответствия объект удаляется и создаётся
вновь (с тем же именем), но уже с правильными свойствами.
При исполнении функции deinit() решается ещё одна задача: из всей совокупности объектов,
имеющихся в окне финансового инструмента, необходимо удалить только те, которые
созданы экспертом. Это делается в два этапа: на первом этапе в массив Name_Del[]
запоминаются имена всех объектов, которые необходимо удалить, а затем, в отдельном
цикле, все эти объекты удаляются. Общее количество всех объектов в окне (в том
числе, созданных программой и установленных пользователем вручную) вычисляется
с помощью функции ObjectsTotal():
int Quant_Objects=ObjectsTotal();
Количество раскрашиваемых баров устанавливается пользователем во внешней переменной,
т.е. заранее неизвестно, сколько графических объектов придётся удалять. Поэтому
строковый массив, несущий имена удаляемых объектов, объявляется с количеством элементов равным 1, а затем размер массива программно изменяется - количество его элементов
увеличивается до общего количества объектов.
ArrayResize(Name_Del,Quant_Objects);
Для того, чтобы отобрать объекты, созданные экспертом, в функции deinit() имеется
цикл for, в котором производится анализ имени каждого объекта.
string Obj_Name = ObjectName(k);
Признаком, отличающим "наши" объекты от всех других, является префикс
"Paint_", с которого начинается имя каждого созданного программой объекта.
Для анализа названия объекта необходимо извлечь из строковой переменной, являющейся
уникальным именем объекта, начальную часть (в данном случае 6 символов), а затем
сравнить полученное значение со значением переменной Prefix. Если обнаружится
совпадение, то исследуемый объект подлежит удалению, если же нет, то объект удалять
не нужно.
Функция StringSubstr()
string StringSubstr(string text, int start, int length=0)
Функция извлекает подстроку из текстовой строки, начинающейся c указанной позиции.
Функция возвращает копию извлеченной подстроки, если возможно, иначе возвращается
пустая строка.
Параметры:
text - строка, из которой должна быть извлечена подстрока;
start - начальная позиция подстроки. Может быть от 0 до StringLen(text)-1;
length - длина извлекаемой подстроки. Если значение параметра меньше или равно 0 либо
параметр не задан, то будет извлекаться подстрока, начиная с указанной позиции
и до конца строки.
В рассматриваемом примере извлечение подстроки из имени объекта выполняется так:
string Head=StringSubstr(Obj_Name,0,6);
В данном случае из строковой переменной Obj_Name извлекаются первые 6 символов,
начиная с нулевого. Обратите внимание, счёт любых индексов в MQL4 (баров, массивов),
строк в списке ордеров, а также номер позиции в строке, начинается с 0, в то же
время количественный счёт начинается с 1.
Извлечённая подстрока (значение типа string) присваивается строковой переменной
Head. Если имя объекта (и сам объект) было создано рассматриваемым экспертом, то
значение извлечённой подстроки будет таким: "Paint_". Если же анализируется
другое имя, то искомое значение будет другим. Например, для имени объекта "StdDev
Channel 23109" значение извлечённой подстроки будет таким: "StdDev",
а для объекта с именем "Fibo 22800" - таким: "Fibo 2".
В последующих строках значение переменной Head сравнивается со значением переменной
Prefix:
if (Head == Prefix)
{
И если эти значения равны, то анализируемое имя объекта заносится в массив Name_Del[]
имён объектов, назначенных к удалению. В следующем цикле for удаляются все объекты,
имена которых содержатся в этом массиве (отдельно нужно заметить, что в первом
цикле for удалять объекты нельзя, т.к. в этом случае после каждого удаления изменится
общее количество объектов и их нумерация, в результате чего некоторые имена объектов
будут пропущены).
Во время исполнения эксперта
strings.mq4 ценовой график будет выглядеть так:
Рис. 142. Ценовой график раскрашен с помощью графических объектов (strings.mq4).
На Рис. 142 кроме группы объектов, покрывающих ценовой график, показаны два других
объекта, установленные пользователем вручную, - канал регрессии и уровни Фибоначчи.
После прекращения работы эксперта созданные им объекты будут удалены, а объекты,
установленные пользователем, останутся в окне финансового инструмента. Указанный
результат получен благодаря использованию в программе строковых функций, позволяющих
создавать и анализировать строковые значения, в том числе, имена графических объектов.
Строковые функции
Функция |
Краткое описание |
StringConcatenate |
Формирует строку из переданных параметров и возвращает её. Параметры могут иметь
любой тип. Количество параметров не может превышать 64. |
StringFind |
Поиск подстроки. Возвращает номер позиции в строке, с которой начинается искомая
подстрока, либо -1, если подстрока не найдена. |
StringGetChar |
Возвращает значение символа, расположенного в указанной позиции строки. |
StringLen |
Возвращает число символов в строке. |
StringSetChar |
Возвращает копию строки с измененным значением символа в указанной позиции. |
StringSubstr |
Извлекает подстроку из текстовой строки, начинающейся c указанной позиции. Функция
возвращает копию извлеченной подстроки, если возможно, иначе возвращается пустая
строка. |
StringTrimLeft |
Функция урезает символы перевода каретки, пробелы и символы табуляции в левой части
строки. Функция возвращает копию преобразованной строки, если это возможно, в противном
случае возвращается пустая строка. |
StringTrimRight |
Функция урезает символы перевода каретки, пробелы и символы табуляции в правой части
строки. Функция возвращает копию преобразованной строки, если это возможно, в противном
случае возвращается пустая строка. |
Функции преобразования данных
Функция |
Краткое описание |
CharToStr |
Преобразование кода символа в односимвольную строку. |
DoubleToStr |
Преобразование числового значения в текстовую строку, содержащую символьное представление
числа в указанном формате точности. |
NormalizeDouble |
Округление числа с плавающей запятой до указанной точности. Рассчитываемые значения
StopLoss, TakeProfit, а также значения цены открытия отложенных ордеров должны
быть нормализованы с точностью, значение которой хранится в предопределенной переменной
Digits. |
StrToDouble |
Преобразование строки, содержащей символьное представление числа, в число типа double
(формат двойной точности с плавающей точкой). |
StrToInteger |
Преобразование строки, содержащей символьное представление числа, в число типа int
(целое). |
StrToTime |
Преобразование строки, содержащей время и/или дату в формате "yyyy.mm.dd [hh:mi]",
в число типа datetime (количество секунд, прошедших с 01.01.1970). |
TimeToStr |
Преобразование значения, содержащего время в секундах, прошедшее с 01.01.1970, в
строку формата "yyyy.mm.dd hh:mi". |
Для получения подробного описания этих и других функций необходимо обратиться к
справочной документации на MQL4.community, сайте MetaQuotes Ltd. или к разделу "Справка" в редакторе MetaEditor.