Обсуждение статьи "Как перенести расчетную часть любого индикатора в код эксперта" - страница 3

 

Решил поделиться доработанным под себя Indicator.mqh, может кому сэкономит время при переводе индикатора в класс. 

Файлы:
 
MetaQuotes:

Опубликована новая статья Внедрение расчетов индикатора в код эксперта:

Автор: Дмитрий Гизлык

Взрыв из прошлого.

Действительно, очень интересная статья! Продуманная и красивая концепция... но боюсь, что в распространяемом ПО есть ошибка, а оставлять ошибки вокруг себя нехорошо.


Метод GetData. Распространенный код:

double CIndicator::GetData(const uint buffer_num,const uint shift)
  {
   if(!Calculate())
      return EMPTY_VALUE;
//---
   if((int)buffer_num>=m_buffers)
      return EMPTY_VALUE;
//---
   return ar_IndBuffers[buffer_num].At(m_data_len-shift);
  }

Исправленный код должен быть:

double CIndicator::GetData(const uint buffer_num,const uint shift)
  {
   if(!Calculate())
      return EMPTY_VALUE;
//---
   if((int)buffer_num>=m_buffers)
      return EMPTY_VALUE;
//---
   return ar_IndBuffers[buffer_num].At(m_data_len-shift - 1);
  }

Индекс массива начинается с 0 и последний элемент имеет индекс (m_data_len - 1), а не m_data_len, не так ли?

 

рф, раздел Работа с пользовательскими индикаторами https://www.mql5.com/ru/articles/261

Use of Resources in MQL5
Use of Resources in MQL5
  • www.mql5.com
MQL5 programs not only automate routine calculations, but also can create a full-featured graphical environment. The functions for creating truly interactive controls are now virtually the same rich, as those in classical programming languages. If you want to write a full-fledged stand-alone program in MQL5, use resources in them. Programs with resources are easier to maintain and distribute.
 
Привет, спасибо вам большое
 

Спасибо за статью! Изучаю для ухода от нестабильных обычных индикаторов.

Но мне важна возможность визуализации индикаторов на графике. Кто-нибудь реализовавал?

 

А зачем вообще переносить расчеты из индикатора в советник?

Очень многие используют индикаторы вовсе без советника.

Можно просто разбить расчеты на этапы.

Например так:

//+------------------------------------------------------------------+
//|                                                      FutData.mq5 |
//|                              Copyright 2020 - 2021, prostotrader |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020-2021, prostotrader"
#property link      "https://www.mql5.com"
#property version   "1.001"
//---
#property indicator_separate_window
#property indicator_plots   1
#property indicator_buffers 1
//---
enum IND_STAGE
{
  LOAD_TICKS = 0,
  READ_TICKS = 1,
  READ_DEALS = 2,
  FILL_DATA = 3
} stage;
//+------------------------------------------------------------------+
//| Custom indicator OnInit function                                 |
//+------------------------------------------------------------------+
int OnInit()
{
  stage = LOAD_TICKS;  
//---
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator Load ticks function                             |
//+------------------------------------------------------------------+
bool LoadTicks(const datetime &a_times[])
{
  return(false);
}
//+------------------------------------------------------------------+
//| Custom indicator Read primary ticks function                     |
//+------------------------------------------------------------------+
bool ReadTicks()
{
  return(false);
}
//+------------------------------------------------------------------+
//| Custom indicator Read secondary ticks function                   |
//+------------------------------------------------------------------+
bool ReadDeals()
{
  return(false);
}
//+------------------------------------------------------------------+
//| Custom indicator Fill data function                              |
//+------------------------------------------------------------------+
void FillData()
{
//---
}
//+------------------------------------------------------------------+
//| Custom indicator On Calculate 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(prev_calculated == 0)
  {
      switch (stage)
      {
        case LOAD_TICKS:
          if(LoadTicks(time) == true)
          {
            stage = READ_TICKS;
          }
          return(0);
        break;
        case READ_TICKS:
          if(ReadTicks() == true)
          {
            stage = READ_DEALS;
          }  
          return(0);
        break;
        case READ_DEALS:
          if(ReadDeals() == true)
          {
            stage = FILL_DATA;
          }  
          return(0);
        break;
        case FILL_DATA:
          stage = LOAD_TICKS;
        break;
      }
  }
  else
  {
    //
  }    
  //---
  return(rates_total);
}
//+------------------------------------------------------------------+
 
