Страница 6 из 8
Глобальные переменные видны в пределах всей программы, их значение может быть изменено в любом месте программы и память, выделяемая под глобальные переменные вне программного стека, освобождается при выгрузке программы.
Здесь видно, что input переменные – это те же глобальные переменные, за исключением опции – их значение не может быть изменено в любом месте программы.
Если глобальную или локальную переменную объявить со спецификатором const – это так же не позволит изменять значение этой переменной в процессе выполнения программы.
Статические переменные определяются модификатором static, который указывается перед типом данных.
Со статическими переменными все немного сложнее, но легче всего их понять, сравнивая статические переменные с локальными и глобальными переменными.
В принципе, статическая переменная, объявленная там же, где и глобальная переменная, ничем не отличается от глобальной переменной.
Хитрость начинается, если локальную переменную объявить с модификатором static.
В этом случае, после выполнения блока кода, память, выделенная под статическую переменную, не освобождается. И при следующем выполнении того же блока кода, предыдущее значение статической переменной можно использовать.
Хотя область видимости такой статической переменной ограничивается те же самым блоком кода, в котором она была объявлена.
extern переменные это аналог статических глобальных переменных. Нельзя объявить локальную переменную с модификатором extern.
Отличие extern переменных от статических глобальных переменных проще всего продемонстрировать на индикаторе MACD.
Индикатор MACD имеет включаемый файл MovingAverages, обозначенный с помощью директивы #include и расположенный в папке Include.
Если в файле MovingAverages и файле MACD одновременно объявить extern-переменную:
extern int a=0;
то при компиляции обоих файлов все пройдет удачно, и переменную можно будет использовать.
Если же в файле MovingAverages и файле MACD одновременно объявить статическую глобальную переменную:
static int a=0;
тогда при компиляции обоих файлов возникнет ошибка.
Помимо команды #include полезной является также директива #define, которая позволяет делать подстановку выражения вместо идентификатора, например:
#define PI 3.14
Хэндл индикатора
Начнем с цитаты:
HANDLE идентифицирует объект, которым Вы можете манипулировать. Джеффри РИХТЕР "Windows для профессионалов".
Переменные типа handle представляют собой указатель на некоторую системную структуру или индекс в некоторой системной таблице, которая содержит адрес структуры.
Таким образом, получив хэндл некоторого индикатора, мы можем использовать его данные для построения своего индикатора.
Хэндл индикатора представляет собой переменную типа int и объявляется, как правило, после объявления массивов буферов индикатора, вместе с глобальными переменными, например в индикаторе MACD:
Объявляются два хэндла – int ExtFastMaHandle и int ExtSlowMaHandle.
Здесь хэндлы индикаторов – это указатели на индикатор скользящего среднего с разными периодами 12 и 26.
Объявив эти переменные, мы, естественно, реально ничего не получаем, так как объекта индикатора, данные которого мы хотим использовать, еще не существует.
Создать в глобальном кеше клиентского терминала копию соответствующего технического индикатора и получить ссылку на нее можно несколькими способами.
Если это стандартный индикатор, проще всего получить его хэндл можно с помощью стандартной функции для работы с техническими индикаторами.
Стандартная функция для индикатора скользящего среднего это функция iMA.
И в индикаторе MACD хэндлы индикатора скользящего среднего получаются с помощью вызова функции iMA в функции OnInit().
где используются свойства индикатора – InpFastEMA, InpSlowEMA и InpAppliedPrice.
Предположим, что мы хотим использовать не стандартный, а пользовательский индикатор.
В папке Indicators/Examples редактора MQL5 есть нужный нам индикатор – это файл Custom Moving Average.mq5.
Для вызова того индикатора воспользуемся функцией iCustom.
В функции OnInit() индикатора MACD изменим код, где для получения хэндлов вместо стандартной функции, используем функцию iCustom.
После компиляции индикатора мы увидим, что его отображение никак не изменилось.
Еще один способ получить хэндл пользовательского индикатора, это использовать функцию IndicatorCreate.
В функции OnInit() индикатора MACD изменим код, где для получения хэндлов используем функцию IndicatorCreate.
После компиляции индикатора мы опять увидим, что его отображение никак не изменилось.
После получения хэндла индикатора, если он используется в коде один раз, для экономии памяти неплохо использовать функцию IndicatorRelease.
Которая удаляет хэндл индикатора и освобождает расчетную часть индикатора.
Хорошо, хэндл индикатора мы получили. Как же теперь извлечь его данные?
Делается это в функции OnCalculate с помощью функции CopyBuffer.
При этом функция CopyBuffer() распределяет размер принимающего массива под размер копируемых данных.
Напомним, что это работает, если принимающий массив является просто динамическим массивом.
Если же принимающий массив связан с буфером индикатора, тогда клиентский терминал сам заботится о том, чтобы размер такого массива соответствовал количеству баров, доступных индикатору для расчета.
В индикаторе MACD именно такая ситуация.
Промежуточные массивы ExtFastMaBuffer и ExtSlowMaBuffer привязаны к буферам индикатора с помощью функции SetIndexBuffer.