Базовые индикаторы, применяемые к кастомному инструменту - страница 2

 
Более грамотный подход к работе с индикаторными буферами
// МАшка на любом количестве кастомных данных
#property indicator_separate_window 
#property indicator_buffers 5 // здесь задаем желаемое количество кастомных данных
#property indicator_plots   indicator_buffers

input int CustomData = WRONG_VALUE; // true - кастомный режим для iCustom
input int MAPeriod = 1e2;           // Период МАшки

const bool FlagCustomData = (CustomData != WRONG_VALUE);

#include <Graphics\ColorGenerator.mqh>

CColorGenerator Color;

class BUFFER
{
private:
  static int Amount;

  const int handleMA;
  double Buffer[];

  static string GetMyName()
  {
    const int Length = StringLen(TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Indicators\\");
    const string Path = MQLInfoString(MQL_PROGRAM_PATH);
    
    return(StringSubstr(Path, Length, StringLen(Path) - Length - 4));
  }
    
public:  
  BUFFER() : handleMA(FlagCustomData ? INVALID_HANDLE
                                     : iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, BUFFER::GetMyName(), BUFFER::Amount)))
  {
    if (!FlagCustomData || !BUFFER::Amount)
    {
      SetIndexBuffer(BUFFER::Amount, this.Buffer, INDICATOR_DATA);
  
      PlotIndexSetInteger(BUFFER::Amount, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(BUFFER::Amount, PLOT_LINE_COLOR, Color.Next());
      PlotIndexSetString(BUFFER::Amount, PLOT_LABEL, "Buffer" + (string)BUFFER::Amount);       
      
      BUFFER::Amount++;
    }
  }
  
  int Calc( const int prev_calculated, const int rates_total )
  {
    if (FlagCustomData)
      for (int i = prev_calculated; i < rates_total; i++)
        this.Buffer[i] = MathRand() * (CustomData + 1); // Подготовили данные
    
    return(FlagCustomData ? rates_total : prev_calculated + CopyBuffer(this.handleMA, 0, prev_calculated, rates_total - prev_calculated, this.Buffer));
  }
  
  static int GetAmount()
  {
    return(BUFFER::Amount);
  }
};

int BUFFER::Amount = 0;

BUFFER Buffers[indicator_buffers];

int OnCalculate( const int rates_total,      // размер входных таймсерий 
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time 
                 const double& open[],       // Open 
                 const double& high[],       // High 
                 const double& low[],        // Low 
                 const double& close[],      // Close 
                 const long& tick_volume[],  // Tick Volume 
                 const long& volume[],       // Real Volume 
                 const int& spread[] )       // Spread 
{
  int Res = rates_total;
    
  for (int i = 0; i < BUFFER::GetAmount(); i++)
    Res = MathMin(Res, Buffers[i].Calc(prev_calculated, rates_total));
  
  return(Res);
}


 
fxsaber:

Возможно, мы неправильно поняли друг друга. Это имел в виду

Стандартные индикаторы, конечно, считают только нулевые буферы в режиме хэндла. Поэтому для каждого буфера нужно делать свой хэндл.


Прошу разжевать:

input int CustomData = WRONG_VALUE; // Для кастомного режима iCustom

пусть будет всегда false и соответственно будет

const int handleMA0 = iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 0));
const int handleMA1 = iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 1));

Дальше

iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 0)

как я понимаю это хендл "самого себя", но... по справке

int  iCustom( 
   string           symbol,     // имя символа 
   ENUM_TIMEFRAMES  period,     // период 
   string           name        // папка/имя_пользовательского индикатора 
   ...                          // список входных параметров индикатора 
   );

получается, что в зоне параметров индикатора указывается номер буфера, а входящие параметры игнорируются???

А что за обозначение периода МА?

input int MAPeriod = 1e2;           // Период МАшки
 
Alexey Viktorov:

Прошу разжевать:

пусть будет всегда false и соответственно будет

Нужен тип с бОльшим количеством значений, поэтому int.

получается, что в зоне параметров индикатора указывается номер буфера, а входящие параметры игнорируются???

Все в точности со Справкой там. Никакой буфер не указывается.

А что за обозначение периода МА?

Это степень десятки.

 
fxsaber:

Нужен тип с бОльшим количеством значений, поэтому int.

Все в точности со Справкой там. Никакой буфер не указывается.

Это степень десятки.

Я не ту строку скопировал из кода. Имел ввиду эту

const bool FlagCustomData = (CustomData != WRONG_VALUE);

Но это не проблема...

Если всё в точности со справкой, то как получается, что input переменных две

input int CustomData = WRONG_VALUE; // Для кастомного режима iCustom
input int MAPeriod = 1e2;           // Период МАшки

