Проблема с цветами индикатора DRAW_COLOR_LINE

 

Пытаюсь создать вменяемый индикатор Ренко, насколько он только может быть вменяемым на минутных барах.

Вроде более-менее похоже на правду, но с цветами запутался.

Может кто подскажет, почему цвет присваивается не по индексу буфера, а на опр. его участке?

Мой индикатор нижний.

Хочется так

iRenko[k] = iRenko[k + 1] > iRenko[k] ? Blue : Red
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots 1

#property indicator_type1 DRAW_COLOR_LINE
#property indicator_color1 clrBlue, clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2

input int InpBoxSize = 100;
input int InpDepth = 0;

double iRenkoValues[];
double iRenkoColors[];
double iRenko[];
int iMaxBars = 0;

int OnInit()
{
    SetIndexBuffer(0, iRenko, INDICATOR_DATA);
    SetIndexBuffer(1, iRenkoColors, INDICATOR_COLOR_INDEX);
    
    PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
    PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 2);
    PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, clrBlue); // PROBLEM MAY BE HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, clrRed);
    
    IndicatorSetInteger(INDICATOR_DIGITS, Digits());
    IndicatorSetString(INDICATOR_SHORTNAME, "Renko");

    iMaxBars = InpDepth ? InpDepth : TerminalInfoInteger(TERMINAL_MAXBARS);
    
    ArrayResize(iRenkoValues, iMaxBars);
    ArraySetAsSeries(iRenko, true);
    ArraySetAsSeries(iRenkoValues, true);
    ArrayFill(iRenkoValues, 0, iMaxBars, 0);
    ArrayInitialize(iRenkoValues, 0);

    return 0;
}

int OnCalculate(const int bars, const int counted, const int begin, const double &price[])
{
    string symbol = Symbol();
    
    MqlRates rates[];
    
    int stop = 0;
    int index = 0;
    int downloads = CopyRates(symbol, PERIOD_M1, 0, iMaxBars, rates);
    int direction = rates[downloads - 1].close > rates[downloads - 2].open ? 1 : -1;

    double residualUp = 0;
    double residualDown = 0;
    double size = InpBoxSize * Point();
    double point = direction > 0 ? rates[downloads - 1].high : rates[downloads - 1].low;

    for (int k = downloads - 2; k > 0; k--)
    {
        direction = rates[k].close > rates[k - 1].open ? 1 : -1;
        
        double distance = MathAbs(rates[k].high - rates[k].low);
        int intervals = (int) MathFloor(distance / Point() / InpBoxSize);
        
        for (int n = 0; n < intervals; n++)
        {
            if (index + n >= iMaxBars)
            {
                stop = 1;
                break;
            }

            iRenkoValues[index] = point;
            point -= direction * size;
            index += 1;
        }

        if (stop == 1 || index >= iMaxBars)
        {
            break;
        }

        double residual = intervals < 1 ? distance : MathMod(distance, InpBoxSize);

        if (direction > 0)
        {
            residualUp += residual;
        }
        
        if (direction < 0)
        {
            residualDown += residual;
        }

        if (MathAbs(residual) > size)
        {
            residualDown = residualDown ? residualDown - size : 0;
            residualUp = residualUp ? residualUp - size : 0;
            iRenkoValues[index] = point;
            point -= direction * size;
            index++;
        }
    }

    int pos = 0;
    int count = MathMin(ArraySize(iRenko), ArraySize(iRenkoValues));

    for (int k = 0; k < count - InpBoxSize - 1; k++)
    {
        iRenko[pos] = iRenkoValues[k];
        iRenkoColors[pos] = iRenkoValues[k + 1] > iRenkoValues[k] ? 0 : 1; // PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        pos++;
    }
    
    return bars;
}


 

Думаю этот пример "DRAW_COLOR_LINE Lite.mq5" поможет понять как работают цветные буферы:

