English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Цветные индикаторы - создание и применение

Цветные индикаторы - создание и применение

MetaTrader 5Индикаторы | 27 июля 2010, 12:52
11 188 10
Дмитрий Александрович
Дмитрий Александрович

Введение

Благодаря усилиям и стараниям разработчиков MetaTrader 5 появился язык MQL5. Всех нововведений не счесть, но я постараюсь описать и показать одну сторону данного языка, а именно возможность создания цветных индикаторов. В MQL4 цвет можно было задавать только для линии индикатора целиком на всем его протяжении. Сделать индикатор разными цветами можно было путем частичного перекрывания разными буферами одного индикатора, что было очень неудобно.

В MQL5 разработчики дали нам новую возможность, а именно - возможность задания цвета для каждого отдельного отрезка кривой индикатора (в случае с линиями) и цвета отдельных объектов (для баров, свечей, гистограмм, стрелок). Для понимания данной статьи желательно хотя бы просмотреть документацию по MQL5.

В этой статье я постараюсь рассмотреть следующие темы:

  • Основы работы с индикаторами
  • Задание буферов данных
  • Задание буферов индексов цветов
  • Как превратить не цветной стиль рисования в цветной на примере индикатора RSI (Стиль из DRAW_LINE в DRAW_COLOR_LINE)
  • Как раскрасить свечной график (Стиль рисования DRAW_COLOR_CANDLES) в зависимости от показаний RSI
  • Как получить значение буфера индексов цветов
Рассмотрим два типа цветных стилей рисования - DRAW_COLOR_LINE и DRAW_COLOR_CANDLES , остальные стили рисования отличаются только количеством буферов.

Зачем нужны цветные индикаторы?

С помощью цветных индикаторов возможно:

  • Отобразить дополнительную информацию на свечах.
  • Создавать гибриды индикаторов (Цвет MACD зависит от показаний RSI).
  • Выделить важные сигналы индикатора.
  • Ну и просто разукрасить свое рабочее место в терминале.

Можете дать волю своей фантазии, сделать торговлю более удобной.

Кратко повторим основы MQL5

Начнем с принципов индикатора.

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

Стиль задается индикатором и/или пользователем через свойства индикатора. Буферы это глобальные массивы типа double. Несколько буферов могут объединяться в графические построения в том случае, если задан стиль рисования который требует более одного буфера. Если вы ни разу не создавали пользовательские индикаторы, можете почитать статьи (В них хорошо изложены основы): "Как написать индикатор в MQL5" и "Пользовательские индикаторы в MQL5 для начинающих"

Приведу минимальный код цветного индикатора и опишу его составные части:

//+------------------------------------------------------------------+
//|                                         test_color_indicator.mq5 |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"                      //Автор
#property indicator_separate_window             //Индикатор в отдельном окне
#property indicator_buffers 2                   //Количество буферов индикатора
#property indicator_plots 1                     //Количество графических построений
#property indicator_type1 DRAW_COLOR_HISTOGRAM  //Стиль графических построения(рисования) - Гистограмма
#property indicator_width1 3                    //Ширина линии графического построения(необязательно, для наглядности)
#property indicator_color1 Red,Green,BlueViolet //Задание трех цветов для графического построения

//Объявление буферов
double buffer_line[]/*Буфер для данных*/, buffer_color_line[]/*Буфер для индекса цвета*/;

//+------------------------------------------------------------------+
//| Инициализация                                                    |
//+------------------------------------------------------------------+
int OnInit()
  {

//Сопоставляем массив-буфер данных с буфером индикатора
   SetIndexBuffer(0,buffer_line,INDICATOR_DATA);

//Сопоставляем массив-буфер индексов цветов с буфером индикатора
   SetIndexBuffer(1,buffer_color_line,INDICATOR_COLOR_INDEX);

//Задаем количество индексов цветов для графического построения
   PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);

//Задаем цвет для каждого индекса
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Blue);   //Нулевой индекс -> Синий
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Orange); //Первый индекс  -> Оранжевый
   return(0);
  }