prostotrader #:

А зачем вообще переносить расчеты из индикатора в советник?

Очень многие используют индикаторы вовсе без советника.

Можно просто разбить расчеты на этапы.

Например так:

Из-за того, что штатный механизм индикаторов работает через пень-колоду, например: https://www.mql5.com/ru/forum/372612 и это обусловлено их реализацией.

С ростом сложности индикаторов мой советник "увяз в болоте". В тестере я словил еще много других багов в работе индикаторов, но не стал их описывать, т.к. бесполезно.

Я не понял вашу идею.

Некорректная инициализация индикаторов в визуальном тестере
Некорректная инициализация индикаторов в визуальном тестере
  • 2021.07.04
  • www.mql5.com
Если делаю инициализацию индикаторов в OnInit() { } эксперта, то в визуальном тестере индикатор обычно не появляется и не отрисовывается...
 
Sunriser #:

Из-за того, что штатный механизм индикаторов работает через пень-колоду, например: https://www.mql5.com/ru/forum/372612 и это обусловлено их реализацией.

С ростом сложности индикаторов мой советник "увяз в болоте". В тестере я словил еще много других багов в работе индикаторов, но не стал их описывать, т.к. бесполезно.

Я не понял вашу идею.

Начнем с того, что у Вас не совсем корректный код.

Я бы написал так:

int OnInit()
  {int  TicksTesterIndicatorHandle = INVALID_HANDLE;
   bool InitComplite=false;
   if(IndicatorInitialization() == false) return(INIT_FAILED);
    return(INIT_SUCCEEDED);
 }
void OnDeinit(const int reason)
{
     if(TicksTesterIndicatorHandle != INVALID_HANDLE) IndicatorRelease(TicksTesterIndicatorHandle);
}
void OnTick()   { //if(!InitComplite)
 //  { //   IndicatorInitialization();
 //  }   } //+------------------------------------------------------------------+
bool IndicatorInitialization()
   { //---Получить хэндл индикатора TicksTesterIndicator
    TicksTesterIndicatorHandle=iCustom(NULL, _Period, "OnInit_TestIndicator");
 //--- Нужно проверить, не были ли возвращены значения Invalid Handle 
  if(TicksTesterIndicatorHandle == INVALID_HANDLE)
      {       Print("Ошибка при создании индикатора TicksTesterIndicator - номер ошибки: ",GetLastError(),"!!!");
      
   }
    else
      { 
      Print("TicksTesterIndicator инициализирован, хэндл: ", TicksTesterIndicatorHandle);
       ArraySetAsSeries(Buf, true);
     InitComplite=true;
     return(true);
   }
    return(false);  
 }

Далее, т.к функции в индикаторах должны выполняться с минимальными задержками, то сложные процессы (загрузка истории, сложные расчеты и т.п)

разбиваются на несколько частей, возвращая в  

OnCalculate

нулевое значение (return(0) ), т.е индикатор находится в начальной стадии, пока мы не выполним все необходимые нам действия с минимальными задержками в каждой стадии.

 
В архитектуре MetaTrader 5 организован асинхронный доступ к значениям индикаторов. Иными словами, при получении хэндла индикатора он прикрепляется к графику. Далее этот индикатор производит свои расчеты вне потока советника. Они взаимодействуют лишь на этапе передачи данных, аналогично получению данных тайм-серий. Поэтому и время на выполнение этих операций сопоставимо.

То есть получается в реале все же icustom будет быстрее?! -Ведь в реальности так и будет. Эксперт в одном треде, индикатор в другом (и может даже на разных ядрах). Это только если из засунуть в последовательную обработку получается медленнее - но это ведь только искуственное ограничение из-за  тестера стратегий

 
Из статьи я не понял, есть ли у класса-индикатора защита от пропущенных баров? К примеру произошел разрыв связи на 5 баров, а потом дальше история загрузилась, класс-индикатор перезаполнит только последнее значение в буере или сделает полный перерасчет?