Предопределённые переменные и функция RefreshRates
В языке MQL4 существуют переменные с предопределёнными именами.
Предопределённая переменная - это переменная с предопределённым названием, значение которой определяется клиентским
терминалом и не может быть изменено программным способом. Предопределённые переменные
отражают состояние текущего ценового графика на момент запуска программы (эксперта,
скрипта или пользовательского индикатора) или в результате исполнения функции RefreshRates().
Перечень простых предопределённых имён переменных
Ask- последняя известная цена продажи по текущему финансовому инструменту;
Bid- последняя известная цена покупки по текущему финансовому инструменту;
Bars - количество баров на текущем графике;
Point - размер пункта текущего финансового инструмента в валюте котировки;
Digits - количество цифр после десятичной точки в цене текущего финансового инструмента.
Перечень предопределённых имён массивов-таймсерий
Time - время открытия каждого бара текущего графика;
Open - цена открытия каждого бара текущего графика;
Close - цена закрытия каждого бара текущего графика;
High - максимальная цена каждого бара текущего графика;
Low - минимальная цена каждого бара текущего графика;
Volume - тиковый объем каждого бара текущего графика.
(понятия "массив" и "массив-таймсерия" рассматриваются в
разделе Массивы).
Свойства предопределённых переменных
Название предопределённой переменной не может быть использовано для идентификации
пользовательской переменной. Предопределённые переменные могут использоваться в
выражениях наравне с другими переменными по тем же правилам, но изменить значение
предопределённой переменной нельзя. При попытке компилировать программу, содержащую
оператор присваивания, в котором слева от знака равенства указана предопределённая
переменная, редактор MetaEditor выдаст сообщение об ошибке. По области видимости
предопределённые переменные относятся к глобальным, т.е. доступны из любой части
программы (см. Виды переменных).
Наиболее важное свойство предопределённых переменных заключается в следующем:
|
Значения всех предопределённых переменных автоматически обновляются клиентским терминалом
в момент запуска на исполнение специальных функций. |
Предыдущее и текущее значения предопределённых переменных могут совпадать, но само
значение будет обновлённым. В момент запуска специальной функции значения этих
переменных уже обновлены и доступны с первых строк программы. Проиллюстрируем обновление
значений предопределённых переменных на следующем примере (эксперт predefined.mq4
):
int start()
{
Alert("Bid = ", Bid);
return;
}
Запустив эту простую программу на выполнение легко убедиться, что значения переменной
Bid, отражаемые в сообщениях, всякий раз будут соответствовать значениям текущего
курса. Аналогичным способом можно проверить и значения других переменных, зависящих
от сложившихся условий. Например, переменная Ask также прямо зависит от текущего
курса. Значение переменной Bars тоже изменится, если изменится количество баров. Это может
произойти на том тике, на котором в окне текущего финансового инструмента образуется
новый бар. Значение Point зависит от спецификации финансового инструмента. Например, для валютной
пары EUR/USD это значение равно 0.0001, а для валютной пары USD/JPY - равно 0.01.
Значение Digits для тех же валютных инструментов равно соответственно целым числам
4 и 2.
Другим важным свойством предопределённых переменных является следующее:
|
Клиентский терминал создаёт набор локальных копий предопределённых переменных отдельно
для каждой запущенной программы. Каждая запущенная программа работают с собственным
набором копий исторических данных. |
В одном клиентском терминале может быть одновременно запущено несколько прикладных
программ(экспертов, скриптов или индикаторов), и для каждой из них клиентский терминал
создаст свой набор копий значений всех предопределённых переменных - исторических
данных. Рассмотрим более подробно, чем вызвана такая необходимость. На Рис. 52
показано, как будут работать эксперты, характеризующиеся разной длительностью исполнения
специальной функции start(). Для простоты положим, что в рассматриваемых экспертах
других специальных функций нет, и оба эксперта работают в одинаковых таймфреймах одного
и того же финансового инструмента.
Рис. 52. Время работы функции start() может быть больше или меньше интервала времени
между тиками.
Эксперты отличаются друг от друга временем исполнения специальной функции start().
Для обычных экспертов средней сложности это время составляет приблизительно от
1 до 100 миллисекунд. Другие эксперты могут исполняться значительно дольше, например,
несколько секунд или даже десятков секунд. Промежуток времени между тиками также
колеблется от миллисекунд до минут, а в редких случаях - нескольких десятков минут.
Проследим на представленном примере, как повлияет частота поступления тиков на работу
экспертов Эксперт 1 и Эксперт 2, имеющих различное время исполнения специальной
функции start().
В момент времени t 0 Эксперт 1 присоединяется к клиентскому терминалу и переходит
в режим ожидания тика. В момент t 1 поступает тик, в результате чего клиентский
терминал запускает на исполнение специальную функцию start(). Одновременно с этим
событием программа получает доступ к обновлённому набору копий значений предопределённых
переменных. В период исполнения программа может обращаться к этим значениям, они
будут оставаться неизменными в течение всего времени работы специальной функции
start(). По окончании исполнения специальной функции start() программа перейдёт
в режим ожидания нового тика.
Ближайшим событием, при котором предопределённые переменные могут получить новые
значения, является новый тик. Время исполнения Т1 специальной функции start() Эксперта
1 значительно меньше, чем ожидаемое время между тиками, например, промежуток времени
t 1 - t 2 или t 2 - t 3 и т.д. В связи с этим в рассматриваемом периоде исполнении
Эксперта 1 не возникает ситуация, при которой значения предопределённых переменных
могли бы устареть, т.е. не соответствовать истинным (последним известным) значениям на текущий момент.
В работе Эксперта 2 наблюдается иная ситуация, потому что период исполнения Т2 его
специальной функции start() в некоторых случаях превышает период времени между тиками.
Функция start() Эксперта 2 также запускается в момент t 1. На Рис. 52 показано,
что интервал времени меду тиками t 1 - t 2 больше, чем время Т2 исполнения функции
start(), поэтому в этот период работы программы обновление предопределённых
переменных не происходит (т.е. в этот период новые значения переменных с сервера
не поступают, поэтому их истинными значениями следует считать те, которые
появились в момент t 1).
В следующий раз функция start() Эксперта 2 запускается на исполнение в момент t 2,
в результате прихода второго тика. Одновременно с этим обновляются и значения набора
копий предопределённых переменных. На Рис. 52 показано, что момент прихода третьего
тика t 3 приходится на тот период, когда специальная функция start() ещё не закончила
свою работу (т.е. исполняется). Возникает естественный вопрос: каковыми будут значения предопределённых
переменных, доступные Эксперту 2, в период с момента t 3 прихода третьего тика
до момента t 32 окончания работы специальной функции start()? Ответ на этот вопрос
можно получить согласно следующему правилу:
|
Значения копий предопределённых переменных сохраняются в течение всего периода работы
специальных функций. Эти значения могут быть принудительно обновлены с помощью
стандартной функции RefreshRates(). |
Таким образом (если не была исполнена функция RefreshRates()), в течение всего периода
исполнения специальной функции start() Эксперту 2 будут доступны значения того локального
набора копий предопределённых переменных, который был сформирован в момент поступления
второго тика. Несмотря на то, что эксперты работают в одинаковых окнах, начиная
с момента прихода третьего тика t 3, каждый из экспертов будет работать с разными
значениями предопределённых переменных. Эксперт 1 будет работать со своей локальной
копией набора исторических данных, значения которых определены в момент t 3, а
Эксперт 2 будет работать со своей копией данных, значения которых соответствуют
моменту t 2.
|
Чем больше время исполнения прикладной программы и меньше промежуток между тиками,
тем больше вероятность того, что очередной тик придётся на период, когда программа
исполняется. С помощью набора локальных копий исторических данных для каждой программы
создаются условия, гарантирующие неизменность предопределённых переменных в течение
всего времени исполнения специальных функций. |
Начиная с момента t 4, когда придёт очередной тик, оба эксперта снова будут запущены
в работу, при этом каждый из них будет иметь доступ к своей копии предопределённых
переменных, значения которых сформированы в момент t 4 прихода четвёртого тика.
Функция RefreshRates()
bool RefreshRates()
Стандартная функция RefreshRates() позволяет обновить значения локальной копии исторических
данных. Другими словами, эта функция принудительно обновляет данные о текущем рыночном
окружении (объем Volume, серверное время последней котировки Time[0], цены Bid,
Ask и т.д.). Эта функция может использоваться, когда программа производит вычисления
в течение длительного времени и нуждается в обновленных данных.
Функция RefreshRates() возвращает TRUE, если на момент её исполнения в клиентском
терминале имеются сведения о новых значениях исторических данных (т.е. если в период
исполнения специальной функции приходил новый тик). В этом случае значения набора
локальных копий предопределённых переменных будут обновлены.
Функция RefreshRates() возвращает FALSE, если с момента начала исполнения специальной
функции исторические данные в клиентском терминале не обновлялись. В этом случае
текущие значения набора локальных копий предопределённых переменных не изменяются.
|
Обратите внимание, действие функции RefreshRates() распространяется только на ту
программу, в которой она запущена (а не на все программы, одновременно работающие
в клиентском терминале). |
Проиллюстрируем исполнение функции RefreshRates() на примере.
|
Задача 21. Посчитать сколько итераций может выполнить оператор цикла в период
между тиками (для ближайших пяти тиков). |
Решить эту задачу возможно только с использованием функции RefreshRates()
(скрипт
countiter.mq4 ):
int start()
{
int i, Count;
for (i=1; i<=5; i++)
{
Count=0;
while(RefreshRates()==false)
{
Count = Count+1;
}
Alert("Тик ",i,", циклов ",Count);
}
return;
}
По условию задачи необходимо сделать вычисления только для ближайших пяти тиков,
поэтому для решения можно использовать скрипт. В программе используются две переменные:
i - для подсчёта количества тиков и Count - для подсчёта итераций. Внешний цикл
for организован по количеству обрабатываемых тиков (от 1 до 5). В начале каждого
цикла for обнуляется счётчик количества итераций (выполняемых в цикле while), а
в конце - выдаётся сообщение с номером тика и соответствующим ему количеством итераций.
Внутренний цикл while будет работать до тех пор, пока значение, возвращаемое функцией
RefreshRates(), равно false, т.е. до тех пор, пока нового тика нет. В течение времени
работы цикла while (т.е. в период между тиками) значение переменной Count будет
постоянно увеличиваться, таким образом, будет производиться подсчёт искомого количества
итераций в цикле while. Если в момент проверки условия в операторе цикла while
значение, возвращаемое функцией RefreshRates(), окажется равным true, то это будет
означать, что в клиентском терминале имеются новые значения предопределённых переменных,
т.е. пришёл новый тик. В результате этого управление передаётся за пределы цикла
while и подсчёт итераций, таким образом, прекращается.
В результате исполнения скрипта countiter.mq4 в окне финансового инструмента может быть получен ряд сообщений, характеризующих
быстродействие языка MQL4:
Рис. 53. Результат работы скрипта countiter.mq4 в окне EUR/USD.
Легко увидеть, что за 1 секунду (продолжительность между третьим и четвёртым тиками)
скрипт совершил более 400 тысяч итераций. Аналогичный результат можно получить
путём простого расчёта и для других тиков.
Вернёмся к предыдущему примеру (эксперт predefined.mq4). Ранее было показано, что если в Эксперте
2 не исполняется функция RefreshRates(), то значения локальных копий предопределённых
переменных будут оставаться неизменными в течение всего времени исполнения специальной
функции start(), т.е., например, в течение периода t 2 - t 32. Если же после третьего
тика (приходящегося на период исполнения специальной функции start()) в Эксперте
2 исполнить функцию RefreshRates(), например, в момент t 31, то значения локальных
копий предопределённых переменных будут обновлены. Поэтому оставшееся время, начиная
с момента t 31 исполнения функции RefreshRates() до момента t 32 окончания исполнения
специальной функции start(), Эксперту 2 будут доступны новые значения локальных
копий предопределённых переменных, соответствующие тем значениям, которые определены
клиентским терминалом в момент t 3 прихода третьего тика.
Если же в Эксперте 2 функцию RefreshRates() исполнить в момент t 11 или t 21 (т.е.
в период, когда последний известный тик - это тот, который запустил на исполнение
специальную функцию start()), то это не приведёт к изменению значений локальных
копий предопределённых переменных. В этих случаях текущие значения локальных копий
предопределённых переменных будут соответствовать последним известным, а именно
тем, которые были определены клиентским терминалом на момент последнего запуска
специальной функции start().