//+------------------------------------------------------------------+
//| Вычисления на каждом тике                                        |
//+------------------------------------------------------------------+
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[])
  {
   //Заполняем буферы данных и индексов цвета для каждого бара в цикле
   for(int i=prev_calculated;i<=rates_total-1;i++)
     {
      //Добавляем простое условие раскрашивания -> Если цена открытия больше цены закрытия то:
      if(open[i]>close[i])
        {   buffer_color_line[i]=0;   }       //Присваиваем бару индекс цвета равный нулю (0)
      else
        {  buffer_color_line[i]=1;   }        //Присваиваем бару индекс цвета равный единице (1)
      
      //Задаем данные для отображения, а именно цену открытия текущего бара
      buffer_line[i]=open[i];
     }

   return(rates_total-1); //Возвращаем количество посчитанных баров, 
                          //вычитаем единицу для пересчета последнего бара
  }
//+------------------------------------------------------------------+

Разберем по порядку то, что относится к написанию цветных индикаторов:

#property indicator_buffers 2 //Количество буферов индикатора
#property indicator_plots 1   //Количество графических построений

В первой строчке мы задаем количество буферов индикатора, их у нас два:

  1. Для данных индикатора, в нашем случае для цен открытия
  2. Для индексов цвета.

Во второй строке мы указываем количество графических построений. Важно отличать графические построения от буферов индикатора. Графическое построение - Отображаемая линия(свеча, бар, стрелка и т.п.) индикатора. Буфер индикатора - Массив данных, которые необходимы для графического построения, цветов или для внутренних расчетах данных индикатора (Данный тип не отображается в окне индикатора.)

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

А вот начинается "самое интересное":

#property indicator_type1 DRAW_COLOR_HISTOGRAM  //Стиль графического построения(рисования) - Гистограмма
#property indicator_width1 3                    //Ширина линии графического построения(необязательно, для наглядности)
#property indicator_color1 Red,Green,BlueViolet //Задание трех цветов для графического построения

В первой строке задаем стиль рисования(графического построения), в данном случае графическое построение будет иметь вид "Гистограмма от нулевой линии". Для данного графического построения необходим один буфер данных и один буфер индексов цветов. Все стили рисования, содержащие в название слово "COLOR", нуждаются в буфере для индексов цветов.

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

В третьей строке мы задаем цвета для индексов графического построения, в данном случае мы задали три цвета - "Red - Красный(перевод с англ.)", "Green - Зеленый", "BlueViolet - Смесь синего и фиолетового". Индексация цветов начинается с нуля: 0-"Red", 1-"Green", 2-"BlueViolet". Эти цвета нужны для задания цветов графического построения. Указание цветов через "#property indicator_color1" является одним из двух способов. Этот способ задает цвета "статически", то есть, на стадии компиляции программы. Второй способ рассмотрим ниже.

double buffer_line[]/*Буфер для данных*/, buffer_color_line[]/*Буфер для индекса цвета*/;

Здесь объявляем два массива, которые будем использовать как буферы, один для данных индикатора, второй для индексов цветов оба имеют тип double.

Рассмотрим обработчик события инициализации индикатора:

SetIndexBuffer(0,buffer_line,INDICATOR_DATA);

Здесь сопоставляем буфер индикатора с массивом и задаем тип буфера "INDICATOR_DATA" - это означает, что в этом буфере будут храниться значения индикатора (данные по которым строится индикатор). Обратите внимание на то, что первый параметр равен нулю (0) - это индекс буфера.

SetIndexBuffer(1,buffer_color_line,INDICATOR_COLOR_INDEX);

Сопоставляем буфер индикатора с массивом и задаем тип буфера "INDICATOR_COLOR_INDEX" - это означает, что в этом буфере будут храниться индексы цветов каждого "бара индикатора". Обратите внимание на то, что первый параметр равен единице (1) - это индекс буфера.

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

Ну и наконец, второй способ задания цветов графического построения, точнее, сопоставления цвета индексу.

//Задаем количество индексов цветов для графического построения
   PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);

Здесь мы указываем количество индексов цветов. Первый параметр функции - "0" это индекс графического построения. Обратите внимание, в данном случае мы сами должны задавать количество индексов цветов(в первом способе количество рассчитывает компилятор).

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

Тут мы задаем цвета для каждого индекса. Первый параметр функции - индекс графического построения, третий параметр индекс цвета начиная с нуля. Второй способ задания индексов цветов отличается тем, что количества индексов и цветов можно задавать динамически, например через функцию. Если используется оба способа, то способ динамического задания индекса цвета перекрывает статический(первый) способ.

