Использование стиля рисования DRAW_COLOR_ARROW

 

Я цветные индикаторы особо не писал ни разу. И вообще с индюками не особо работал. Вот решил написать некоторые вещи. Оказалось, что не всё так, как хотелось бы.

Если используется стиль рисования DRAW_ARROW, то всё работает как и ожидается. Вот, например:

//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                                                                                  InsideBar.mq5 |
//|                                                                                                                                                                            hoz |
//|                                                                                                                                                                                |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
#property copyright "hoz"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrRed
#property indicator_width1  2

#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrBlue
#property indicator_width2  2

double upper_buffer[];
double lower_buffer[];
int    firstBarIndexToCalculate;

input int  arrowShift = 1;
input int barsToCalculate = 1390;
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator initialization function                                                                                                                                       |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int OnInit() {
//---
  IndicatorSetString(INDICATOR_SHORTNAME, "Inside Bar");
  IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

  SetIndexBuffer(0, upper_buffer, INDICATOR_DATA);
  PlotIndexSetInteger(0, PLOT_ARROW, 159);        
  PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, -arrowShift);
  PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);

  SetIndexBuffer(1, lower_buffer, INDICATOR_DATA);
  PlotIndexSetInteger(1, PLOT_ARROW, 159);
  PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, arrowShift);
  PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);  
  
  return INIT_SUCCEEDED;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Поиск паттерна Inside Bar                                                                                                                                                      |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void findInsideBar(const double& high[], const double& low[], int index) {
//---
  if (high[index + 1] <= high[index + 2] && low[index + 1] >= low[index + 2]) {
    upper_buffer[index] = low[index];
    lower_buffer[index] = high[index];
  } else {
    upper_buffer[index] = EMPTY_VALUE;
    lower_buffer[index] = EMPTY_VALUE;
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Расчет значений индикатора                                                                                                                                                     |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void checkingPattern(const double& high[], const double& low[], int limit) {
  for (int i = limit; i > 0; i--) {
    findInsideBar(high, low, i);
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Определение индекса бара, с которого необходимо производить перерасчет                                                                                                         |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int recalcIndex(int barsTotal, int calculatedYet) {
  firstBarIndexToCalculate = barsTotal - 2;
  
  if (barsToCalculate > 0 && barsToCalculate < firstBarIndexToCalculate) {    // Если не нужно рассчитывать всю..
    firstBarIndexToCalculate = barsToCalculate;                               // ..историю, то начнем с указанного..
  }

  if (calculatedYet == 0) {
    ArrayInitialize(upper_buffer, EMPTY_VALUE);
    ArrayInitialize(lower_buffer, EMPTY_VALUE);
    return (firstBarIndexToCalculate - 1);
  }
  return 2;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| 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[]) {
//---
  int limit = recalcIndex(rates_total, prev_calculated);
  checkingPattern(high, low, limit);
//---
  return rates_total;
}

А если нужно использовать стиль рисования DRAW_COLOR_ARROW как быть?

Как я понимаю, исходя из справки, буфер у стиля рисования DRAW_ARROW лишь 1. Это буфер значений. А у стиля рисования DRAW_COLOR_ARROW должно быть уже 2 буфера - буфер значений и буфер цвета. Тем не менее, я вижу, что у обоих стилей цвет задаётся директивами компилятора. Какой тогда смысл в этом?

Необходимо использовать функцию?

SetIndexBuffer(1, upperColor1Buf, INDICATOR_COLOR_INDEX);

Только не особо понятно как эта функция присваивает свойство т.е. к какому буферу.

Я по аналогии вышеприведённого кода написал такой код, где индикатор уже должен отрисовывать именно DRAW_COLOR_ARROW, а не DRAW_ARROW как в предыдущем коде.

Всё остальное неизменно.

//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                                                                                  InsideBar.mq5 |
//|                                                                                                                                                                            hoz |
//|                                                                                                                                                                                |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
#property copyright "hoz"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 2

#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1 clrRed
#property indicator_width1  2

#property indicator_type3 DRAW_COLOR_ARROW
#property indicator_color3 clrBlue
#property indicator_width3  2

double upper_buffer[];
double upperColor1Buf[];
double lower_buffer[];
double lowerColor2Buf[];
int    firstBarIndexToCalculate;

input int arrowShift = 1;
input int barsToCalculate = 1390;
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator initialization function                                                                                                                                       |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int OnInit() {
//---
  IndicatorSetString(INDICATOR_SHORTNAME, "Inside Bar");
  IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

  SetIndexBuffer(0, upper_buffer, INDICATOR_DATA);
  SetIndexBuffer(1, upperColor1Buf, INDICATOR_COLOR_INDEX);
  PlotIndexSetInteger(0, PLOT_ARROW, 159);        
  PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, arrowShift);
  PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);

  SetIndexBuffer(2, lower_buffer, INDICATOR_DATA);
  SetIndexBuffer(3, lowerColor2Buf, INDICATOR_COLOR_INDEX);
  PlotIndexSetInteger(2, PLOT_ARROW, 159);
  PlotIndexSetInteger(2, PLOT_ARROW_SHIFT, -arrowShift);
  PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);  

//  ArraySetAsSeries(upper_buffer, true);
  //ArraySetAsSeries(lower_buffer, true);
    
  return INIT_SUCCEEDED;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Поиск паттерна Inside Bar                                                                                                                                                      |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void findInsideBar(const double& high[], const double& low[], int index) {
//---
  if (high[index + 1] <= high[index + 2] && low[index + 1] >= low[index + 2]) {
    upper_buffer[index] = low[index];
    upperColor1Buf[index] = clrBlack;
    lower_buffer[index] = high[index];
    lowerColor2Buf[index] = clrBlack;
  } else {
    upper_buffer[index] = EMPTY_VALUE;
    lower_buffer[index] = EMPTY_VALUE;
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Расчет значений индикатора                                                                                                                                                     |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void checkingPattern(const double& high[], const double& low[], int limit) {
  for (int i = limit; i > 0; i--) {
    findInsideBar(high, low, i);
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Определение индекса бара, с которого необходимо производить перерасчет                                                                                                         |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int recalcIndex(int barsTotal, int calculatedYet) {
  firstBarIndexToCalculate = barsTotal - 2;
  
  if (barsToCalculate > 0 && barsToCalculate < firstBarIndexToCalculate) {    // Если не нужно рассчитывать всю..
    firstBarIndexToCalculate = barsToCalculate;                               // ..историю, то начнем с указанного..
  }

  if (calculatedYet == 0) {
    ArrayInitialize(upper_buffer, EMPTY_VALUE);
    ArrayInitialize(lower_buffer, EMPTY_VALUE);
    return (firstBarIndexToCalculate - 1);
  }
  return 2;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| 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[]) {
//---
  int limit = recalcIndex(rates_total, prev_calculated);
  checkingPattern(high, low, limit);

  return rates_total;
}

Почему отрисовывается лишь снизу кружочек? Ведь у меня их 2 должно быть..

Файлы:
 

Примеры для DRAW_COLOR_ARROW

Поиск - MQL5.community
Поиск - MQL5.community
  • www.mql5.com
Поиск выполняется с учетом морфологии и без учета регистра. Все буквы, независимо от того, как они введены, будут рассматриваться как строчные. По умолчанию наш поиск показывает страницы...
 
Виктор Демихов:

Я цветные индикаторы особо не писал ни разу. И вообще с индюками не особо работал. Вот решил написать некоторые вещи. Оказалось, что не всё так, как хотелось бы.

Если используется стиль рисования DRAW_ARROW, то всё работает как и ожидается. Вот, например:

А если нужно использовать стиль рисования DRAW_COLOR_ARROW как быть?

Как я понимаю, исходя из справки, буфер у стиля рисования DRAW_ARROW лишь 1. Это буфер значений. А у стиля рисования DRAW_COLOR_ARROW должно быть уже 2 буфера - буфер значений и буфер цвета. Тем не менее, я вижу, что у обоих стилей цвет задаётся директивами компилятора. Какой тогда смысл в этом?

Необходимо использовать функцию?

Только не особо понятно как эта функция присваивает свойство т.е. к какому буферу.

Я по аналогии вышеприведённого кода написал такой код, где индикатор уже должен отрисовывать именно DRAW_COLOR_ARROW, а не DRAW_ARROW как в предыдущем коде.

Всё остальное неизменно.

Почему отрисовывается лишь снизу кружочек? Ведь у меня их 2 должно быть..

Буферов должно быть 2, а построений 1.

#property indicator_buffers 2
#property indicator_plots 1

#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1 clrRed,clrBlue
#property indicator_width1  2

Затем в зависимости от условий в буфер заносится значение high или low и в буфер цвета заносится 0—красный или 1—синий.

 
Vladimir Karputov:

Примеры для DRAW_COLOR_ARROW

Конечно, я это смотрел. Меня интересует реализация, когда 2 будфера и 2 цвета. У каждого буфера - свой цвет. Я такого варианта не нашёл в кодобазе.

 
Alexey Viktorov:

Буферов должно быть 2, а построений 1.

Затем в зависимости от условий в буфер заносится значение high или low и в буфер цвета заносится 0—красный или 1—синий.

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

Файлы:
 

Потренируйтесь сначала с добавлением разных индикаторных буферов через Мастер MQL и смотрите в файле как что пронумеровано... постепенно дойдет.

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

Два буфера и два цвета - это просто буфер со стрелками одноцветный - и таких два.

 
Виктор Демихов:

Конечно, я это смотрел. Меня интересует реализация, когда 2 будфера и 2 цвета. У каждого буфера - свой цвет. Я такого варианта не нашёл в кодобазе.

Самый простой способ - используйте MQL Wizard для создания индикатора. Он корректно пропишет буферы и цвета.

Пример:

Сгенерированный код

//+------------------------------------------------------------------+
//|                                         Two DRAW_COLOR_ARROW.mq5 |
//|                              Copyright © 2020, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020, Vladimir Karputov"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   2
//--- plot One
#property indicator_label1  "One"
#property indicator_type1   DRAW_COLOR_ARROW
#property indicator_color1  clrRed,clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Two
#property indicator_label2  "Two"
#property indicator_type2   DRAW_COLOR_ARROW
#property indicator_color2  clrDeepPink,clrFuchsia
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- input parameters
input int      Input1=9;
//--- indicator buffers
double         OneBuffer[];
double         OneColors[];
double         TwoBuffer[];
double         TwoColors[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,OneBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,OneColors,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,TwoBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,TwoColors,INDICATOR_COLOR_INDEX);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   PlotIndexSetInteger(0,PLOT_ARROW,159);
   PlotIndexSetInteger(1,PLOT_ARROW,159);
   
//---
   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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
Как самому создать советника или индикатор - Алгоритмический трейдинг, торговые роботы - Справка по MetaTrader 5
Как самому создать советника или индикатор - Алгоритмический трейдинг, торговые роботы - Справка по MetaTrader 5
  • www.metatrader5.com
Для разработки торговых систем в платформу встроен собственный язык программирования MetaQuotes Language 5 (MQL5), среда разработки MetaEditor и инструменты тестирования стратегий. Любую информацию о разработке торговых стратегий на языке MQL5 можно найти на официальном сайте MQL5.community. На этом же сайте в разделе Code Base могут быть...
Файлы:
 

Благодарю за подсказку. Как-то я сразу не взялся за конструктор.. Да, здесь странная логика. Буферы для отрисовки почему-то отдельно, а остальные буферы отдельно. Это и вызвало недопонимание первоначальное. Теперь всё уже понятно. Кроме одного момента. Вот что у меня получилось в тестовом индюке, который я накидал лишь для того, чтобы понять как отрисовываются стрелочки, которые нужно, опять-таки, лишь для удобства отображения:

#property copyright "hoz"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 2

#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1  clrRed, clrTurquoise, clrLightSkyBlue, clrGoldenrod
#property indicator_width1  2

#property indicator_type2 DRAW_COLOR_ARROW
#property indicator_color2  clrIndigo, clrAzure, clrSienna
#property indicator_width2  2

double upperArrowBuffer[];
double upperArrowColor[];
double lowerArrowBuffer[];
double lowerArrowColor[];
int    firstBarIndexToCalculate;

input int arrowShift = 5;
input int barsToCalculate = 1390;
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator initialization function                                                                                                                                       |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int OnInit() {
//---
  IndicatorSetString(INDICATOR_SHORTNAME, "Inside Bar");
  IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

  SetIndexBuffer(0, upperArrowBuffer, INDICATOR_DATA);
  SetIndexBuffer(1, upperArrowColor, INDICATOR_COLOR_INDEX);
  PlotIndexSetInteger(0, PLOT_ARROW, 218);        
  PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, arrowShift);
  PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);

  SetIndexBuffer(2, lowerArrowBuffer, INDICATOR_DATA);
  SetIndexBuffer(3, lowerArrowColor, INDICATOR_COLOR_INDEX);
  PlotIndexSetInteger(1, PLOT_ARROW, 217);
  PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, -arrowShift);
  PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);  

//  ArraySetAsSeries(upperArrowBuffer, true);
  //ArraySetAsSeries(lowerArrowBuffer, true);
    
  return INIT_SUCCEEDED;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Поиск паттерна Inside Bar                                                                                                                                                      |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void findInsideBar(const double& high[], const double& low[], int index) {
//---
  if (high[index + 1] <= high[index + 2] && low[index + 1] >= low[index + 2]) {
    upperArrowBuffer[index] = low[index];
    lowerArrowBuffer[index] = high[index];
  } else {
    upperArrowBuffer[index] = EMPTY_VALUE;
    lowerArrowBuffer[index] = EMPTY_VALUE;
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Расчет значений индикатора                                                                                                                                                     |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void checkingPattern(const double& high[], const double& low[], int limit) {
  for (int i = limit; i > 0; i--) {
    findInsideBar(high, low, i);
  }
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Определение индекса бара, с которого необходимо производить перерасчет                                                                                                         |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int recalcIndex(int barsTotal, int calculatedYet) {
  firstBarIndexToCalculate = barsTotal - 2;
  
  if (barsToCalculate > 0 && barsToCalculate < firstBarIndexToCalculate) {    // Если не нужно рассчитывать всю..
    firstBarIndexToCalculate = barsToCalculate;                               // ..историю, то начнем с указанного..
  }

  if (calculatedYet == 0) {
    ArrayInitialize(upperArrowBuffer, EMPTY_VALUE);
    ArrayInitialize(lowerArrowBuffer, EMPTY_VALUE);
    return (firstBarIndexToCalculate - 1);
  }
  return 2;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| 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[]) {
//---
  int limit = recalcIndex(rates_total, prev_calculated);
  checkingPattern(high, low, limit);

  return rates_total;
}

Вот что я вижу на графике:


В итоге, всё верно отображается, кроме одного момента. Цвет верхней стрелочки не соответствует заданному. Почему?

 
Виктор Демихов:

В итоге, всё верно отображается, кроме одного момента. Цвет верхней стрелочки не соответствует заданному. Почему?

Потому, что вы его не задаёте.

 
Не присваиваете значения буферам для цветовых индексов.
 

Присваивать цвет отрисовку нужно по индексу из буфера цветов?

Я поправил функцию findInsideBar(). Теперь она выглядит вот так:

void findInsideBar(const double& high[], const double& low[], int index) {
//---
  if (high[index + 1] <= high[index + 2] && low[index + 1] >= low[index + 2]) {
    upperArrowBuffer[index] = low[index];
    upperArrowColor[index] = 0;
    lowerArrowBuffer[index] = high[index];
    lowerArrowColor[index] = 2;
  } else {
    upperArrowBuffer[index] = EMPTY_VALUE;
    lowerArrowBuffer[index] = EMPTY_VALUE;
  }
}

Цвет верхних стрелочек должен быть красный, как я понимаю, но я вижу совсем другое. В буфере цветов для нижних стрелок красного цвета нет, но они покрасились в красный..))


Или всё-таки цевт задаётся не по индексу в массиве?

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