Еще один способ получить хэндл пользовательского индикатора, это использовать функцию IndicatorCreate:
int IndicatorCreate (
string symbol, // имя символа
ENUM_TIMEFRAMES period, // период
ENUM_INDICATOR indicator_type, // тип индикатора из перечисления ENUM_INDICATOR
int parameters_cnt=0, // количество параметров
const MqlParam& parameters_array [] =NULL, // массив параметров
);
В функции OnInit индикатора MACD изменим код:
MqlParam params [];
ArrayResize (params,5);
params [0].type =TYPE_STRING;
params[0].string_value=«Examples\\Custom Moving Average»;
// – - set ma_period
params [1].type =TYPE_INT;
params[1].integer_value=InpFastEMA;
// – - set ma_shift
params [2].type =TYPE_INT;
params[2].integer_value=0;
// – - set ma_method
params [3].type =TYPE_INT;
params[3].integer_value=MODE_EMA;
// – - set applied_price
params [4].type =TYPE_INT;
params[4].integer_value=InpAppliedPrice;
// – - initialization done
ExtFastMaHandle=IndicatorCreate (NULL, NULL, IND_CUSTOM,4,params);
params[1].integer_value=InpSlowEMA;
ExtSlowMaHandle=IndicatorCreate (NULL, NULL, IND_CUSTOM,4,params);
После компиляции индикатора мы опять увидим, что его отображение никак не изменилось.
После получения хэндла индикатора, если он используется в коде один раз, для экономии памяти неплохо использовать функцию IndicatorRelease:
bool IndicatorRelease (
int indicator_handle // handle индикатора
);
которая удаляет хэндл индикатора и освобождает расчетную часть индикатора.
Хорошо, хэндл индикатора мы получили. Как же теперь извлечь его данные?
Делается это в функции OnCalculate с помощью функции CopyBuffer:
int CopyBuffer (
int indicator_handle, // handle индикатора
int buffer_num, // номер буфера индикатора
int start_pos, // откуда начнем
int count, // сколько копируем
double buffer [] // массив, куда будут скопированы данные
);
При этом функция CopyBuffer распределяет размер принимающего массива под размер копируемых данных.
Напомним, что это работает, если принимающий массив является просто динамическим массивом.
Если же принимающий массив связан с буфером индикатора, тогда клиентский терминал сам заботится о том, чтобы размер такого массива соответствовал количеству баров, доступных индикатору для расчета.
В индикаторе MACD именно такая ситуация. Промежуточные массивы ExtFastMaBuffer [] и ExtSlowMaBuffer [] привязаны к буферам индикатора:
SetIndexBuffer (2,ExtFastMaBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer (3,ExtSlowMaBuffer, INDICATOR_CALCULATIONS);
И в эти массивы производится копирование буфера индикатора Moving Average на основе его хэндлов:
if (CopyBuffer (ExtFastMaHandle,0,0,to_copy, ExtFastMaBuffer) <=0)
{
Print («Getting fast EMA is failed! Error», GetLastError );
return (0);
}
if (CopyBuffer (ExtSlowMaHandle,0,0,to_copy, ExtSlowMaBuffer) <=0)
{
Print («Getting slow SMA is failed! Error», GetLastError );
return (0);
}
Если убрать привязку массивов ExtFastMaBuffer [] и ExtSlowMaBuffer [] к буферам индикатора, тогда клиентский терминал выдаст ошибку:
Происходит это потому, что при загрузке индикатора значение to_copy равно размеру ценовой истории, а дальше to_copy=1 и производится частичное копирование в массивы ExtFastMaBuffer [] и ExtSlowMaBuffer [], при этом их размеры становятся равны 1.
В этом случае применением функции ArrayResize проблему не решить, так как функция CopyBuffer все равно будет уменьшать размер массива до 1.
Можно конечно использовать еще один массив-посредник, в который копировать один элемент. И уже из этого массива-посредника производить копирование в промежуточный массив, но проще всего, конечно, просто привязать промежуточный массив к буферу индикатора.
Функции OnInit , OnDeinit , OnCalculate
Как уже говорилось, функции OnInit , OnDeinit , OnCalculate вызываются клиентским терминалом при наступлении определенных событий.
Функция OnInit
Функция OnInit вызывается сразу после загрузки индикатора и соответственно используется для его инициализации.
Инициализация индикатора включает в себя привязку массивов к буферам индикатора, инициализацию глобальных переменных, включая инициализацию хэндлеров используемых индикаторов, а также программную установку свойств индикатора.
Давайте разберем некоторые из этих пунктов более подробно.
Как уже было показано, привязка массивов к буферам индикатора осуществляется с помощью функции SetIndexBuffer:
bool SetIndexBuffer (
int index, // индекс буфера
double buffer [], // массив
ENUM_INDEXBUFFER_TYPE data_type // что будем хранить
);
Где data_type может быть INDICATOR_DATA (данные индикатора для отрисовки, по умолчанию, можно не указывать), INDICATOR_COLOR_INDEX (цвет индикатора), INDICATOR_CALCULATIONS (буфер промежуточных расчетов индикатора).
После применения функции SetIndexBuffer к динамическому массиву, его размер автоматически поддерживается равным количеству баров, доступных индикатору для расчета.