Далее рассмотрим функцию OnCalculate, в данной функции мы рассчитываем значения буферов для отображения индикатора. Условия выбора цвета для столбика гистограммы мы выбрали самое простое, если цена открытия больше цены закрытия, присваиваем текущему элементу буфера-массива "buffer_color_line" индекс цвета равный нулю (0). Индекс цвета ноль (0) соответствует цвету - "Синий", который мы задали ранее (способ выше.)

Если цена открытия меньше цены закрытия, присваиваем индекс цвета - "1" чему соответствует цвет - "Оранжевый". Вот как выглядит этот простой пример:

тестовый индикатор

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

Способы указания цвета


Теперь поподробнее о задании цвета.

Цвет в MQL5 согласно документации можно задать разными способами:

  • Литерально
  • Численно
  • При помощи названий цветов

Рассмотрим по порядку:

Литерально

color color_var = C'10,20,255';
color color_var = C'0x0A,0x14,0xFF';

Задаются цвета в соответствии с правилом RGB (в раскрытии и переводе: Red Green Blue, по-русски - Красный Зеленый Синий) любые цвета можно получить сложением этих трех цветов. Соответственно первое число это Красный цвет. Второе - Зеленый, третье - синий. Числа в десятеричной системе могут быть от 0 до 255. А в шестнадцатеричной от 00 до FF.

В первой  и во второй строчке, переменной color_var присваивается синий цвет цвет. Только в разных системах счисления, в первом случае в десятеричной, во втором в шестнадцатеричной. Разницы нет, какой способ использовать, какой удобней тот и выбирайте. Чем меньше число, тем темнее данный цвет, получается белый цвет - "C'255,255,255'" или "C'0xFF,0xFF,0xFF'", а черный "C'0,0,0'" или "C'0x00,0x00,0x00'".

Численно

color color_var = 0xFFFFFF;  // белый
color color_var = 0x0000FF;  // красный
color color_var = 16777215   // белый
color color_var = 0x008000   // зеленый
color color_var = 32768      // зеленый

Здесь цвета задаются числами в шестнадцатеричной или десятеричной системе счисления. Например, "0x0000FF" равно "C'0xFF,0x00,0x00'" - как видите, первая и последняя пара чисел поменялись местами. Чтобы получить число 16777215 в  десятеричной системе счисления надо перевести число FFFFFF из шестнадцатеричной в десятеричную.

Названия цветов

color color_var = Red;    //красный
color color_var = Blue;   //синий
color color_var = Orange; //оранжевый

Этот способ самый простой, но с помощью него нельзя задать любые цвета, только из набора web-цветов

И так, подведем итог, как задавать цвета

Все три способа эквивалентны между собой, вот пример:

color color1 = C'255,0,0';
color color2 = C'0xFF,0x00,0x00';
color color3 = 0x0000FF;
color color4 = 255;
color color5 = Red;

Alert((color1==color2)
       && (color1==color2)
       && (color1==color4)
       && (color1==color5)); //Выведет true


Практика

Повторили основы, теперь рассмотрим, как можно раскрасить свечи графика в зависимости от показаний другого индикатора, например, от RSI. Чтобы сделать свечи графика разноцветными нужно написать индикатор, который будет накладываться на график и поверх рисовать цветные свечи. Вот листинг индикатора, если показания RSI меньше 50%, то свечи синие, иначе - оранжевые.

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

//+------------------------------------------------------------------+
//|                                                   cand_color.mq5 |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"                      //Автор
#property indicator_chart_window                //Индикатор в отдельном окне

                                                //Задаем количество буферов индикатора 
//4 шт для построения свечей + 1 шт для цвета + 1 шт для внутреннего хранения данных RSI
#property indicator_buffers 6

//Зададим отображаемые имена в Data Window
#property indicator_label1 "Open;High;Low;Close"

#property indicator_plots 1                     //Количество графических построений
#property indicator_type1 DRAW_COLOR_CANDLES    //Стиль графических построения(рисования) - Цветные свечи
#property indicator_width1 3                    //Ширина линии графического построения(необязательно, для наглядности)

                                                //Объявление буферов