//+------------------------------------------------------------------+
//|                                         DRAW_COLOR_LINE Lite.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#property description "An indicator to demonstrate DRAW_COLOR_LINE"
#property description "It draws a line on Close price in colored pieces of 20 bars each"
#property description "The width, style and color of the line parts are changed randomly"
#property description "every N ticks"

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1
//--- plot ColorLine
#property indicator_label1  "ColorLine"
#property indicator_type1   DRAW_COLOR_LINE
//--- Define 5 colors for coloring each bar (they are stored in the special array)
#property indicator_color1  clrBlue,clrRed // (Up to 64 colors can be specified)
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3
//--- A buffer for plotting
double         ColorLineBuffer[];
//--- A buffer for storing the line color on each bar
double         ColorLineColors[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Binding an array and an indicator buffer
   SetIndexBuffer(0,ColorLineBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ColorLineColors,INDICATOR_COLOR_INDEX);
//---
   ArraySetAsSeries(ColorLineBuffer,true);
   ArraySetAsSeries(ColorLineColors,true);
//---
   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[])
  {
   ArraySetAsSeries(close,true);
   if(prev_calculated==0)
     {
      for(int i=0;i<rates_total;i++)
         ColorLineBuffer[i]=close[i];
     }
//--- Block for calculating indicator values
   for(int i=0;i<10;i++)
     {
      //--- Write the indicator value into the buffer
      ColorLineBuffer[i]=close[i];
      //--- For this bar, the line will have the color with the index color_index
      if(ColorLineBuffer[i]>ColorLineBuffer[i+1])
         ColorLineColors[i]=0;
      else
         ColorLineColors[i]=1;
     }

//--- Return the prev_calculated value for the next call of the function
   return(rates_total);
  }
//+------------------------------------------------------------------+


Цикл 

   for(int i=0;i<10;i++)

взят просто так, просто захотелось мне на каждом тике перезаписывать последние 10 баров :)

Файлы:
 

Vladimir Karputov:

Доделал.
Спасибо за помощь.
В том скрипте не хватало
ArraySetAsSeries(iRenkoColors, true);
Все буфера были помечены как серии, а буфер цветов - обычный, поэтому красило фигню какую-то, ревертнутые индексы :)

Исправил. Сейчас вроде правильно работает и пошустрее, чем единственный подобный индикатор под МТ5.

https://www.mql5.com/en/code/1299

В этом индикаторе бывает такое, что рисуется 5 боксов по 100 пипс = 500 пипс, хотя цена прошла не больше 150.

Мой вроде правильней считает, тренды более плавные.
Тем не менее, было бы неплохо, если бы кто выложил в кодобазу или проверил корректность написаного.

Интерес вызвала эта тема 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Классический теханализ больше не работает. А что работает, может квантовый?

Sergey Pavlov, 2009.11.12 19:39

Если Вы говорите о том как построить цифровой фильтр или провести спектральный или квантовый анализ. То на мой взгляд, Вы ищете какое-то супер-сложное решение. Скорее всего что и найдёте (чуствуется у вас крепкая хватка). Но о том, что вы говорили, уменя самое смутное представление. Цифровой приёмник (дешифратор) или анализатор, как хотите называйте, у меня занимает 10 строк внутри советника. Ну как в таком коротком коде можно вместить всю высшую математику?

===

Можно я Вам подскажу? Выкиньте из головы цену и время, а оставьте только сигналы ТС и результаты сделок по этим сигналам. Вы же программисты. Выключите аналоговое, а включите своё цифровое мышление. Битовые операции наверняка знаете.

===

Может найдёте подсказку в прикреплённом файле. Примерно так я получаю конечный результат.


Файлы:
Renko.mq5  9 kb
 

Не совсем понятно, как можно получить вторую цветную линию в одном индикаторе. Для примера, пытаюсь продублировать ценовые серии High и Low.

Для начала беру одну цветную линию серии High. Тут все нормально.

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1

double bufHigh[];
double highColor[];

//------------------------------------------------------------------
void OnInit()
{
  SetIndexBuffer(0,bufHigh);
  PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetString(0, PLOT_LABEL, "High"); 
  
  SetIndexBuffer(1, highColor, INDICATOR_COLOR_INDEX);

  PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);
  PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrDeepSkyBlue);    //Нулевой индекс -> Синий
  PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrTomato);         //Первый индекс  -> Оранжевый
}

//------------------------------------------------------------------
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 = rates_total - prev_calculated;         // как правило, выдает 0-й или 1-й индекс свечи для расчета

  for(int i = limit-1; i >= 0; --i)
  {
    bufHigh[i] = high[i];
    highColor[i] = (i%2 == 0) ? 0 : 1;
  }


  return rates_total;
}


Файлы:
 

Но вот с добавлением второй линии по серии Low возникли проблемы с отрисовкой.

