MQL4 iCustom всегда возвращает одно и то же (неправильное) значение (0x7FFFFFFF)
Я написал собственный индикатор Speed.mq4
следующее:
double SpeedBuffer[]; // a Custom Indicator BUFFER
int OnInit() {
SetIndexBuffer( 0, SpeedBuffer ); // an access INDEX 0->BUFFER
...
}
int OnCalculate( const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]
) {
int start;
if ( prev_calculated == 0 ) start = 1;
else start = prev_calculated - 1;
for ( int i = start; i < rates_total - 1 ; i++ ) { // CPU-WASTED BY AN INEFFICIENT BACK-STEPPING IN TIME
double curTypical = typical( high[i], low[i], close[i] );
double prevTypical = typical( high[i+1],low[i+1],close[i+1] ); // CPU-WASTED, NO NEED TO RECALC ...
double curSpeed = curTypical - prevTypical;
SpeedBuffer[i] = curSpeed;
}
//--- return value of prev_calculated for next call
return( rates_total );
}
Индикатор отлично работает в приложении и график построен правильно.
Когда я пытаюсь получить последнее значение в ExpertAdvisor, я всегда получаю одно и то же значение:
double speed = iCustom( NULL, 0, "Speed", 2, 0, 0 );
Print( "speed is: " + speed );
печатает:
скорость составляет: 2147483647
Это всегда один и тот же номер. Я не уверен, где проблема.
от Print
в индикаторе видно, что значения рассчитаны правильно. но когда я использую iCustom, я получаю только это значение.
3 ответа
Я просмотрел свой код и наконец понял, что:
double speed=iCustom(NULL,0,"Speed",2,0,0);
использовал последнее значение, которое еще не было рассчитано с помощью пользовательского индикатора,
изменив его на:
double speed=iCustom(NULL,0,"Speed",2,0,1);
сделал трюк.
Пользовательский индикатор MQL4 iCustom()
механика
MQL4 и даже New-MQL4 (иногда называемый MQL4.5) используют довольно сложную модель взаимодействия для обработки вызовов эксперта / вызова пользовательских индикаторов.
Первое, что нужно понять, это то, что iCustom()
это не вызов функции, а скорее метод, который косвенно "запрашивает" пользовательский индикатор, указанный по имени файла, для получения одного конкретного значения из "предварительно рассчитанного" DataSTORE.
Несмотря на то, что это может показаться сложным, сама фабрика вычислений с эффективным использованием ЦП является самой природой, для которой пользовательские индикаторы были разработаны в первые годы существования MQL4.
iCustom()
Таким образом, это всего лишь синтаксический сахар для запуска метода поиска, который возвращает соответствующий кусок предварительно рассчитанного значения обратно в руки эксперта.
Пользовательские индикаторы помещают все предварительно вычисленные значения в BUFFER (s), совмещенные со стилем TimeSeries упорядочения ячеек DataSTORE ( [0] == "Сейчас текущий бар", продвигаясь вперед [1], [2], [3], ... глубже и глубже возвращаемся в историю)
iCustom()
проходит shift
значение, как количество баров - то есть, насколько глубоко в истории должен идти метод извлечения, чтобы выбрать запрошенное значение из соответствующего буфера, а также ИНДЕКС идентификации БУФЕРА (0 в нашем случае выше, так как есть только один БУФЕР, с ИНДЕКСОМ == 0
). Это используется для того, чтобы советник был полностью независим от имен внутренних переменных пользовательского индикатора и др.
Просто спросите, какой BufferINDEX для какого BarNUMBER нужно, чтобы значение было считано.
Buffer - это тот, кого нужно обвинить в (неправильном) значении
Первая строка кода говорит:
double SpeedBuffer[]; // a Custom Indicator BUFFER
Если не обработано иначе в OnInit(){}
все ячейки в SpeedBuffer будут иметь EMPTY_VALUE
Пустое значение в буфере индикатора имеет по умолчанию это значение == 2147483647 (0x7FFFFFFF)
как было возражено выше.
QED
Можно заявить в OnInit(){ ArrayInitialize( SpeedBuffer, 0.123456 ); }
иметь любое другое значение для инициализации ячейки (что для буфера Buffers с выравниванием по TimeSeries происходит при каждом событии new-Bar) (все ячейки перетасовываются на один назад, а ячейка [0] становится "пустой", предварительно загруженной со значением по умолчанию) обсуждается здесь)).
Можно также добавить шаг в индикатор OnCalculate(){ ... SpeedBuffer[0] = -9.87654; ...}
чтобы не оставлять ячейку [0] в несовместимом с контекстом состоянии, а не в "только" инициализированном состоянии / значении.
Интерфейс на стороне вызывающего абонента (как снизить риск на интерфейсе слабой интеграции)
Тем не менее, ответственность за поиск значения лежит на эксперте, так как он заполняет параметры iCustom()
Интерфейс-прокси.
Можно использовать предупреждающие шаги, как показано в >>> /questions/18052841/mql4-kodirovanie-pustogo-bufera-v-stroke/18052844#18052844 чтобы минимизировать риск неправильного упорядочения / значения параметров при вызове внешнего пользовательского индикатора (ов) для получения набора значений.
Этот простой метод может сэкономить вам буквально десятки человеко-дней тестирования / отладки extern
-параметрический пользовательский индикатор с несколькими индикаторными буферами попал в число подозреваемых из-за обслуживания "неправильных" чисел (просто из-за iCustom()
параметры вызова " невидимы " из правильного порядка / контекста)
Еще одна вещь, которую нужно иметь в виду, когда пользовательский индикатор показывает другие значения на диаграмме, а затем сообщается в ExpertAdvisor, заключается в том, что поток выполнения через OnCalculate() должен отличаться для ExpertAdvisor, чем для диаграммы; в частности, график изначально запускает вызов OnCalculate() с prev_calculated = 0, тогда как советник (работает ли он с тестером стратегий или в режиме реального времени) всегда будет иметь prev_calculated = rate_total-1, так что количество баров для вычисления значения индикатора for is rate_total - prev_calcualted = 1 (т.е. только текущий бар).
Вы учитываете это в своем коде, устанавливая start, но в целом для сложного индикатора (который часто включает в себя ссылки не только на предыдущий бар), нужно помнить об этой разнице и никогда не предполагать, что если индикатор выглядит хорошо на график, который означает, что это на самом деле работает. Это нужно тестировать отдельно с экспертом.