double buffer_open[],buffer_high[],buffer_low[],buffer_close[];//Буферы для данных
double buffer_color_line[];//Буфер для индекса цвета
double buffer_tmp[1];//Временный буфер для копирования RSI
double buffer_RSI[];//Индикаторный буфер для RSI
int handle_rsi=0;//Хендл для индикатора RSI
//+------------------------------------------------------------------+
//| Инициализация                                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
/**
        *       Порядок сопоставления буферов индикатора и массивов-буферов ОЧЕНЬ ВАЖЕН!
        *  Сначала идут буфер(ы) данных
        *       Затем буфер цвета
        *       И в конце буфер(ы) для внутренних расчетов.
        */
//Сопоставляем массив-буфер данных с буфером индикатора
   SetIndexBuffer(0,buffer_open,INDICATOR_DATA);
   SetIndexBuffer(1,buffer_high,INDICATOR_DATA);
   SetIndexBuffer(2,buffer_low,INDICATOR_DATA);
   SetIndexBuffer(3,buffer_close,INDICATOR_DATA);

//Сопоставляем массив-буфер индексов цветов с буфером индикатора
   SetIndexBuffer(4,buffer_color_line,INDICATOR_COLOR_INDEX);

//Сопоставляем массив буфер для данных индикатора RSI
   SetIndexBuffer(5,buffer_RSI,INDICATOR_CALCULATIONS);

//Задаем количество индексов цветов для графического построения
   PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);

//Задаем цвет для каждого индекса
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Blue);   //Нулевой индекс -> Синий
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Orange); //Первый индекс  -> Оранжевый
   

//Получаем хендл индикатора RSI, он необходим для получения его показаний
   handle_rsi=iCustom(_Symbol,_Period,"Examples\\RSI");
   return(0);
  }
//+------------------------------------------------------------------+
//| Вычисления на каждом тике                                        |
//+------------------------------------------------------------------+
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[])
  {
//Заполняем буферы данных и индексов цвета для каждого бара в цикле
   for(int i=prev_calculated;i<=rates_total-1;i++)
     {
      //Копируем данные из индикатора RSI во временный буфер - buffer_tmp
      CopyBuffer(handle_rsi,0,BarsCalculated(handle_rsi)-i-1,1,buffer_tmp);
      //Затем из временного буфера копируем в индикаторный буфер
      buffer_RSI[i]=buffer_tmp[0];

      //Задаем данные для отображения
      buffer_open[i]=open[i];  //Цена открытия
      buffer_high[i]=high[i];  //Максимальная цена
      buffer_low[i]=low[i];    //Минимальная цена
      buffer_close[i]=close[i];//Цена закрытия

                               //Добавляем простое условие -> Если RSI меньше 50%:
      if(buffer_RSI[i]<50)
        {   buffer_color_line[i]=0;   } //Присваиваем бару индекс цвета равный нулю (0)
      else
        {  buffer_color_line[i]=1;   }  //Присваиваем бару индекс цвета равный единице (1)
     }
   return(rates_total-1); //Возвращаем количество посчитанных баров, 
                          //вычитаем единицу для пересчета последнего бара
  }
//+------------------------------------------------------------------+

А вот как это выглядит:

Цветной индикатор зависит от RSI

Выглядит неплохо, но мы пойдем дальше. Раскрасим свечи в зависимости от уровня RSI сразу большим количеством цветов, так сказать - градиентом.

Можно вручную задавать цвета, но написать 30-40 цветов сложно и неудобно. Поступим по-другому, напишем две функции, первую для задания индексов цветов, а вторую для получения цвета в зависимости от передаваемых аргументов. В комментариях расписан весь принцип работы.

//+------------------------------------------------------------------+
//|                                               cand_color_RSI.mq5 |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"                      //Автор
#property indicator_chart_window                //Индикатор в отдельном окне

//Задаем количество буферов индикатора 
//4 шт для построения свечей + 1 шт для цвета + 1 шт для внутреннего хранения данных RSI
#property indicator_buffers 6

//Зададим отображаемые имена в Data Window
#property indicator_label1 "Open;High;Low;Close"

#property indicator_plots 1                     //Количество графических построений
#property indicator_type1 DRAW_COLOR_CANDLES    //Стиль графического построения(рисования) - Цветные свечи
#property indicator_width1 3                    //Ширина линии графического построения(необязательно, для наглядности)

                                                //Объявление буферов