а в iCustom вводится только одна? Вот это и вводит в заблуждение.

iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 0)

Дальше опять одни вопросы без понимания.

Здесь

    for (int i = prev_calculated; i < rates_total; i++)
      Buffer0[i] = MathRand() * (CustomData + 1); // Подготовили данные

подготовлен только один буфер и только он один получается в iMA по хендлу. Так?

А если надо два буфера, например берём в один буфер Open в другой Close и потом по iMA этих двух буферов надо построить, скажем DRAW_FILLING использующий тоже два буфера.

 
Alexey Viktorov:

Если всё в точности со справкой, то как получается, что input переменных две

а в iCustom вводится только одна? Вот это и вводит в заблуждение.

Не указанные входные параметры принимают значения по-умолчанию.

подготовлен только один буфер и только он один получается в iMA по хендлу. Так?

Да.

А если надо два буфера, например берём в один буфер Open в другой Close и потом по iMA этих двух буферов надо построить, скажем DRAW_FILLING использующий тоже два буфера.

Так там два буфера и работают. Обратите внимание, что там два хэндла MA.


Если дружите с ООП, то этот вариант на любое количество буферов должен быть понятней.

 
fxsaber:

Не указанные входные параметры принимают значения по-умолчанию.

Да.

Так там два буфера и работают. Обратите внимание, что там два хэндла MA.


Если дружите с ООП, то этот вариант на любое количество буферов должен быть понятней.

Два хендла по данным одного буфера, а я спрашивал о двух исходных буферах.

Я-то подружился-бы с ООП, но она не хочет со мной дружить. Только дразнится...

 
Alexey Viktorov:

Два хендла по данным одного буфера, а я спрашивал о двух исходных буферах.

Напишите, какой индикатор нужно сделать. Так проще будет.

 
fxsaber:

Напишите, какой индикатор нужно сделать. Так проще будет.

Надеюсь достаточно будет грубой заготовки.

У меня нет желания, чтобы за меня кто-то сделал. Я хочу в этом разобраться, понять.

double maOpen[], maClose[];
int OnInit()
  {
//--- indicator buffers mapping
   handOpen = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_SMMA, PRICE_OPEN);
   handClose = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_SMMA, PRICE_CLOSE);
  }

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 copyOp = CopyBuffer(handOpen, 0, 0, rates_total, maOpen);
   int copyCl = CopyBuffer(handClose, 0, 0, rates_total, maClose);

  }

Дальше надо массивы maOpen и maClose усреднить по типу как в mql4 iMAOnArray и на полученных данных построить гистограммы или DRAW_FILLING.

Первый вариант уже проверен, работает. Получившийся из этого индикатор прицепить в другом индикаторе ресурсом и получив хендл этого индикатора скопируем 2 буфера которые и будем использовать. Проверено на другом индикаторе. А когда начал писать этот увидел ваши примеры, но понять не смог пока как.

Второй, воспользоваться библиотекой MovingAverages.mqh, но пока не разбирался в ней и что-то не хочется... Мне проще сделать первый вариант.


Ой... Пока писал, что-то родилось, не до конца понятое...

handOpen = iMA(_Symbol, PERIOD_CURRENT, 3, 0, MODE_SMMA, iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_SMMA, PRICE_OPEN));

Сейчас проверю.

Но, это вариант по данным индикатора. А если готовить данные по какой либо формуле, то этот вариант не пойдёт. Так-что жду вашего варианта.

 
Alexey Viktorov:
Надеюсь достаточно будет грубой заготовки.

У меня нет желания, чтобы за меня кто-то сделал. Я хочу в этом разобраться, понять.

Дальше надо массивы maOpen и maClose усреднить по типу как в mql4 iMAOnArray и на полученных данных построить гистограммы или DRAW_FILLING.

Первый вариант уже проверен, работает. Получившийся из этого индикатор прицепить в другом индикаторе ресурсом и получив хендл этого индикатора скопируем 2 буфера которые и будем использовать. Проверено на другом индикаторе. А когда начал писать этот увидел ваши примеры, но понять не смог пока как.

Второй, воспользоваться библиотекой MovingAverages.mqh, но пока не разбирался в ней и что-то не хочется... Мне проще сделать первый вариант.


Ой... Пока писал, что-то родилось, не до конца понятое...

Сейчас проверю.

Но, это вариант по данным индикатора. А если готовить данные по какой либо формуле, то этот вариант не пойдёт. Так-что жду вашего варианта.

Рабочим кодом должен быть этот

// МАшка на двух кастомных данных - DRAW_FILLING
#property indicator_chart_window 
#property indicator_buffers 2 
#property indicator_plots   1 