Добавил второй буфер bufLow[] и для него отдельный буфер для цвета. Ниже в коде таким образом прописал в секцию OnInit(). В «Окне данных» значения есть, а отрисовки не видно.
Помогите прояснить ситуацию.

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   4

double bufHigh[];
double highColor[];

double bufLow[];
double lowColor[];

//------------------------------------------------------------------
void OnInit()
{
  SetIndexBuffer(0,bufHigh);
  PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetString(0, PLOT_LABEL, "High"); 
  
  SetIndexBuffer(1, highColor, INDICATOR_COLOR_INDEX);

  PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);
  PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrDeepSkyBlue);    //Нулевой индекс -> Синий
  PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrTomato);         //Первый индекс  -> Оранжевый
  
  // ---- добавление Low линии
  SetIndexBuffer(2,bufLow);
  PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetString(2, PLOT_LABEL, "Low"); 
  
  SetIndexBuffer(3, lowColor, INDICATOR_COLOR_INDEX);

  PlotIndexSetInteger(2,PLOT_COLOR_INDEXES,2);
  PlotIndexSetInteger(2,PLOT_LINE_COLOR,0,clrBlue);
  PlotIndexSetInteger(2,PLOT_LINE_COLOR,1,clrGold);
}

//------------------------------------------------------------------
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 = rates_total - prev_calculated;    

  for(int i = limit-1; i >= 0; --i)
  {
    bufHigh[i] = high[i];
    highColor[i] = (i%2 == 0) ? 0 : 1;          // на четных индексах цвет из индекса 0, на нечетных - из индекса 1
    
    bufLow[i] = low[i];
    lowColor[i] = (i%2 == 0) ? 0 : 1;           // на четных индексах цвет из индекса 0, на нечетных - из индекса 1
  }


  return rates_total;
}


Файлы:
 

Создавайте заготовку через MQL Wizard - и не будет ошибок:

//+------------------------------------------------------------------+
//|                                                 HighLowColor.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   2
//--- plot High
#property indicator_label1  "High"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrDeepSkyBlue,clrTomato
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Low
#property indicator_label2  "Low"
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  clrBlue,clrGold
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- input parameters
input int      Input1=9;
//--- indicator buffers
double         HighBuffer[];
double         HighColors[];
double         LowBuffer[];
double         LowColors[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,HighBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighColors,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,LowColors,INDICATOR_COLOR_INDEX);
//---
   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[])
  {
//---
   int limit=prev_calculated-1;
   if(prev_calculated==0)
      limit=0;
   for(int i=limit; i<rates_total; i++)
     {
      int result=i%2;
      HighBuffer[i]=high[i];
      HighColors[i]=(result==0)?0:1;
      LowBuffer[i]=low[i];
      LowColors[i]=(result==0)?0:1;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Результат:


Файлы:
 
Vladimir Karputov #:

Создавайте заготовку через MQL Wizard - и не будет ошибок:


Результат:


Отлично. Спасибо за решение.
 
Vladimir Karputov #:

Создавайте заготовку через MQL Wizard - и не будет ошибок:

Мне на данный момент представленное Вами решение подходит, спасибо большое. Однако, я попробовал поочередно переносить некоторые из свойств property в функции PlotIndex... В справке все-таки написано, что можно и так и так задавать:

Получается для второй линии перестает работать вывод названия в окно данных PLOT_LABEL, и отрисовки PLOT_DRAW_TYPE, PLOT_COLOR_INDEXES не отображаются.

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

Возможно, это недоработка и нужны поправки от разработчиков.

 

Vasiliy Pushkaryov #:

Возможно, это недоработка и нужны поправки от разработчиков.

Нет, просто вы немного недоразобрались.

У индикаторов есть буферы (buffers) и графики (plots). В простых случаях нумерация для них совпадает, в вашем нет.

У вас 4 буфера и 2 графика, соответственно для второго графика для функций PlotIndexSet* индекс будет 1 а не 2, потому что индексация у них последовательная.

 
TheXpert #:

Нет, просто вы немного недоразобрались.

У индикаторов есть буферы (buffers) и графики (plots). В простых случаях нумерация для них совпадает, в вашем нет.

У вас 4 буфера и 2 графика, соответственно для второго графика для функций PlotIndexSet* индекс будет 1 а не 2, потому что индексация у них последовательная.

Вы очень помогли. Спасибо, теперь разобрался. Действительно, через функции PlotIndexSet* все настраивается и работает.