double buffer_open[],buffer_high[],buffer_low[],buffer_close[];//Буферы для данных
double buffer_color_line[];//Буфер для индекса цвета
double buffer_tmp[1];//Временный буфер для копирования RSI
double buffer_RSI[];//Индикаторный буфер для RSI
int handle_rsi=0;//Хендл для индикатора RSI
//+------------------------------------------------------------------+
//|    Задаем цвета графическому построению                          |
//+------------------------------------------------------------------+
/*
*       Функция задающая цвета графическому построению 
*       50 цветов от зеленого до синего.
*       В функцию передается индекс графического построения.
*/
void setPlotColor(int plot)
  {
   PlotIndexSetInteger(plot,PLOT_COLOR_INDEXES,50); //Задаем количество цветов

                                                    //В циклах задаем цвета
   for(int i=0;i<=24;i++)
     {
      PlotIndexSetInteger(plot,PLOT_LINE_COLOR,i,StringToColor("\"0,175,"+IntegerToString(i*7)+"\""));
     }
   for(int i=0;i<=24;i++)
     {
      PlotIndexSetInteger(plot,PLOT_LINE_COLOR,i+25,StringToColor("\"0,"+IntegerToString(175-i*7)+",175\""));
     }
  }
//+------------------------------------------------------------------+
//|  Получаем индекс цвета                                           |
//+------------------------------------------------------------------+
/*
*       Функция возвращает индекс цвета
*       Первый параметр текущее показание индикатора
*       Второй параметр минимальное показание индикатора
*       Третий параметр максимальное показание индикатора
*/
int getPlotColor(double current,double min,double max)
  {
   return((int)NormalizeDouble((50/(max-min))*current,0));
  }
//+------------------------------------------------------------------+
//| Инициализация                                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
/**
        *       Порядок сопоставления буферов индикатора и массивов-буферов ОЧЕНЬ ВАЖЕН!
        *  Сначала идут буфер(ы) данных
        *       Затем буфер цвета
        *       И в конце буфер(ы) для внутренних расчетов.
        */
//Сопоставляем массив-буфер данных с буфером индикатора
   SetIndexBuffer(0,buffer_open,INDICATOR_DATA);
   SetIndexBuffer(1,buffer_high,INDICATOR_DATA);
   SetIndexBuffer(2,buffer_low,INDICATOR_DATA);
   SetIndexBuffer(3,buffer_close,INDICATOR_DATA);

//Сопоставляем массив-буфер индексов цветов с буфером индикатора
   SetIndexBuffer(4,buffer_color_line,INDICATOR_COLOR_INDEX);

//Сопоставляем массив-буфер для данных индикатора RSI с буфером индикатора
   SetIndexBuffer(5,buffer_RSI,INDICATOR_CALCULATIONS);

//Задаем индексы цветов
   setPlotColor(0);

//Получаем хендл индикатора RSI, он необходим для получения его показаний
   handle_rsi=iCustom(_Symbol,_Period,"Examples\\RSI",6);
   return(0);
  }
//+------------------------------------------------------------------+
//| Вычисления на каждом тике                                        |
//+------------------------------------------------------------------+
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[])
  {
//Заполняем буферы данных и индексов цвета для каждого бара в цикле
   for(int i=prev_calculated;i<=rates_total-1;i++)
     {
      //Копируем данные из индикатора RSI во временный буфер - buffer_tmp
      CopyBuffer(handle_rsi,0,BarsCalculated(handle_rsi)-i-1,1,buffer_tmp);
      //Затем из временного буфера копируем в индикаторный буфер
      buffer_RSI[i]=buffer_tmp[0];

      //Задаем данные для отображения
      buffer_open[i]=open[i];  //Цена открытия
      buffer_high[i]=high[i];  //Максимальная цена
      buffer_low[i]=low[i];    //Минимальная цена
      buffer_close[i]=close[i];//Цена закрытия

      //Раскрашиваем свечи в зависимости от показаний RSI
      //RSI = 0                 - цвет свечи зеленый
      //RSI = 100               - цвет свечи синий
      //        0<RSI<100   - цвет свечи между зеленым и синим 
      buffer_color_line[i]=getPlotColor(buffer_RSI[i],0,100);

     }
   return(rates_total-1); //Возвращаем количество посчитанных баров, 
                          //вычитаем единицу для пересчета последнего бара
  }
//+------------------------------------------------------------------+

Вот как выглядит:

RSI_gradient

Поэкспериментируйте с этим примером, подберите другие цвета. Попробуйте заменить RSI на другой индикатор. Практика всегда важна.

Раскрасим старые и проверенные

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