#property indicator_type1   DRAW_FILLING 
#property indicator_color1  clrRed, clrBlue 
#property indicator_width1  1 

input int CustomData = WRONG_VALUE; // Для кастомного режима iCustom
input int MAPeriod = 5;             // Период МАшки

string GetMyName( void )
{
  const int Length = StringLen(TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Indicators\\");
  const string Path = MQLInfoString(MQL_PROGRAM_PATH);
  
  return(StringSubstr(Path, Length, StringLen(Path) - Length - 4));
}

const bool FlagCustomData = (CustomData != WRONG_VALUE);

double Buffer0[], Buffer1[];
const bool Init = SetIndexBuffer(0, Buffer0, INDICATOR_DATA) && (!FlagCustomData) && SetIndexBuffer(1, Buffer1, INDICATOR_DATA);

const int handleMA0 = FlagCustomData ? iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_SMA, CustomData ? PRICE_OPEN : PRICE_CLOSE)
                                     : iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 0));
const int handleMA1 = FlagCustomData ? INVALID_HANDLE
                                     : iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 1));

int OnCalculate( const int rates_total,      // размер входных таймсерий 
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time 
                 const double& open[],       // Open 
                 const double& high[],       // High 
                 const double& low[],        // Low 
                 const double& close[],      // Close 
                 const long& tick_volume[],  // Tick Volume 
                 const long& volume[],       // Real Volume 
                 const int& spread[] )       // Spread 
{
  return(prev_calculated + (FlagCustomData ? CopyBuffer(handleMA0, 0, prev_calculated, rates_total - prev_calculated, Buffer0)
                                           : MathMin(CopyBuffer(handleMA0, 0, prev_calculated, rates_total - prev_calculated, Buffer0),
                                                     CopyBuffer(handleMA1, 0, prev_calculated, rates_total - prev_calculated, Buffer1))));
}

Но обнаружился баг в MT5, поэтому до исправления он работать не будет - iMA от iMA через кастомный хэндл.


А пока баг не исправили, вот так будет работать

// МАшка на двух кастомных данных - DRAW_FILLING
#property indicator_chart_window 
#property indicator_buffers 2 
#property indicator_plots   1 

#property indicator_type1   DRAW_FILLING 
#property indicator_color1  clrRed, clrBlue 
#property indicator_width1  1 

input int CustomData = WRONG_VALUE; // Для кастомного режима iCustom
input int MAPeriod = 5;             // Период МАшки

string GetMyName( void )
{
  const int Length = StringLen(TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Indicators\\");
  const string Path = MQLInfoString(MQL_PROGRAM_PATH);
  
  return(StringSubstr(Path, Length, StringLen(Path) - Length - 4));
}

const bool FlagCustomData = (CustomData != WRONG_VALUE);

double Buffer0[], Buffer1[];
const bool Init = SetIndexBuffer(0, Buffer0, INDICATOR_DATA) && (!FlagCustomData) && SetIndexBuffer(1, Buffer1, INDICATOR_DATA);

const int handleMA0 = FlagCustomData ? INVALID_HANDLE
                                     : iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 0));
const int handleMA1 = FlagCustomData ? INVALID_HANDLE
                                     : iMA(NULL, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, iCustom(_Symbol, PERIOD_CURRENT, GetMyName(), 1));

int OnCalculate( const int rates_total,      // размер входных таймсерий 
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time 
                 const double& open[],       // Open 
                 const double& high[],       // High 
                 const double& low[],        // Low 
                 const double& close[],      // Close 
                 const long& tick_volume[],  // Tick Volume 
                 const long& volume[],       // Real Volume 
                 const int& spread[] )       // Spread 
{
  if (FlagCustomData)
  {
    if (CustomData)
      ArrayCopy(Buffer0, open, prev_calculated, prev_calculated);  // забиваем нужными значениями массив для нулевого буфера.
    else
      ArrayCopy(Buffer0, close, prev_calculated, prev_calculated); // забиваем нужными значениями массив для первого буфера.
  }
  
  return(FlagCustomData ? rates_total : prev_calculated + MathMin(CopyBuffer(handleMA0, 0, prev_calculated, rates_total - prev_calculated, Buffer0),
                                                                  CopyBuffer(handleMA1, 0, prev_calculated, rates_total - prev_calculated, Buffer1)));
}
 
fxsaber:

Рабочим кодом должен быть этот

Но обнаружился баг в MT5, поэтому до исправления он работать не будет - iMA от iMA через кастомный хэндл.


А пока баг не исправили, вот так будет работать

Спасибо. Пробую прожевать...

Причина обращения: