[SOLVED] Индикаторы неправильно инстанцируются при вызове/создании из индикатора другого рабочего таймфрейма.
Боюсь, что это не ошибка в MT5, а ошибка в вашем коде. Кстати, как и во всех других темах, о которых вы сообщаете. Вы должны иметь дело с платформой/языком так, как он был разработан, а не так, как вы думаете или хотите, чтобы было.
Почему вы используете ima.Create() в OnCalculate()? Вы получаете хэндл, но данные еще не доступны, вы получаете ошибку, затем ваш код больше никогда не вызывается.
P.S: Что значит "Работает без доступа к данным." ?Боюсь, что это не ошибка в MT5, а ошибка в вашем коде. Кстати, как и во всех других темах, о которых вы сообщаете. Вы должны иметь дело с платформой/языком так, как он был разработан, а не так, как вы думаете или хотели бы.
Почему вы используете ima.Create() в OnCalculate()? Вы получаете хэндл, но данные еще не доступны, вы получаете ошибку, затем ваш код больше никогда не вызывается.
P.S: Что значит "Работает без доступа к данным." ?Боюсь, что это действительно ошибка в платформе. Я запускаю точно такой же блок кода в OnInit() в эксперте и не получаю никаких ошибок, в то время как OnInit() в индикаторе выбрасывает ошибки. Работа без доступа к данным означает, что он работает в автономном режиме, в тестере или в нерабочее время. Вызов любого индикатора должен инстанцировать его из любого места в любое время, и тот факт, что платформа непоследовательна в этом отношении, означает, что это не особенность, а ошибка. Наличие ima.Create внутри oncalculate - это просто пример, потому что он также не инстанцирует индикатор на любом другом таймфрейме - из любого места, где вы вызываете его внутри индикатора, до первого тика (обновления данных). Еще раз хочу подчеркнуть, что это работает корректно из любого места в экспертах и скриптах, просто в индикаторах это как-то нарушено.
Вы не верите мне, это ваше право, но вы ошибаетесь.
Я могу только посоветовать вам написать в ServiceDesk и, пожалуйста, сообщить об их ответе здесь.
Вы не верите мне, это ваше право, но вы ошибаетесь.
Я могу только предложить вам написать в ServiceDesk, и, пожалуйста, сообщите об их ответе здесь.
Спасибо, так и сделаю. Если я не прав, то почему именно в экспертах и скриптах это работает, а от индикаторов нет?
Потому что все индикаторы для символа работают в одном потоке. Тестер стратегий, советник и скрипт - это разные ситуации.
Хотя посмотрим на ответ ServiceDesk. Может я не прав :-)
Потому что все индикаторы для символа работают в одном потоке. Тестер стратегий, советник и скрипт - это разные ситуации.
Хотя посмотрим на ответ ServiceDesk. Возможно, я ошибаюсь :-)
Давайте считать, что это так...
- Почему можно инстанцировать индикатор того же таймфрейма и сразу получить доступ к его данным, а другого таймфрейма - нет?
- Почему вы можете инстанцировать индикатор того же таймфрейма и сразу же получить доступ к его данным?
На самом деле это означает, что вам повезло, что данные уже доступны. Это не гарантировано. Это также может не сработать.
Это означает, что если данные немедленно доступны скрипту или советнику, то они будут также доступны и индикатору (т.е. это не проблема доступности данных). Индикатор просто не успевает инстанцироваться до второго прохода OnCalculate() (он же первый тик).
Я принял это во внимание во время диагностики. Я даже включил циклы и период ожидания, на всякий случай. Как и все до меня, у меня те же проблемы с этой конкретной ошибкой.
Это означает, что если данные немедленно доступны скрипту или советнику, то они будут также доступны и индикатору (т.е. это не проблема доступности данных). Индикатор просто не успевает инстанцироваться до второго прохода OnCalculate() (он же первый тик).
Я принял это во внимание во время диагностики. Я даже включил циклы и период ожидания, на всякий случай. Как и все до меня, у меня те же проблемы с этим конкретным багом.
Вы повторяете "не удается инстанцировать", но это не точно. Индикатор инстанцируется во всех случаях.
Проблема в том, что данные не доступны синхронно, с этим нужно смириться. Это НЕ баг МТ5, это СЛОЖНОСТЬ.
Предлагаю прекратить дискуссию и подождать ответа SD.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
ОБНОВЛЕНИЕ: см. обходной путь ниже
CopyBuffer() выбрасывает ошибку 4806 (Данные индикатора недоступны) при вызове индикатора с другим тайм-фреймом из кода индикатора. Это происходит при вызове действительного хэндла индикатора с таймфреймом, отличным от текущего рабочего таймфрейма. Ошибка проявляется только во время инициализации и первого вызова OnCalculate() ДО первого тика данных. Для того чтобы изолировать ошибку, были применены следующие методы:
Этот блок кода используется для проверки вывода CopyBuffer() при вызове из скрипта, советника и индикатора.
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
int total = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",total);
for(int i=0;i<total;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCSIG__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
Полный код индикатора:
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
static int iCnt = 0;
//--- indicator buffers mapping
Print("-----------------------",TimeCurrent(),"--------------------------");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",m_bufferSize);
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
Единственный способ не получить ошибку - запустить его на графиках H1 (тот же TF).
Ссылки на сообщение на форуме с той же проблемой:
https://www.mql5.com/en/forum/73274
https://www.mql5.com/en/forum/13676
https://www.mql5.com/en/forum/30958
https://www.mql5.com/en/forum/16614
РЕШЕНИЕ ПРОБЛЕМЫ:
Обходным решением было создание индикатора в OnInit() и установка EventSetMillisecondTimer на 1 мс. Это позволило OnCalculate() вернуться после первого прохода и быстро вызвать OnTimer для второго прохода. Для фиксации потребовался только один вызов события OnTimer, и дальнейшая временная задержка для вычислений не требовалась.
//| THROWAWAY.mq5 |
//| nicholishen |
//| www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link "www.reddit.com/u/nicholishenFX"
#property version "1.00"
#property indicator_chart_window
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
bool timedEvent = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int waitMS = 1;
Print("-----------------------",TimeCurrent(),"--------------------------");
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
EventSetMillisecondTimer(waitMS);
Print("OnTimer set to ",waitMS," ms");
//---
return(INIT_SUCCEEDED);
}
void OnTimer()
{
//---
ima.Refresh();
EventKillTimer();
timedEvent = true;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
static int tickCnt = 0;
tickCnt++;
if(!timedEvent)return rates_total;
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
if(m_bufferSize <=0) ima.Refresh();
// try wait with looping
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__,buff.Name(),
" Buffer size = ",m_bufferSize,
" | ",ima.PeriodDescription()," iMA(",i,") value = ",
DoubleToString(ima.Main(i),_Digits),
" | Tick-count = ",tickCnt
);
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+