До обработки
После раскраски
DRAW_LINEDRAW_COLOR_LINE
DRAW_SECTIONDRAW_COLOR_SECTION
DRAW_HISTOGRAMDRAW_COLOR_HISTOGRAM
DRAW_HISTOGRAM2DRAW_COLOR_HISTOGRAM2
DRAW_ARROWDRAW_COLOR_ARROW
DRAW_ZIGZAGDRAW_COLOR_ZIGZAG (пример)
DRAW_CANDLESDRAW_COLOR_CANDLES

Ниже приведен код измененного RSI, у который раскрашен в зависимости от собственных показаний. Все изменения прокомментированы на русском.

//+------------------------------------------------------------------+
//|                                                          RSI.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "2009, MetaQuotes Software Corp."
#property link        "http://www.mql5.com"
#property description "Relative Strength Index"
//--- indicator settings
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_level1 30
#property indicator_level2 70
/////////////////////////////////////////////////////////////////////
#property indicator_buffers 4 //Увеличили число буферов на 1
#property indicator_width1 5  //Задали толщину линии в 4 пикселя для виду
/////////////////////////////////////////////////////////////////////
#property indicator_plots   1
/////////////////////////////////////////////////////////////////////
//Изменили тип графического построения с DRAW_LINE на DRAW_COLOR_LINE
#property indicator_type1   DRAW_COLOR_LINE
/////////////////////////////////////////////////////////////////////
#property indicator_color1  DodgerBlue
//--- input parameters
input int InpPeriodRSI=14; // Period
//--- indicator buffers
double    ExtRSIBuffer[];
double    ExtPosBuffer[];
double    ExtNegBuffer[];
//--- global variable
int       ExtPeriodRSI;

//////////////////////////////////////////////////////////////////////
double buffer_color[]; //Объявили массив для индексов цветов

//Добавили две функции
//+------------------------------------------------------------------+
//|    Задаем цвета графическому построению                          |
//+------------------------------------------------------------------+
/*
*       Функция задающая цвета графическому построению 
*       50 цветов от зеленого до синего.
*       В функцию передается индекс графического построения.
*/
void setPlotColor(int plot)
  {
   PlotIndexSetInteger(plot,PLOT_COLOR_INDEXES,50); //Задаем количество цветов

                                                    //В циклах задаем цвета
   for(int i=0;i<=24;i++)
     {
      PlotIndexSetInteger(plot,PLOT_LINE_COLOR,i,StringToColor("\"0,175,"+IntegerToString(i*7)+"\""));
     }
   for(int i=0;i<=24;i++)
     {
      PlotIndexSetInteger(plot,PLOT_LINE_COLOR,i+25,StringToColor("\"0,"+IntegerToString(175-i*7)+",175\""));
     }
  }
//+------------------------------------------------------------------+
//|  Получаем индекс цвета                                           |
//+------------------------------------------------------------------+
/*
*       Функция возвращает индекс цвета
*       Первый параметр текущее показание индикатора
*       Второй параметр минимальное показание индикатора
*       Третий параметр максимальное показание индикатора
*/
int getPlotColor(double current,double min,double max)
  {
   return((int)NormalizeDouble((50/(max-min))*current,0));
  }
//////////////////////////////////////////////////////////////////////


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input
   if(InpPeriodRSI<1)
     {
      ExtPeriodRSI=12;
      Print("Incorrect value for input variable InpPeriodRSI =",InpPeriodRSI,
            "Indicator will use value =",ExtPeriodRSI,"for calculations.");
     }
   else ExtPeriodRSI=InpPeriodRSI;
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtRSIBuffer,INDICATOR_DATA);
   
/////////////////////////////////////////////////////////////////////
//Ассоциируем масив-буфер индексов цветов
        SetIndexBuffer(1,buffer_color,INDICATOR_COLOR_INDEX);
//Изменили порядок буферов!
        SetIndexBuffer(2,ExtPosBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,ExtNegBuffer,INDICATOR_CALCULATIONS);
   //Задали цвета
   setPlotColor(0);
/////////////////////////////////////////////////////////////////////

//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,2);
//--- sets first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriodRSI);
//--- name for DataWindow and indicator subwindow label
   IndicatorSetString(INDICATOR_SHORTNAME,"RSI("+string(ExtPeriodRSI)+")");
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Relative Strength Index                                          |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
   int    i;
   double diff;
//--- check for rates count
   if(rates_total<=ExtPeriodRSI)
      return(0);
//--- preliminary calculations
   int pos=prev_calculated-1;
   if(pos<=ExtPeriodRSI)
     {
      //--- first RSIPeriod values of the indicator are not calculated
      ExtRSIBuffer[0]=0.0;
      ExtPosBuffer[0]=0.0;
      ExtNegBuffer[0]=0.0;
      double SumP=0.0;
      double SumN=0.0;
      for(i=1;i<=ExtPeriodRSI;i++)
        {
         ExtRSIBuffer[i]=0.0;
         ExtPosBuffer[i]=0.0;
         ExtNegBuffer[i]=0.0;
         diff=price[i]-price[i-1];
         SumP+=(diff>0?diff:0);
         SumN+=(diff<0?-diff:0);
        }
      //--- calculate first visible value
      ExtPosBuffer[ExtPeriodRSI]=SumP/ExtPeriodRSI;
      ExtNegBuffer[ExtPeriodRSI]=SumN/ExtPeriodRSI;
      ExtRSIBuffer[ExtPeriodRSI]=100.0-(100.0/(1.0+ExtPosBuffer[ExtPeriodRSI]/ExtNegBuffer[ExtPeriodRSI]));
      //--- prepare the position value for main calculation
      pos=ExtPeriodRSI+1;
     }
//--- the main loop of calculations
   for(i=pos;i<rates_total;i++)
     {
      diff=price[i]-price[i-1];
      ExtPosBuffer[i]=(ExtPosBuffer[i-1]*(ExtPeriodRSI-1)+(diff>0.0?diff:0.0))/ExtPeriodRSI;
      ExtNegBuffer[i]=(ExtNegBuffer[i-1]*(ExtPeriodRSI-1)+(diff<0.0?-diff:0.0))/ExtPeriodRSI;
      ExtRSIBuffer[i]=100.0-100.0/(1+ExtPosBuffer[i]/ExtNegBuffer[i]);
/////////////////////////////////////////////////////////////////////
//Раскрашиваем
                buffer_color[i] = getPlotColor(ExtRSIBuffer[i],0,100);
/////////////////////////////////////////////////////////////////////
     }
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }
//+------------------------------------------------------------------+

Вот что получилось, можете сравнить цвет свечей и цвет RSI.

RSI color

Получение цвета индикатора из эксперта/индикатора/скрипта

Необходиомть получить цвет линии может пригодиться для автоматической торговли в эксперте или для других целей. Реализовать это просто, покажу на примере скрипта.
//+------------------------------------------------------------------+
//|                                                         test.mq5 |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"
#property link      "http://"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
        int handle = 0; //хендл для индикатора
        double tmp[1];  //временный массив куда мы скопируем цветовой индекс.
        //Получаем хэндл нашего измененного RSI
        handle = iCustom(_Symbol,_Period,"Examples\\RSI",6);
        
        //Вспомним то, что показания хранятся в нашем измененном RSI, в буфере "1"
        //А индекс цвета в буфере "0"
        //Копируем из буфера "1" индикатора RSI, который мы раскрасили ранее индекс цвета.
        CopyBuffer(handle,1,0,1,tmp);
        
        //Выдаем алерт с последним индексом цвета, который вернул RSI
        Alert(tmp[0]); //Вывел например число "0" значит RSI 
        //раскрашен в зеленый цвет и имеет текущий уровень около нуля.
  }
//+------------------------------------------------------------------+
Обратите внимание на то, что мы можем узнать только индекс цвета, а не сам цвет!


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

Итог

Мы рассмотрели стили рисования - DRAW_COLOR_LINE, DRAW_COLOR_CANDLES. Раскрасили свечи, научились раскрашивать индикатор RSI (стиль рисования DRAW_LINE -> DRAW_COLOR_LINE). А так же научились получать значения буфера индексов цветов.

В MQL5  хорошие возможности раскрашивания индикаторов, все зависит от вашей фантазии, умения и опыта. Так же при использовании цветовой раскраски улучшается восприятие такой динамичной сущности как рынок. Используйте новые возможности для более комфортной торговли.

Буду рад вашим отзывам.

Прикрепленные файлы |
rsi.mq5 (6.57 KB)
cand_color.mq5 (4.61 KB)
cand_color_rsi.mq5 (5.72 KB)
test.mq5 (1.44 KB)

Другие статьи автора

Последние комментарии | Перейти к обсуждению на форуме трейдеров (10)
Ruslan Piraliyev
Ruslan Piraliyev | 16 дек. 2022 в 10:58
Alexey Viktorov #:

Индекс буфера не должен совпадать с индексом построения. У них своя индикация. Попробуйте  PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);

Подскажите плз еще такой момент, а можно как то менять порядок линий чтоб нужная была сверху? Или тут только порядком объявления буферов? К примеру хотелось чтоб 0-й буфер соответствовал самой главной линии, а канал заливки был в конце, но он всех перекрывает). Это удобно так как планируется использовать индикатор в советнике чтоб удобно было доставать данные.

Alexey Viktorov
Alexey Viktorov | 16 дек. 2022 в 11:15
Ruslan Piraliyev #:

Подскажите плз еще такой момент, а можно как то менять порядок линий чтоб нужная была сверху? Или тут только порядком объявления буферов? К примеру хотелось чтоб 0-й буфер соответствовал самой главной линии, а канал заливки был в конце, но он всех перекрывает). Это удобно так как планируется использовать индикатор в советнике чтоб удобно было доставать данные.

Ничего не понял. И какая разница какой номер буфера вытаскивать в советник?

Ruslan Piraliyev
Ruslan Piraliyev | 16 дек. 2022 в 11:19
Alexey Viktorov #:

Ничего не понял. И какая разница какой номер буфера вытаскивать в советник?

Это просто когда знаешь что нужен нулевой буфер и все тут), а так надо заглянуть в индюк и посмотреть какая по счету нужная. А так да никакой).

Alexey Viktorov
Alexey Viktorov | 16 дек. 2022 в 11:40
Ruslan Piraliyev #:

Это просто когда знаешь что нужен нулевой буфер и все тут), а так надо заглянуть в индюк и посмотреть какая по счету нужная. А так да никакой).

Когда вы пишете советник, вам по любому надо уточнять какой буфер надо копировать и как на какие значения реагировать.

Ruslan Piraliyev
Ruslan Piraliyev | 16 дек. 2022 в 15:28
Alexey Viktorov #:

Когда вы пишете советник, вам по любому надо уточнять какой буфер надо копировать и как на какие значения реагировать.

Да, все так. Еще раз спасибо что подсказали, а то за деревьями и леса не увидел)

Ограничения и проверки в экспертах Ограничения и проверки в экспертах
Можно ли торговать этим инструментом в понедельник? Хватит ли денег на открытие позиции? Какой размер убытка мы получим, если сработает Stop Loss? Как ограничить количество отложенных ордеров? Была ли выполнена торговая операция на этом баре или это было на предыдущем? Если торговый робот не может сделать подобные проверки, то любая прибыльная торговая система может превратиться в проигрышную. В этой статье показаны примеры проверок, которые пригодятся в любом эксперте.
Интервью с Николаем Косициным: мультивалютные эксперты менее рискованны (ATC 2010) Интервью с Николаем Косициным: мультивалютные эксперты менее рискованны (ATC 2010)
Мы побеседовали с Николаем Косициным о его разработках. Он считает мультивалютники перспективным направлением и занимается разработкой именно таких экспертов. На чемпионатах Николай также выступает только с мультивалютниками. Именно его советник стал единственным мультивалютником, который вышел в победители Чемпионата за все время проведения соревнования.
Исследование паттернов (моделей) японских свечей Исследование паттернов (моделей) японских свечей
Построение графиков японских свечей и анализ свечных моделей — удивительное направление технического анализа. Преимущество японских свечей в том, что они представляют данные таким образом, что появляется возможность увидеть динамику внутри данных. В данной статье мы рассмотрим типы свечей, классификацию свечных моделей и напишем индикатор, распознающий свечные паттерны.
Взаимодействие MetaTrader 5 и MATLAB Взаимодействие MetaTrader 5 и MATLAB
Статья раскрывает детали реализации связки MetaTrader 5 и математического пакета MatLab. Детально раскрывается механизм преобразования данных, процесс разработки универсальной библиотеки для взаимодействия с рабочим столом MatLab, также рассматривается вопрос использования DLL библиотек, сгенерированных средой MatLab. Данная статья рассчитана на подготовленных читателей, знающих C++ и MQL5.