Цветные буферы в мультисимвольных мультипериодных индикаторах
Содержание
- Введение
- Основные принципы
- Доработка классов
- Тестирование
- Accumulation/Distribution
- Accelerator Oscillator
- Alligator
- Average Directional Movement Index
- Average Directional Movement Index Wilder
- Average True Range
- Awesome Oscillator
- Bears Power
- Bollinger Bands
- Bulls Power
- Chaikin Oscillator
- Commodity Channel Index
- DeMarker
- Envelopes
- Force Index
- MACD
- MA of Oscillator
- Market Facilitation Index
- Momentum
- Money Flow Index
- Moving Averages
- On Balance Volume
- Parabolic SAR
- Relative Strength Index
- Relative Vigor Index
- Standard Deviation
- Stochastic Odcillator
- Triple Exponential Average
- Volumes
- Williams Percent Range
- Заключение
Введение
Продолжаем разработку мультисимвольных мультипериодных индикаторов, начатую в прошлой статье.
Одноцветный индикаторный буфер является обычным double-массивом, который заполняется данными при просчёте индикатора. Данные из этого массива мы можем получить и отобразить на графике при помощи функции CopyBuffer() при условии, что приёмным массивом будет служить double-массив, назначенный как рисуемый индикаторный буфер (SetIndexBuffer()). При копировании данных из буфера расчётной части индикатора в буфер рисуемой части индикатора, данные отображаются на графике одним цветом, установленным для массива-буфера рисуемой части индикатора. С цветными же буферами дело обстоит немного иначе. У цветного буфера помимо массива данных есть ещё один массив — массив индексов цвета.
Одной рисуемой цветной линии индикатора мы можем задать не более 64 различных цветов для её отображения. Задать цвета для рисуемой линии можно директивой компилятора indicator_colorN, например
#property indicator_color1 clrGreen,clrRed
либо функцией PlotIndexSetInteger(), например
PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2); PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrGreen); PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrRed);
В обоих случаях здесь для первой рисуемой линии индикатора устанавливаются два цвета отрисовки — зелёный и красный. Индекс зелёного цвета равен 0, а индекс красного равен 1. Вот именно эти индексы цвета и хранятся в специальном массиве индексов цвета в цветном буфере индикатора. Для каждого бара таймсерии, рассчитанной индикатором, может задаваться свой цвет отрисовки — просто для каждого бара устанавливается свой индекс цвета. В данном случае — либо 0, либо 1. И линия индикатора рисуется цветом, назначенным по этому индексу.
Кажется, что в примерах выше первый способ выглядит лаконичнее. Это так, но для того, чтобы была возможность динамичного изменения цвета для линии индикатора, нужно использовать второй способ: назначить количество цветов, а затем динамически их менять на любые другие в зависимости от ситуации, отображаемой индикатором.
Для каждого цветного буфера обязательно назначен массив индексов цвета, и массив индексов цвета обязательно имеет индекс на 1 больший, чем индекс рисуемого массива. Для стилей рисования, требующих более одного массива, индекс массива цвета всегда на 1 больше, чем индекс последнего массива, назначенного для рисования линии.
Основные принципы
Исходя из вышеизложенного, понимаем, что
- Рисуемый индикаторный буфер может использовать для отрисовки один и более массивов в зависимости от стиля рисования.
- Для любого цветного массива используется ещё один дополнительный массив — массив индексов цвета рисуемого буфера, индекс которого на 1 больше индекса последнего массива, назначенного для рисуемого буфера.
Для большего понимания создадим новый индикатор, в котором укажем несколько рисуемых буферов, как простых, так и цветных и использующих несколько массивов для своего построения:
В итоге получим такой шаблон индикатора:
//+------------------------------------------------------------------+ //| Test.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 17 // Всего 17 массивов для расчёта индикатора #property indicator_plots 6 // Из 17-ти массивов 6 графических серий - рисуемых буферов //--- plot Label1 #property indicator_label1 "Label1" #property indicator_type1 DRAW_LINE // Рисуемый буфер с индексом 0, простая линия, требует один массив для построения #property indicator_color1 clrRed // Цвет линии: Red #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Label2 #property indicator_label2 "Label2" #property indicator_type2 DRAW_FILLING // Рисуемый буфер с индексом 1, цветная область, рисуемая между двумя индикаторными линиями, требует два массива для построения #property indicator_color2 clrRed,clrDeepSkyBlue // Цвет области: либо Red, либо DeepSkyBlue, в зависимости от того, какая линия из двух выше #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot Label3 #property indicator_label3 "Label3" #property indicator_type3 DRAW_CANDLES // Рисуемый буфер с индексом 2, отображение в виде одноцветных свечей, требует четыре массива данных OHLC для построения #property indicator_color3 clrDarkSalmon // Цвет: DarkSalmon #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot Label4 #property indicator_label4 "Label4" #property indicator_type4 DRAW_COLOR_LINE // Рисуемый буфер с индексом 3, цветная линия, требует два массива для построения: массив данных + массив индексов цвета #property indicator_color4 clrRed,clrRoyalBlue // Два цвета: Red и RoyalBlue. Может быть до 64-х цветов #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot Label5 #property indicator_label5 "Label5" #property indicator_type5 DRAW_COLOR_HISTOGRAM2 // Рисуемый буфер с индексом 4, цветная гистограмма между двумя линиями, требует три массива для построения - два массива данных + массив индексов цвета #property indicator_color5 clrRed,clrForestGreen,clrBurlyWood // Три цвета: Red, ForestGreen и BurlyWood. Может быть до 64-х цветов #property indicator_style5 STYLE_SOLID #property indicator_width5 1 //--- plot Label6 #property indicator_label6 "Label6" // Рисуемый буфер с индексом 5, отображение в виде цветных свечей, требует пять массивов для построения: 4 массива данных OHLC + массив индексов цвета #property indicator_type6 DRAW_COLOR_CANDLES // Три цвета: Red, Blue и Gray. Может быть до 64-х цветов #property indicator_color6 clrRed,clrBlue,clrGray #property indicator_style6 STYLE_SOLID #property indicator_width6 1 //--- input variables input uchar InpHidePlotIndex = 0; // Hide Plot Index //--- indicator buffers double Label1Buffer[]; // Рисуемый буфер с индексом 0 double Label2Buffer1[]; // Рисуемый буфер с индексом 1, массив 1 double Label2Buffer2[]; // Рисуемый буфер с индексом 1, массив 2 double Label3Buffer1[]; // Рисуемый буфер с индексом 2, массив 1 double Label3Buffer2[]; // Рисуемый буфер с индексом 2, массив 2 double Label3Buffer3[]; // Рисуемый буфер с индексом 2, массив 3 double Label3Buffer4[]; // Рисуемый буфер с индексом 2, массив 4 double Label4Buffer[]; // Рисуемый буфер с индексом 3 double Label4Colors[]; // Массив индексов цветов рисуемого буфера с индексом 3 double Label5Buffer1[]; // Рисуемый буфер с индексом 4, массив 1 double Label5Buffer2[]; // Рисуемый буфер с индексом 4, массив 2 double Label5Colors[]; // Массив индексов цветов рисуемого буфера с индексом 4 double Label6Buffer1[]; // Рисуемый буфер с индексом 5, массив 1 double Label6Buffer2[]; // Рисуемый буфер с индексом 5, массив 2 double Label6Buffer3[]; // Рисуемый буфер с индексом 5, массив 3 double Label6Buffer4[]; // Рисуемый буфер с индексом 5, массив 4 double Label6Colors[]; // Массив индексов цветов рисуемого буфера с индексом 5 //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- Рисуемый буфер 0. Один массив для построения SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA); // Буфер данных //--- Рисуемый буфер 1. Два массива для построения SetIndexBuffer(1,Label2Buffer1,INDICATOR_DATA); // Буфер данных линии 1 SetIndexBuffer(2,Label2Buffer2,INDICATOR_DATA); // Буфер данных линии 2 //--- Рисуемый буфер 2. Четыре массива для построения SetIndexBuffer(3,Label3Buffer1,INDICATOR_DATA); // Буфер данных линии 1 Open SetIndexBuffer(4,Label3Buffer2,INDICATOR_DATA); // Буфер данных линии 2 High SetIndexBuffer(5,Label3Buffer3,INDICATOR_DATA); // Буфер данных линии 3 Low SetIndexBuffer(6,Label3Buffer4,INDICATOR_DATA); // Буфер данных линии 4 Close //--- Рисуемый буфер 3. Два массива для построения SetIndexBuffer(7,Label4Buffer,INDICATOR_DATA); // Буфер данных SetIndexBuffer(8,Label4Colors,INDICATOR_COLOR_INDEX); // Буфер индексов цвета //--- Рисуемый буфер 4. Три массива для построения SetIndexBuffer(9,Label5Buffer1,INDICATOR_DATA); // Буфер данных линии 1 SetIndexBuffer(10,Label5Buffer2,INDICATOR_DATA); // Буфер данных линии 2 SetIndexBuffer(11,Label5Colors,INDICATOR_COLOR_INDEX);// Буфер индексов цвета //--- Рисуемый буфер 5. Пять массивов для построения SetIndexBuffer(12,Label6Buffer1,INDICATOR_DATA); // Буфер данных линии 1 Open SetIndexBuffer(13,Label6Buffer2,INDICATOR_DATA); // Буфер данных линии 2 High SetIndexBuffer(14,Label6Buffer3,INDICATOR_DATA); // Буфер данных линии 3 Low SetIndexBuffer(15,Label6Buffer4,INDICATOR_DATA); // Буфер данных линии 4 Close SetIndexBuffer(16,Label6Colors,INDICATOR_COLOR_INDEX);// Буфер индексов цвета } //+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Здесь уже прописаны комментарии для понимания какие массивы какой графической серии назначаются. Если при создании индикатора не менять предлагаемые по умолчанию наименования графических серий, то мастер создаёт вполне логичные и понятные имена буферам индикатора, где "LabelX" — это наименование рисуемого буфера с номером X, а "Buffer" — это номер массива (одного, или нескольких) для построения графической серии.
Например,
- Label5Buffer1 — это первый массив пятого рисуемого буфера (его индекс на самом деле равен 4, так как отсчёт начинается с нуля) для построения цветной гистограммы, рисуемой между двумя линиями,
- Label5Buffer2 — это второй массив пятого рисуемого буфера для построения цветной гистограммы, рисуемой между двумя линиями,
- Label5Colors — это массив индексов цвета пятого рисуемого буфера для построения цветной гистограммы, рисуемой между двумя линиями.
Для рассмотренного выше примера индекс графической серии (рисуемого буфера) равен 4, хотя для него назначены массивы с индексами 9, 10 и 11. Т.е., чтобы назначить этой графической серии какое-либо свойство, нужно устанавливать его не по индексам массивов, назначенных для построения графической серии, а по индексу рисуемого буфера, а их у нас в этом примере шесть — от 0 до 5.
Для наглядного просмотра назначения свойств графическим сериям можно добавить входную переменную, где будем указывать индекс рисуемого буфера, который не нужно отображать в окне данных и устанавливать заданному рисуемому буферу значение false:
//+------------------------------------------------------------------+ //| Test.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 17 // Всего 17 массивов для расчёта индикатора #property indicator_plots 6 // Из 17-ти массивов 6 графических серий - рисуемых буферов //--- plot Label1 #property indicator_label1 "Label1" #property indicator_type1 DRAW_LINE // Рисуемый буфер с индексом 0, простая линия, требует один массив для построения #property indicator_color1 clrRed // Цвет линии: Red #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Label2 #property indicator_label2 "Label2" #property indicator_type2 DRAW_FILLING // Рисуемый буфер с индексом 1, цветная область, рисуемая между двумя индикаторными линиями, требует два массива для построения #property indicator_color2 clrRed,clrDeepSkyBlue // Цвет области: либо Red, либо DeepSkyBlue, в зависимости от того, какая линия из двух выше #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot Label3 #property indicator_label3 "Label3" #property indicator_type3 DRAW_CANDLES // Рисуемый буфер с индексом 2, отображение в виде одноцветных свечей, требует четыре массива данных OHLC для построения #property indicator_color3 clrDarkSalmon // Цвет: DarkSalmon #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot Label4 #property indicator_label4 "Label4" #property indicator_type4 DRAW_COLOR_LINE // Рисуемый буфер с индексом 3, цветная линия, требует два массива для построения: массив данных + массив индексов цвета #property indicator_color4 clrRed,clrRoyalBlue // Два цвета: Red и RoyalBlue. Может быть до 64-х цветов #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot Label5 #property indicator_label5 "Label5" #property indicator_type5 DRAW_COLOR_HISTOGRAM2 // Рисуемый буфер с индексом 4, цветная гистограмма между двумя линиями, требует три массива для построения - два массива данных + массив индексов цвета #property indicator_color5 clrRed,clrForestGreen,clrBurlyWood // Три цвета: Red, ForestGreen и BurlyWood. Может быть до 64-х цветов #property indicator_style5 STYLE_SOLID #property indicator_width5 1 //--- plot Label6 #property indicator_label6 "Label6" // Рисуемый буфер с индексом 5, отображение в виде цветных свечей, требует пять массивов для построения: 4 массива данных OHLC + массив индексов цвета #property indicator_type6 DRAW_COLOR_CANDLES // Три цвета: Red, Blue и Gray. Может быть до 64-х цветов #property indicator_color6 clrRed,clrBlue,clrGray #property indicator_style6 STYLE_SOLID #property indicator_width6 1 //--- input variables input uchar InpHidePlotIndex = 0; // Hide Plot Index //--- indicator buffers double Label1Buffer[]; // Рисуемый буфер с индексом 0 double Label2Buffer1[]; // Рисуемый буфер с индексом 1, массив 1 double Label2Buffer2[]; // Рисуемый буфер с индексом 1, массив 2 double Label3Buffer1[]; // Рисуемый буфер с индексом 2, массив 1 double Label3Buffer2[]; // Рисуемый буфер с индексом 2, массив 2 double Label3Buffer3[]; // Рисуемый буфер с индексом 2, массив 3 double Label3Buffer4[]; // Рисуемый буфер с индексом 2, массив 4 double Label4Buffer[]; // Рисуемый буфер с индексом 3 double Label4Colors[]; // Массив индексов цветов рисуемого буфера с индексом 3 double Label5Buffer1[]; // Рисуемый буфер с индексом 4, массив 1 double Label5Buffer2[]; // Рисуемый буфер с индексом 4, массив 2 double Label5Colors[]; // Массив индексов цветов рисуемого буфера с индексом 4 double Label6Buffer1[]; // Рисуемый буфер с индексом 5, массив 1 double Label6Buffer2[]; // Рисуемый буфер с индексом 5, массив 2 double Label6Buffer3[]; // Рисуемый буфер с индексом 5, массив 3 double Label6Buffer4[]; // Рисуемый буфер с индексом 5, массив 4 double Label6Colors[]; // Массив индексов цветов рисуемого буфера с индексом 5 //--- global variables int hide_index=(InpHidePlotIndex>5 ? 5 : InpHidePlotIndex); //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- Рисуемый буфер 0. Один массив для построения SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA); // Буфер данных //--- Рисуемый буфер 1. Два массива для построения SetIndexBuffer(1,Label2Buffer1,INDICATOR_DATA); // Буфер данных линии 1 SetIndexBuffer(2,Label2Buffer2,INDICATOR_DATA); // Буфер данных линии 2 //--- Рисуемый буфер 2. Четыре массива для построения SetIndexBuffer(3,Label3Buffer1,INDICATOR_DATA); // Буфер данных линии 1 Open SetIndexBuffer(4,Label3Buffer2,INDICATOR_DATA); // Буфер данных линии 2 High SetIndexBuffer(5,Label3Buffer3,INDICATOR_DATA); // Буфер данных линии 3 Low SetIndexBuffer(6,Label3Buffer4,INDICATOR_DATA); // Буфер данных линии 4 Close //--- Рисуемый буфер 3. Два массива для построения SetIndexBuffer(7,Label4Buffer,INDICATOR_DATA); // Буфер данных SetIndexBuffer(8,Label4Colors,INDICATOR_COLOR_INDEX); // Буфер индексов цвета //--- Рисуемый буфер 4. Три массива для построения SetIndexBuffer(9,Label5Buffer1,INDICATOR_DATA); // Буфер данных линии 1 SetIndexBuffer(10,Label5Buffer2,INDICATOR_DATA); // Буфер данных линии 2 SetIndexBuffer(11,Label5Colors,INDICATOR_COLOR_INDEX);// Буфер индексов цвета //--- Рисуемый буфер 5. Пять массивов для построения SetIndexBuffer(12,Label6Buffer1,INDICATOR_DATA); // Буфер данных линии 1 Open SetIndexBuffer(13,Label6Buffer2,INDICATOR_DATA); // Буфер данных линии 2 High SetIndexBuffer(14,Label6Buffer3,INDICATOR_DATA); // Буфер данных линии 3 Low SetIndexBuffer(15,Label6Buffer4,INDICATOR_DATA); // Буфер данных линии 4 Close SetIndexBuffer(16,Label6Colors,INDICATOR_COLOR_INDEX);// Буфер индексов цвета //--- Скроем в окне данных указанный рисуемый буфер PlotIndexSetInteger(0,PLOT_SHOW_DATA,true); PlotIndexSetInteger(1,PLOT_SHOW_DATA,true); PlotIndexSetInteger(2,PLOT_SHOW_DATA,true); PlotIndexSetInteger(3,PLOT_SHOW_DATA,true); PlotIndexSetInteger(4,PLOT_SHOW_DATA,true); PlotIndexSetInteger(5,PLOT_SHOW_DATA,true); PlotIndexSetInteger(hide_index,PLOT_SHOW_DATA,false); 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); } //+------------------------------------------------------------------+
Если задать в настройках буфер 0, которому соответствует графическая серия с именем Label1, то в окне данных этот буфер отображён не будет:
Видно, что список данных начинается с буфера с именем Label2.
Если ввести 5 в настройках индикатора, то будет скрыт из окна данных рисуемый буфер с именем Label6:
Соответственно, сколько бы массивов не было назначено в индикаторе для построения графических серий, нужно учитывать факты:
- для изменения свойств именно графических серий, нужно обращаться по индексу нужного рисуемого буфера, а не по индексу массивов, назначенных для построения этих серий,
- для построения буферов с различными стилями рисования требуется от одного до пяти массивов, назначаемых как индикаторные буферы,
- все массивы, принадлежащие одному рисуемому буферу должны идти в строгой последовательности друг за другом. Нельзя их перемешивать с другими массивами, назначенными для построения других графических серий,
- массив индексов цвета в списке массивов, назначенных одному рисуемому буферу, идёт самым последним.
Исходя из всего вышесказанного, понимаем, что структуру буферов мультисимвольных мультипериодных индикаторов необходимо доработать. Теперь в структуре будут объявлены пять массивов: четыре массива для хранения данных буфера и пятый — для хранения индексов цвета. Различные стили рисования индикаторных линий подразумевают использование от одного до пяти double-массивов. Вот все эти массивы и будут объявлены в структуре буфера, а использоваться будут только нужные для конкретного индикатора. Соответственно, при обращении к данным буфера нужно будет вместе с индексом этого буфера указывать и номер (индекс) требуемого массива. Это не очень удобно — постоянно указывать индекс нужного буфера и индекс требуемого массива, так как большинство индикаторных построений в стандартных индикаторах выполнено на одномассивном буфере, и придётся вторым индексом всегда указывать ноль. Но в последующем, после создания и обкатки всех индикаторов в виде их мульти- версий, добавим в классы каждого индикатора методы получения нужных данных с нужного буфера и массива. Это будет позже. А пока займёмся структурой буферов индикаторов.
Доработка классов
Чтобы не отслеживать сколько массивов требует рисуемый индикаторный буфер для своего построения, организуем получение данных от графической серии таким образом, чтобы обращаться только по индексу рисуемого буфера и по индексу нужного массива. Т.е. если буфер 0 рисуется на двух массивах данных и одном массиве индексов цветов, то для запроса данных от первого массива, нужно будет просто указать индекс рисуемого буфера и индекс нужного массива, например 0 и 0. Если нужны данные от второго массива, то указывать будем 0 и 1. Для запроса данных от буфера цвета сделаем соответствующие методы — указывать будем только индекс рисуемого буфера (0).
Таким образом нам не нужно будет помнить индексы массивов, назначенных индикаторным буферам — в классе они будут запомнены и возвращать данные по индексу графической серии и требуемого массива. Так, наверное, будет немного проще для получения данных — запрашивать их только по индексам рисуемых буферов. Чуть позже сделаем для каждого класса каждого стандартного индикатора методы, возвращающие данные от нужного массива — это будет ещё более облегчать задачу получения данных от буферов мульти- индикаторов и построения на графике их линий.
Все изменения будем вносить в файл библиотеки \MQL5\Include\IndMSTF\IndMSTF.mqh.
В файле библиотеки структура индикаторного буфера будет переработана. Некоторые функции перенесём в приватную секцию, так как доступ к ним извне не нужен. Если ранее мы инициализировали и изменяли размер только одного массива, то теперь их будет пять. Поэтому функции инициализации и изменения размера теперь обрабатывают все пять массивов. Выбор нужного количества массивов осуществляется по стилю рисования, установленному для буфера, так как именно стиль и определяет требуемое количество массивов для построения графической серии. Стиль рисования устанавливается в структуру буфера при создании индикатора. Так же в структуре буфера будем прописывать индекс исходного массива индикатора — чтобы по этому индексу точно знать с какого буфера исходного индикатора идёт копирование данных.
//--- struct struct SBuffer // Структура индикаторного буфера { private: double init_value; // Инициализирующее значение uchar init_color_idx; // Инициализирующее значение индекса цвета int shift; // Сдвиг буфера по горизонтали uint source; // Номер буфера исходного индикатора bool colored; // Флаг цветного буфера ENUM_DRAW_TYPE draw_type; // Стиль рисования буфера //--- Изменяет размер всех массивов bool ResizeArrays(const int new_size) { bool res=true; switch(draw_type) { //--- Один буфер case DRAW_LINE : case DRAW_HISTOGRAM : case DRAW_ARROW : case DRAW_SECTION : return ArrayResize(array0,new_size)==new_size; //--- Два буфера case DRAW_HISTOGRAM2 : case DRAW_ZIGZAG : case DRAW_FILLING : res =(ArrayResize(array0,new_size)==new_size); res &=(ArrayResize(array1,new_size)==new_size); return res; //--- Четыре буфера case DRAW_BARS : case DRAW_CANDLES : res =(ArrayResize(array0,new_size)==new_size); res &=(ArrayResize(array1,new_size)==new_size); res &=(ArrayResize(array2,new_size)==new_size); res &=(ArrayResize(array3,new_size)==new_size); return res; //--- Один буфер + буфер цвета case DRAW_COLOR_LINE : case DRAW_COLOR_HISTOGRAM : case DRAW_COLOR_ARROW : case DRAW_COLOR_SECTION : res =(ArrayResize(array0,new_size)==new_size); res &=(ArrayResize(color_indexes,new_size)==new_size); return res; //--- Два буфера + буфер цвета case DRAW_COLOR_HISTOGRAM2 : case DRAW_COLOR_ZIGZAG : res =(ArrayResize(array0,new_size)==new_size); res &=(ArrayResize(array1,new_size)==new_size); res &=(ArrayResize(color_indexes,new_size)==new_size); return res; //--- Четыре буфера + буфер цвета case DRAW_COLOR_BARS : case DRAW_COLOR_CANDLES : res =(ArrayResize(array0,new_size)==new_size); res &=(ArrayResize(array1,new_size)==new_size); res &=(ArrayResize(array2,new_size)==new_size); res &=(ArrayResize(array3,new_size)==new_size); res &=(ArrayResize(color_indexes,new_size)==new_size); return res; //---DRAW_NONE default: break; } return false; } //--- Инициализирует все массивы int InitArrays(void) { bool res=0; switch(draw_type) { //--- Один буфер case DRAW_LINE : case DRAW_HISTOGRAM : case DRAW_ARROW : case DRAW_SECTION : return ArrayInitialize(array0,init_value); //--- Два буфера case DRAW_HISTOGRAM2 : case DRAW_ZIGZAG : case DRAW_FILLING : res+=ArrayInitialize(array0,init_value); res+=ArrayInitialize(array1,init_value); return res/2; //--- Четыре буфера case DRAW_BARS : case DRAW_CANDLES : res+=ArrayInitialize(array0,init_value); res+=ArrayInitialize(array1,init_value); res+=ArrayInitialize(array2,init_value); res+=ArrayInitialize(array3,init_value); return res/4; //--- Один буфер + буфер цвета case DRAW_COLOR_LINE : case DRAW_COLOR_HISTOGRAM : case DRAW_COLOR_ARROW : case DRAW_COLOR_SECTION : res+=ArrayInitialize(array0,init_value); res+=ArrayInitialize(color_indexes,init_color_idx); return res/2; //--- Два буфера + буфер цвета case DRAW_COLOR_HISTOGRAM2 : case DRAW_COLOR_ZIGZAG : res+=ArrayInitialize(array0,init_value); res+=ArrayInitialize(array1,init_value); res+=ArrayInitialize(color_indexes,init_color_idx); return res/3; //--- Четыре буфера + буфер цвета case DRAW_COLOR_BARS : case DRAW_COLOR_CANDLES : res+=ArrayInitialize(array0,init_value); res+=ArrayInitialize(array1,init_value); res+=ArrayInitialize(array2,init_value); res+=ArrayInitialize(array3,init_value); res+=ArrayInitialize(color_indexes,init_color_idx); return res/5; //---DRAW_NONE default: break; } return false; } public: double array0[]; // Массив-буфер0 индикатора double array1[]; // Массив-буфер1 индикатора (2-й массив для расчёта) double array2[]; // Массив-буфер2 индикатора (3-й массив для расчёта) double array3[]; // Массив-буфер3 индикатора (4-й массив для расчёта) double color_indexes[]; // Массив-буфер индексов цветов индикатора color clrs[]; // Массив цветов, назначенных буферу string descript; // Описание буфера //--- Возвращает флаг цветного буфера bool IsColoredBuffer(void) { return colored; } //--- (1) Устанавливает, (2) возвращает стиль рисования буфера, (3) номер соответствующего буфера исходного индикатора void SetBufferDrawType(const ENUM_DRAW_TYPE type,const uint buff_source) { draw_type=type; source=buff_source; switch(draw_type) { case DRAW_COLOR_LINE : case DRAW_COLOR_SECTION : case DRAW_COLOR_HISTOGRAM : case DRAW_COLOR_HISTOGRAM2 : case DRAW_COLOR_ARROW : case DRAW_COLOR_ZIGZAG : case DRAW_COLOR_BARS : case DRAW_COLOR_CANDLES : colored=true; break; default : colored=false; break; } } ENUM_DRAW_TYPE DrawType(void) { return draw_type; } uint BufferFrom(void) { return source; } //--- (1) Устанавливает, (2) возвращает инициализирующее значение void SetInitValue(const double value) { init_value=value; } double InitValue(void) { return init_value; } //--- (1) Устанавливает, (2) возвращает инициализирующее значение индекса цвета void SetInitColorIdx(const uchar idx) { init_color_idx=idx; } uchar InitColorIdx(void) { return init_color_idx; } //--- (1) Устанавливает, (2) возвращает сдвиг буфера void SetShift(const int value) { shift=value; } int Shift(void) { return shift; } //--- (1) Возвращает размер массива буфера, (2) изменяет размер массива буфера, //--- (3) инициализирует массив установленным "пустым" значением uint BufferSize(void) { return array0.Size(); } bool BuffResize(const int new_size) { return ResizeArrays(new_size); } int InitBuffer(void) { return InitArrays(); } //--- (1) Возвращает размер массива буфера индексов цвета, uint BufferColorIdxSize(void) { return color_indexes.Size(); } //--- (1) Устанавливает, (2) возвращает значение цвета по индексу void SetColorToIdx(const uchar idx,const color clr) { if(idx>(int)clrs.Size()-1) { ResetLastError(); if(ArrayResize(clrs,idx+1)!=idx+1) { PrintFormat("%s: ArrayResize 'clrs' failed. Error %lu",__FUNCTION__,GetLastError()); return; } } clrs[idx]=clr; } color ColorByIdx(const uchar idx){ return(idx<clrs.Size() ? clrs[idx] : clrNONE); } };
Ранее копирование массивов осуществлялось в методе расчёта индикатора Calculate(). Теперь же, так как копировать нужно будет более одного массива, созданы новые методы, возвращающие результат копирования всех используемых для расчёта массивов. В классе мульти- индикатора объявим новые методы и добавим в методы получения данных индекс требуемого массива.
//+------------------------------------------------------------------+ //| Базовый класс мультисимвольного мультипериодного индикатора | //+------------------------------------------------------------------+ class CIndMSTF : public CObject { private: ENUM_PROGRAM_TYPE m_program; // Тип программы ENUM_INDICATOR m_type; // Тип индикатора ENUM_TIMEFRAMES m_timeframe; // Период графика string m_symbol; // Символ графика int m_handle; // Хэндл индикатора int m_id; // Идентификатор bool m_success; // Флаг успешного расчёта ENUM_ERR_TYPE m_type_err; // Тип ошибки при расчёте string m_description; // Пользовательское описание индикатора string m_name; // Наименование индикатора string m_parameters; // Описание параметров индикатора protected: ENUM_IND_CATEGORY m_category; // Категория индикатора MqlParam m_param[]; // Массив параметров индикатора string m_title; // Заголовок (наименование индикатора + описание параметров) SBuffer m_buffers[]; // Буферы индикатора int m_digits; // Digits значений индикатора int m_limit; // Количество баров, необходимое для просчёта индикатора на текущем тике int m_rates_total; // Количество доступных баров для просчёта индикатора int m_prev_calculated; // Количество просчитанных баров на прошлом вызове индикатора //--- (1) Устанавливает наименование индикатора, (2) описание параметров void SetName(const string name) { this.m_name=name; } void SetParameters(const string str) { this.m_parameters=str; } //--- Изменяет размер (1) указанного, (2) всех буферов индикатора bool BufferResize(const uint buffer_num,const int new_buff_size); bool BuffersResize(const int new_buff_size); //--- Инициализирует (1) укакзанный, (2) все буферы индикатора bool BufferInitialize(const uint buffer_num,const int new_buff_size); bool BuffersInitialize(const int new_buff_size); //--- Возвращает флаг равенства структуры одного параметра двух объектов bool IsEqualParameters(const MqlParam &this_param,const MqlParam &compared_param) const { if(this_param.type==compared_param.type && this_param.integer_value==compared_param.integer_value && this_param.string_value==compared_param.string_value && ::NormalizeDouble(this_param.double_value-compared_param.double_value,8)==0 ) return true; return false; } //--- Возвращает результат сравнения одного параметра двух объектов int CompareParams(const MqlParam &this_param,const MqlParam &compared_param) { if(this.IsEqualParameters(this_param,compared_param)) return 0; else if(this_param.type>compared_param.type || this_param.integer_value>compared_param.integer_value || this_param.string_value>compared_param.string_value || this_param.double_value>compared_param.double_value ) return 1; else if(this_param.type<compared_param.type || this_param.integer_value<compared_param.integer_value || this_param.string_value<compared_param.string_value || this_param.double_value<compared_param.double_value ) return -1; else return -1; } //--- Копирует данные указанного массива указанного буфера bool CopyArray(const uint buff_num,const uint array_num,const int to_copy,double &array[]); //--- Копирует данные всех массивов указанного буфера bool CopyArrays(const uint buff_num,const int to_copy); public: //--- Создаёт расчётную часть индикатора, возвращает хэндл int CreateIndicator(void); //--- (1) Рассчитывает индикатор, заполняет переданный (2) рисуемый массив-буфер, (3) массив-буфер индексов цвета (с учётом символа-периода графика) данными из буфера расчётной части индикатора данного класса bool Calculate(void); bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &buffer[]); bool DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]); //--- (1) Устанавливает (2) возвращает инициализирующее значение для указанного буфера void SetBufferInitValue(const uint buffer_num,const double value); double BufferInitValue(const uint buffer_num) const; //--- (1) Устанавливает (2) возвращает инициализирующее значение индекса цвета для указанного буфера void SetBufferInitColorIndex(const uint buffer_num,const uchar index); uchar BufferInitColorIndex(const uint buffer_num) const; //--- (1) Устанавливает, (2) возвращает значение цвета по индексу для указанного буфера void SetBufferColorToIndex(const uint buffer_num,const uchar color_idx,const color clr); color BufferColorByIndex(const uint buffer_num,const uchar color_idx); //--- Возвращает флаг цветного буфера bool IsColoredBuffer(const uint buffer_num) const; //--- (1) Устанавливает (2) возвращает значение сдвига для указанного буфера void SetBufferShift(const uint buffer_num,const int value); double BufferShift(const uint buffer_num) const; //--- (1) Устанавливает, (2) возвращает стиль рисования указанного буфера, (3) номер соответствующего буфера исходного индикатора void SetBufferDrawType(const uint buffer_num,const ENUM_DRAW_TYPE type,const uint buff_source); ENUM_DRAW_TYPE BufferDrawType(const uint buffer_num); uint BufferFrom(const uint buffer_num); //--- Возвращает данные указанного буфера и массива (1) как есть, (2) относительно указанного символа/таймфрейма, //--- данные указанного буфера цвета (3) как есть, (4) относительно указанного символа/таймфрейма, //--- (5) количество данных в указанном буфере, (7) количество цветов, установленных буферу, (7) состояние линии индикатора как есть в буфере расчётной части, //--- (8) состояние линии индикатора с учётом символа/периода графика, описание состояния линии (9) как есть в буфере (10) с учётом символа/периода графика double GetData(const uint buffer_num,const uint array_num,const int index) const; double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int index) const; double GetColorData(const uint buffer_num,const int index) const; double GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const; uint DataTotal(const uint buffer_num,const uint array_num) const; uint ColorsTotal(const uint buffer_num) const; ENUM_LINE_STATE BufferLineState(const uint buffer_num,const uint array_num,const int index) const; ENUM_LINE_STATE BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const uint array_num,const int index) const; ENUM_LINE_STATE BufferLineStateRelative(const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE); //--- Возвращает (1) флаг успешности, (2) тип ошибки расчёта bool IsSuccess(void) const { return this.m_success; } ENUM_ERR_TYPE TypeError(void) const { return this.m_type_err; } //--- Устанавливает (1) идентификатор, (2) Digits, (3) пользовательское описание, (4) описание указанного буфера void SetID(const int id) { this.m_id=id; } void SetDigits(const uint digits) { this.m_digits=(int)digits; } void SetDescription(const string descr) { this.m_description=descr; } void SetBufferDescription(const uint buffer_num,const string descr); //--- Устанавливает индексацию массивов буферов расчётной части не как в таймсерии void SetAsSeriesOff(void); //--- Возвращает флаг серийности указанного буфера, (2) синхронизированности исторических данных по символу/периоду bool IsSeries(const uint buffer_num,const uint array_num) const; bool IsSynchronized(void) const { return (bool)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_SYNCHRONIZED); } //--- Возвращает (1) таймфрейм, (2) символ, (3) наименование, (4) список параметров, (5) хэндл, (6) Digits //--- количество (7) буферов, (8) баров, (9) идентификатор, (10) описание, (11) заголовок, (12) категорию, //--- (13) количество параметрпов, (14) тип программы, описание (15) категории, (16) буфера индикатора ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; } string Symbol(void) const { return this.m_symbol; } string Name(void) const { return this.m_name; } string Parameters(void) const { return this.m_parameters; } int Handle(void) const { return this.m_handle; } int Digits(void) const { return this.m_digits; } uint BuffersTotal(void) const { return this.m_buffers.Size(); } uint RatesTotal(void) const { return this.m_rates_total; } int ID(void) const { return this.m_id; } string Description(void) const { return this.m_description; } string Title(void) const { return this.m_title; } ENUM_IND_CATEGORY Category(void) const { return this.m_category; } uint ParamsTotal(void) const { return this.m_param.Size(); } ENUM_PROGRAM_TYPE Program(void) const { return this.m_program; } string CategoryDescription(void); string BufferDescription(const uint buffer_num); //--- Возвращает (1) структуру параметров по индексу из массива, (2) флаг программы-индикатора, (3) описание таймфрейма MqlParam GetMqlParam(const int index) const { return this.m_param[index]; } bool IsIndicator() const { return(this.Program()==PROGRAM_INDICATOR); } string TimeframeDescription(void) const { return ::StringSubstr(::EnumToString(this.m_timeframe),7); } //--- Возвращает количество рассчитанных данных int Calculated(void) const { return ::BarsCalculated(this.m_handle); } //--- Виртуальный метод, возвращающий тип объекта (индикатора) virtual int Type(void) const { return this.m_type; } //--- Виртуальный метод сравнения двух объектов virtual int Compare(const CObject *node,const int mode=0) const { const CIndMSTF *compared=node; switch(mode) { case COMPARE_MODE_ID : return(this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : 0); case COMPARE_MODE_HANDLE : return(this.Handle()>compared.Handle() ? 1 : this.Handle()<compared.Handle() ? -1 : 0); case COMPARE_MODE_CATEGORY : return(this.Category()>compared.Category() ? 1 : this.Category()<compared.Category() ? -1 : 0); case COMPARE_MODE_SYMBOL : return(this.Symbol()>compared.Symbol() ? 1 : this.Symbol()<compared.Symbol() ? -1 : 0); case COMPARE_MODE_TIMEFRAME : return(this.Timeframe()>compared.Timeframe() ? 1 : this.Timeframe()<compared.Timeframe() ? -1 : 0); case COMPARE_MODE_DESCRIPTION : return(this.Description()>compared.Description() ? 1 : this.Description()<compared.Description() ? -1 : 0); //---Равенство всех параметров объектов default : return(this.IsEqualIndicators(compared) ? 0 : -1); } } //--- Возвращает флаг равенства параметров двух объектов-индикаторов bool IsEqualIndicators(const CIndMSTF *compared) const { if(this.Type()!=compared.Type() || this.ParamsTotal()!=compared.ParamsTotal()) return false; bool res=true; int total=(int)this.ParamsTotal(); for(int i=0;i<total;i++) res &=this.IsEqualParameters(this.m_param[i],compared.GetMqlParam(i)); res &=(this.Timeframe()==compared.Timeframe()); res &=(this.Symbol()==compared.Symbol()); return res; } //--- Таймер void OnTimer(void); //--- Конструктор/деструктор CIndMSTF(){} CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe); ~CIndMSTF(); };
В деструкторе класса освобождаем память всех массивов буферов индикатора:
//+------------------------------------------------------------------+ //| Деструктор | //+------------------------------------------------------------------+ CIndMSTF::~CIndMSTF() { //--- Удаляем таймер ::EventKillTimer(); //--- Освобождаем хэндл индикатора ::ResetLastError(); if(this.m_handle!=INVALID_HANDLE && !::IndicatorRelease(this.m_handle)) ::PrintFormat("%s: %s, handle %ld IndicatorRelease failed. Error %ld",__FUNCTION__,this.Title(),m_handle,::GetLastError()); //--- Освобождаем память массивов буферов for(int i=0;i<(int)this.BuffersTotal();i++) { ::ArrayFree(this.m_buffers[i].array0); ::ArrayFree(this.m_buffers[i].array1); ::ArrayFree(this.m_buffers[i].array2); ::ArrayFree(this.m_buffers[i].array3); ::ArrayFree(this.m_buffers[i].color_indexes); } }
Реализация новых объявленных методов:
//+------------------------------------------------------------------+ //| Устанавливает инициализирующее значение индекса цвета | //| для указанного буфера | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferInitColorIndex(const uint buffer_num,const uchar index) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Устанавливаем новое инициализирующее значение индекса цвета для указанного буфера this.m_buffers[buffer_num].SetInitColorIdx(index); } //+------------------------------------------------------------------+ //| Возвращает инициализирующее значение индекса цвета | //| для указанного буфера | //+------------------------------------------------------------------+ uchar CIndMSTF::BufferInitColorIndex(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем инициализирующее значение индекса цвета самого первого, иначе - 0 return uchar(this.BuffersTotal()>0 ? this.m_buffers[0].InitColorIdx() : 0); } //--- Возвращаем инициализирующее значение индекса цвета запрошенного буфера return this.m_buffers[buffer_num].InitColorIdx(); } //+------------------------------------------------------------------+ //| Устанавливает значение цвета по индексу для указанного буфера | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferColorToIndex(const uint buffer_num,const uchar color_idx,const color clr) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Устанавливаем новое значение цвета по индексу для указанного буфера this.m_buffers[buffer_num].SetColorToIdx(color_idx,clr); } //+------------------------------------------------------------------+ //| Возвращает значение цвета по индексу для указанного буфера | //+------------------------------------------------------------------+ color CIndMSTF::BufferColorByIndex(const uint buffer_num,const uchar color_idx) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем инициализирующее значение индекса цвета самого первого, иначе - 0 return clrNONE; } //--- Возвращаем значение цвета по индексу для запрошенного буфера return this.m_buffers[buffer_num].ColorByIdx(color_idx); } //+------------------------------------------------------------------+ //| Возвращает флаг цветного буфера | //+------------------------------------------------------------------+ bool CIndMSTF::IsColoredBuffer(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Возвращаем false return false; } //--- Возвращаем флаг цветности для указанного буфера return this.m_buffers[buffer_num].IsColoredBuffer(); }
//+------------------------------------------------------------------+ //| Устанавливает стиль рисования указанного буфера | //+------------------------------------------------------------------+ void CIndMSTF::SetBufferDrawType(const uint buffer_num,const ENUM_DRAW_TYPE type,const uint buff_source) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и уходим if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return; } //--- Устанавливаем стиль рисования для буфера this.m_buffers[buffer_num].SetBufferDrawType(type,buff_source); } //+------------------------------------------------------------------+ //| Возвращает стиль рисования указанного буфера | //+------------------------------------------------------------------+ ENUM_DRAW_TYPE CIndMSTF::BufferDrawType(const uint buffer_num) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем значение сдвига самого первого, иначе - 0 return(this.BuffersTotal()>0 ? this.m_buffers[0].DrawType() : DRAW_NONE); } //--- Возвращаем стиль рисования запрошенного буфера return this.m_buffers[buffer_num].DrawType(); } //+------------------------------------------------------------------+ //| Возвращает номер соответствующего буфера исходного индикатора | //+------------------------------------------------------------------+ uint CIndMSTF::BufferFrom(const uint buffer_num) { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем значение сдвига самого первого, иначе - 0 return(this.BuffersTotal()>0 ? this.m_buffers[0].Shift() : 0); } //--- Возвращаем номер соответствующего буфера исходного индикатора для запрошенного буфера return this.m_buffers[buffer_num].BufferFrom(); } //+------------------------------------------------------------------+ //| Копирует данные указанного массива указанного буфера | //+------------------------------------------------------------------+ bool CIndMSTF::CopyArray(const uint buff_num,const uint array_num,const int to_copy,double &array[]) { ::ResetLastError(); //--- Копируем либо два последних бара в массив array, либо все имеющиеся исторические данные из массива расчётной части индикатора в массив-буфер объекта индикатора int copied=0; if(to_copy==2) { switch(array_num) { case 0 : case 1 : case 2 : case 3 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(), -this.m_buffers[buff_num].Shift(),to_copy,array); break; case 4 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom()+1,-this.m_buffers[buff_num].Shift(),to_copy,array); break; default : break; } } else { switch(array_num) { case 0 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(), -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array0); break; case 1 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(), -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array1); break; case 2 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(), -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array2); break; case 3 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(), -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array3); break; case 4 : copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom()+1,-this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].color_indexes); break; default : break; } } //--- Если копирование успешно if(copied>0) return true; //--- Если скопированы не все данные //--- Если CopyBuffer вернула -1, то это означает начало загрузки исторических данных //--- выведем сообщение об этом в журнал if(copied==WRONG_VALUE) ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- В любом ином случае - ещё не все данные удалось скопировать //--- выведем сообщение об этом в журнал else ::PrintFormat("%s::%s: Not all data was copied. Data available: %lu, total copied: %ld",__FUNCTION__,this.Title(),this.m_rates_total,copied); return false; } //+------------------------------------------------------------------+ //| Копирует данные всех массивов указанного буфера | //+------------------------------------------------------------------+ bool CIndMSTF::CopyArrays(const uint buff_num,const int to_copy) { bool res=true; double array[2]; if(to_copy==2) { switch(this.BufferDrawType(buff_num)) { //--- Один буфер case DRAW_LINE : case DRAW_HISTOGRAM : case DRAW_ARROW : case DRAW_SECTION : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } return res; //--- Два буфера case DRAW_HISTOGRAM2 : case DRAW_ZIGZAG : case DRAW_FILLING : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } res &=this.CopyArray(buff_num,1,to_copy,array); if(res) { this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1]; this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0]; } return res; //--- Четыре буфера case DRAW_BARS : case DRAW_CANDLES : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } res &=this.CopyArray(buff_num,1,to_copy,array); if(res) { this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1]; this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0]; } res &=this.CopyArray(buff_num,2,to_copy,array); if(res) { this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-1]=array[1]; this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-2]=array[0]; } res &=this.CopyArray(buff_num,3,to_copy,array); if(res) { this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-1]=array[1]; this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-2]=array[0]; } return res; //--- Один буфер + буфер цвета case DRAW_COLOR_LINE : case DRAW_COLOR_HISTOGRAM : case DRAW_COLOR_ARROW : case DRAW_COLOR_SECTION : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } res &=this.CopyArray(buff_num,4,to_copy,array); if(res) { this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1]; this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0]; } return res; //--- Два буфера + буфер цвета case DRAW_COLOR_HISTOGRAM2 : case DRAW_COLOR_ZIGZAG : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } res &=this.CopyArray(buff_num,1,to_copy,array); if(res) { this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1]; this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0]; } res &=this.CopyArray(buff_num,4,to_copy,array); if(res) { this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1]; this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0]; } return res; //--- Четыре буфера + буфер цвета case DRAW_COLOR_BARS : case DRAW_COLOR_CANDLES : res=this.CopyArray(buff_num,0,to_copy,array); if(res) { this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1]; this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0]; } res &=this.CopyArray(buff_num,1,to_copy,array); if(res) { this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1]; this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0]; } res &=this.CopyArray(buff_num,2,to_copy,array); if(res) { this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-1]=array[1]; this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-2]=array[0]; } res &=this.CopyArray(buff_num,3,to_copy,array); if(res) { this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-1]=array[1]; this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-2]=array[0]; } res &=this.CopyArray(buff_num,4,to_copy,array); if(res) { this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1]; this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0]; } return res; //---DRAW_NONE default: break; } } else { switch(this.BufferDrawType(buff_num)) { //--- Один буфер case DRAW_LINE : case DRAW_HISTOGRAM : case DRAW_ARROW : case DRAW_SECTION : return this.CopyArray(buff_num,0,to_copy,array); //--- Два буфера case DRAW_HISTOGRAM2 : case DRAW_ZIGZAG : case DRAW_FILLING : res =this.CopyArray(buff_num,0,to_copy,array); res &=this.CopyArray(buff_num,1,to_copy,array); return res; //--- Четыре буфера case DRAW_BARS : case DRAW_CANDLES : res =this.CopyArray(buff_num,0,to_copy,array); res &=this.CopyArray(buff_num,1,to_copy,array); res &=this.CopyArray(buff_num,2,to_copy,array); res &=this.CopyArray(buff_num,3,to_copy,array); return res; //--- Один буфер + буфер цвета case DRAW_COLOR_LINE : case DRAW_COLOR_HISTOGRAM : case DRAW_COLOR_ARROW : case DRAW_COLOR_SECTION : res =this.CopyArray(buff_num,0,to_copy,array); res &=this.CopyArray(buff_num,4,to_copy,array); return res; //--- Два буфера + буфер цвета case DRAW_COLOR_HISTOGRAM2 : case DRAW_COLOR_ZIGZAG : res =this.CopyArray(buff_num,0,to_copy,array); res &=this.CopyArray(buff_num,1,to_copy,array); res &=this.CopyArray(buff_num,4,to_copy,array); return res; //--- Четыре буфера + буфер цвета case DRAW_COLOR_BARS : case DRAW_COLOR_CANDLES : res =this.CopyArray(buff_num,0,to_copy,array); res &=this.CopyArray(buff_num,1,to_copy,array); res &=this.CopyArray(buff_num,2,to_copy,array); res &=this.CopyArray(buff_num,3,to_copy,array); res &=this.CopyArray(buff_num,4,to_copy,array); return res; //---DRAW_NONE default: break; } } return false; }
Теперь в методе расчёта индикатора вместо копирования массивов вызывается метод, осуществляющий копирование всех массивов буферов индикатора, а ошибка возвращается после попытки копирования всех массивов:
//+------------------------------------------------------------------+ //| Заполняет буферы объекта данными из буфера расчётной части | //+------------------------------------------------------------------+ bool CIndMSTF::Calculate(void) { //--- Устанавливаем флагу успешности значение true, а типу ошибки - её отсутствие this.m_success=true; this.m_type_err=ERR_TYPE_NO_ERROR; //--- Если данные ещё не синхронизированы с торговым сервером, if(!this.IsSynchronized()) { //--- Выводим в журнал сообщение о несинхронизированности, ::PrintFormat("%s::%s: Waiting for data to sync...",__FUNCTION__,this.Title()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_SYNC; this.m_success=false; return false; } //--- Если метод Calculated вернул -1, это означает начало закачки данных if(this.Calculated()==WRONG_VALUE) { //--- Выводим в журнал сообщение о начале закачки данных, ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_DATA; this.m_success=false; return false; } //--- Если метод Calculated вернул 0, это означает, что индикатор ещё не рассчитан if(this.Calculated()==0) { //--- Выводим в журнал сообщение об ожидании расчёта индикатора, ::PrintFormat("%s::%s: Waiting for a new tick and when the indicator will be calculated...",__FUNCTION__,this.Title()); //--- устанавливаем тип ошибки, к флагу ошибки добавляем false и возвращаем false this.m_type_err=ERR_TYPE_NO_CALC; this.m_success=false; return false; } //--- Получаем количество баров данных по символу/периоду индикатора int bars=::Bars(this.m_symbol,this.m_timeframe); //--- Если функция Bars вернула нулевое значение, что часто бывает на выходных, рассчитаем доступное количество баров if(bars==0) { //--- Получим дату самого первого доступного бара в истории по символу/периоду datetime firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE); //--- Получим дату последнего (текущего) бара в истории по символу/периоду datetime lastdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE); //--- Рассчитаем количество баров между первой и последней датами истории int sec=::PeriodSeconds(this.m_timeframe); ulong date_bars=(((ulong)lastdate-(ulong)firstdate)/(sec>0 ? sec : 1))+1; //--- В переменную bars запишем меньшее значение из рассчитанного количества баров и максимального количества баров, доступных в терминале bars=(int)fmin(date_bars,::TerminalInfoInteger(TERMINAL_MAXBARS)); } //--- Запишем в m_rates_total полученное количество доступных баров if(this.m_rates_total!=bars) this.m_rates_total=bars; //--- Если количество доступных баров получено, и их два и меньше, if(this.m_rates_total>=0 && this.m_rates_total<3) { //--- Выведем в журнал сообщение о слишком маленьком количестве доступных баров ::PrintFormat("%s::%s: Not enough data for calculation: %ld bars. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_rates_total); //--- установим тип ошибки, к флагу ошибки добавим false и вернём false this.m_type_err=ERR_TYPE_NO_DATA; this.m_success=false; return false; } //--- Рассчитаем количество необходимых баров для расчёта индикатора //--- Либо вся доступная история, либо 1 при открытии нового бара, либо 0 на текущем тике this.m_limit=this.m_rates_total-this.m_prev_calculated; this.m_prev_calculated=this.Calculated(); //--- Объявляем массив размером 2 для получения в него данных из буфера расчётной части индикатора //--- Получать будем всегда по два бара - прошлый и текущий double array[2]; //--- Получаем количество буферов индикатора int total=(int)this.BuffersTotal(); //--- Если рассчитанное значение m_limit больше 1 - значит это либо первый запуск, либо изменения в исторических данных //--- В этом случае необходим полный перерасчёт индикатора if(this.m_limit>1) { //--- В цикле по количеству буферов индикатора for(int i=0;i<total;i++) { //--- изменяем размер массива буфера индикатора и инициализируем его установленным для этого буфера "пустым" значением this.BufferInitialize(i,this.m_rates_total); //--- Определяем количество копируемых данных int to_copy=(this.m_prev_calculated>this.m_rates_total ? this.m_rates_total : this.m_prev_calculated); //--- Если не все массивы успешно скопированы - запишем в m_success значение false if(!this.CopyArrays(i,to_copy)) this.m_success &=false; } //--- Если после цикла есть ошибки - возвращаем false if(!this.m_success) { this.m_type_err=ERR_TYPE_NO_DATA; return false; } //--- Всё успешно - вернём true this.m_type_err=ERR_TYPE_NO_ERROR; this.m_success=true; return true; } //--- Если рассчитанное значение m_limit меньше, либо равно 1 - значит это либо открытие нового бара (m_limit==1), либо текущий тик (m_limit==0) //--- В этом случае необходимо рассчитать два бара - первый и текущий if(this.m_limit<=1) { //--- В цикле по количеству буферов индикатора for(int i=0;i<total;i++) { //--- Если это открытие нового бара и не удалось изменить размер буфера индикатора, if(this.m_limit==1 && !this.BufferResize(i,this.m_rates_total)) { //--- добавим к переменной m_success значение false и вернём false //--- При этом сообщение об ошибке будет выведено в журнал из метода BufferResize this.m_success=false; return false; } //--- Если не удалось скопировать два бара из буфера расчётной части индикатора, ::ResetLastError(); if(!this.CopyArrays(i,2)) { //--- сообщим об этом в журнал, добавим к переменной m_success значение false и вернём false ::PrintFormat("%s::%s: CopyBuffer(%lu) failed. Error %lu",__FUNCTION__,this.Title(),i,::GetLastError()); this.m_success &=false; } } //--- Если после цикла есть ошибки - возвращаем false if(!this.m_success) { this.m_type_err=ERR_TYPE_NO_DATA; return false; } //--- Успешно this.m_type_err=ERR_TYPE_NO_ERROR; this.m_success=true; return true; } //--- Неопределённый вариант limit - возвращаем false return false; }
Для копирования данных цветного буфера из расчётной части индикатора в буфер рисуемой части, служит метод, аналогичный методу копирования одноцветного буфера:
//+------------------------------------------------------------------+ //| Заполняет переданные в метод рисуемый массив | //| и массив индексов цвета данными из буфера класса | //+------------------------------------------------------------------+ bool CIndMSTF::DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]) { //--- Устанавливаем флаг успешности this.m_success=true; //--- Получаем направление индексации переданного в метод массива буфера и, //--- если индексация не как у таймсерии, - устанавливаем индексацию как у таймсерии bool as_series_plot=::ArrayGetAsSeries(plot_buffer); if(!as_series_plot) ::ArraySetAsSeries(plot_buffer,true); bool as_series_color=::ArrayGetAsSeries(color_buffer); if(!as_series_color) ::ArraySetAsSeries(color_buffer,true); //--- Устанавливаем наименование символа и значение таймфрейма, переданные в метод string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to); ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to); datetime array[2]; //--- Если это первый запуск, или изменения в истории - инициальзируем массив буфера, переданный в метод if(limit>1 && this.m_limit>1) { ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num); ::ArrayInitialize(plot_buffer,this.BufferInitValue(buffer_num)); ::ArrayInitialize(color_buffer,this.BufferInitColorIndex(buffer_num)); } //--- Устанавливаем значение счётчика цикла (не более максимального количества баров в терминале на графике) int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit)); //--- В цикле от нулевого бара до значения счётчика цикла for(int i=0;i<count;i++) { //--- Если таймфрейм графика совпадает с таймфреймом объекта класса - заполняем буфер напрямую из массива объекта класса if(timeframe==::Period() && this.m_timeframe==::Period()) { plot_buffer[i]=this.GetData(buffer_num,array_num,i); color_buffer[i]=this.GetColorData(buffer_num,i); } //--- Иначе, если таймфрейм графика не равен таймфрейму объекта класса else { //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла ::ResetLastError(); if(::CopyTime(symbol,timeframe,i,2,array)!=2) { //--- Если данных нет в терминале - идём дальше if(::GetLastError()==4401) continue; //--- Ошибка получения существующих данных - возвращаем false this.m_success &=false; return false; } //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика объекта класса ::ResetLastError(); int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar==WRONG_VALUE) { this.m_success &=false; continue; } //--- Если это исторические данные (не первый и не нулевой бар) - //--- записываем в буфер индикатора по индексу цикла значение, полученное из буфера расчётной части if(i>1) { plot_buffer[i]=this.GetData(buffer_num,array_num,bar); color_buffer[i]=this.GetColorData(buffer_num,bar); } //--- Если это текущий (нулевой) или предыдущий (первый) бар else { //--- Получаем время баров 0 и 1 по символу/таймфрейму объекта класса if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы текущего и предыдущего баров на графике, символ/период которого передан в метод int bar0=::iBarShift(symbol,timeframe,array[1]); int bar1=::iBarShift(symbol,timeframe,array[0]); if(bar0==WRONG_VALUE || bar1==WRONG_VALUE) { this.m_success &=false; return false; } //--- Если таймфрейм графика младше таймфрейма объекта класса, if(timeframe<this.m_timeframe) { //--- в цикле от бара с меньшим временем до текущего бара графика заполняем буфер данными из двух последних ячеек массива буфера индикатора for(int j=bar1;j>=0;j--) { plot_buffer[j]=this.GetData(buffer_num,array_num,(j>bar0 ? 1 : 0)); color_buffer[j]=this.GetColorData(buffer_num,(j>bar0 ? 1 : 0)); } } //--- Если таймфрейм графика старше таймфрейма объекта класса, else { //--- Получаем время текущего и предыдущего баров по символу/таймфрейму текущего графика if(::CopyTime(symbol,timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы баров в буфере расчётной части индикатора, соответствующие времени текущего и предыдущего баров на графике int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]); int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Записываем в буфер индикатора по индексам 1 и 0 значения из соответствующих индексов буфера расчётной части plot_buffer[1]=this.GetData(buffer_num,array_num,bar1); plot_buffer[0]=this.GetData(buffer_num,array_num,bar0); color_buffer[1]=this.GetColorData(buffer_num,bar1); color_buffer[0]=this.GetColorData(buffer_num,bar0); } } } } //--- Устанавливаем изначальную индексацию переданного в метод массива буфера ::ArraySetAsSeries(plot_buffer,as_series_plot); ::ArraySetAsSeries(color_buffer,as_series_color); //--- Успешно return true; }
Здесь всё точно так же, как и в методе копирования данных одноцветного буфера, только в метод дополнительно передаётся массив индексов цвета рисуемой части, в который необходимо скопировать данные соответствующего массива расчётной части индикатора. Ну и копирование осуществляется для двух массивов — для массива данных и для массива цветов.
Во всех методах, возвращающих какие-либо свойства или данные заданного буфера, теперь указывается и индекс требуемого массива.
//+------------------------------------------------------------------+ //| Заполняет переданный рисуемый массив данными из буфера класса | //+------------------------------------------------------------------+ bool CIndMSTF::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &buffer[]) { //--- Устанавливаем флаг успешности this.m_success=true; //--- Получаем направление индексации переданного в метод массива буфера и, //--- если индексация не как у таймсерии, - устанавливаем индексацию как у таймсерии bool as_series=::ArrayGetAsSeries(buffer); if(!as_series) ::ArraySetAsSeries(buffer,true); //--- Устанавливаем наименование символа и значение таймфрейма, переданные в метод string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to); ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to); datetime array[2]; //--- Если это первый запуск, или изменения в истории - инициальзируем массив буфера, переданный в метод if(limit>1 && this.m_limit>1) { ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num); ::ArrayInitialize(buffer,this.BufferInitValue(buffer_num)); } //--- Устанавливаем значение счётчика цикла (не более максимального количества баров в терминале на графике) int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit)); //--- В цикле от нулевого бара до значения счётчика цикла for(int i=0;i<count;i++) { //--- Если таймфрейм графика совпадает с таймфреймом объекта класса - заполняем буфер напрямую из массива объекта класса if(timeframe==::Period() && this.m_timeframe==::Period()) buffer[i]=this.GetData(buffer_num,array_num,i); //--- Иначе, если таймфрейм графика не равен таймфрейму объекта класса else { //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла ::ResetLastError(); if(::CopyTime(symbol,timeframe,i,2,array)!=2) { //--- Если данных нет в терминале - идём дальше if(::GetLastError()==4401) continue; //--- Ошибка получения существующих данных - возвращаем false this.m_success &=false; return false; } //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика объекта класса ::ResetLastError(); int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar==WRONG_VALUE) { this.m_success &=false; continue; } //--- Если это исторические данные (не первый и не нулевой бар) - //--- записываем в буфер индикатора по индексу цикла значение, полученное из буфера расчётной части if(i>1) buffer[i]=this.GetData(buffer_num,array_num,bar); //--- Если это текущий (нулевой) или предыдущий (первый) бар else { //--- Получаем время баров 0 и 1 по символу/таймфрейму объекта класса if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы текущего и предыдущего баров на графике, символ/период которого передан в метод int bar0=::iBarShift(symbol,timeframe,array[1]); int bar1=::iBarShift(symbol,timeframe,array[0]); if(bar0==WRONG_VALUE || bar1==WRONG_VALUE) { this.m_success &=false; return false; } //--- Если таймфрейм графика младше таймфрейма объекта класса, if(timeframe<this.m_timeframe) { //--- в цикле от бара с меньшим временем до текущего бара графика заполняем буфер данными из двух последних ячеек массива буфера индикатора for(int j=bar1;j>=0;j--) buffer[j]=this.GetData(buffer_num,array_num,(j>bar0 ? 1 : 0)); } //--- Если таймфрейм графика старше таймфрейма объекта класса, else { //--- Получаем время текущего и предыдущего баров по символу/таймфрейму текущего графика if(::CopyTime(symbol,timeframe,0,2,array)!=2) { this.m_success &=false; return false; } //--- Получаем по времени индексы баров в буфере расчётной части индикатора, соответствующие времени текущего и предыдущего баров на графике int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]); int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Записываем в буфер индикатора по индексам 1 и 0 значения из соответствующих индексов буфера расчётной части buffer[1]=this.GetData(buffer_num,array_num,bar1); buffer[0]=this.GetData(buffer_num,array_num,bar0); } } } } //--- Устанавливаем изначальную индексацию переданного в метод массива буфера ::ArraySetAsSeries(buffer,as_series); //--- Успешно return true; }
//+------------------------------------------------------------------+ //| Возвращает данные указанного буфера как есть | //+------------------------------------------------------------------+ double CIndMSTF::GetData(const uint buffer_num,const uint array_num,const int index) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем "пустое" значение самого первого, иначе - EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- Если указан не правильный индекс - возвращаем "пустое" значение указанного буфера if(index<0 || index>(int)this.DataTotal(buffer_num,array_num)-1) return this.BufferInitValue(buffer_num); //--- Рассчитываем реальный индекс в массиве-буфере и возвращаем значение по этому индексу int n=int(this.DataTotal(buffer_num,array_num)-1-index); switch(array_num) { case 0 : return this.m_buffers[buffer_num].array0[n]; case 1 : return this.m_buffers[buffer_num].array1[n]; case 2 : return this.m_buffers[buffer_num].array2[n]; case 3 : return this.m_buffers[buffer_num].array3[n]; case 4 : return this.m_buffers[buffer_num].color_indexes[n]; default: break; } return EMPTY_VALUE; } //+-------------------------------------------------------------------+ //| Возвращает данные указанного буфера на указанный символ/таймфрейм | //+-------------------------------------------------------------------+ double CIndMSTF::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int index) const { //--- Если указан текущий символ/период графика if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol()) return this.GetData(buffer_num,array_num,index); //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); //--- Если у индикатора есть буферы, то возвращаем "пустое" значение самого первого, иначе - EMPTY_VALUE return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE); } //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла datetime array[]; if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1) return this.BufferInitValue(buffer_num); //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика данного класса int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Если бар не найден - возвращаем "пустое" значение, установленное для буфера if(bar==WRONG_VALUE) return this.BufferInitValue(buffer_num); //--- Возвращаем значение из буфера объекта-индикатора по найденному индексу return this.GetData(buffer_num,array_num,bar); }
//+------------------------------------------------------------------+ //| Возвращает состояние линии индикатора как есть | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const uint buffer_num,const uint array_num,const int index) const { //--- Получаем значения линии индикатора со смещением (0,1,2) относительно переданного индекса const double value0=this.GetData(buffer_num,array_num,index); const double value1=this.GetData(buffer_num,array_num,index+1); const double value2=this.GetData(buffer_num,array_num,index+2); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Разворот линии вверх (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Направление линии вверх (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Остановка направления линии вверх (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Разворот линии вниз (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Направление линии вниз (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Остановка направления линии вниз (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Неопределённое состояние return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Возвращает состояние линии индикатора с учётом символа/периода | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const uint array_num,const int index) const { //--- Определяем переданные в метод символ/период графика string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- Если получаем данные от символа/периода, равные текущему графику - возвращаем состояние из буфера "как есть" if(symbol==::Symbol() && symbol==this.m_symbol && timeframe==::Period() && timeframe==this.m_timeframe) return this.BufferLineState(buffer_num,array_num,index); //--- Объявляем переменные для поиска нужных баров на текущем графике datetime array[1]; int bar0=WRONG_VALUE; int bar1=WRONG_VALUE; int bar2=WRONG_VALUE; //--- Получаем время первого бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс первого бара в буфере объекта-индикатора по времени открытия бара на графике bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar0==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем время второго бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+1,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+1,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс второго бара в буфере объекта-индикатора по времени открытия бара на графике bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar1==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем время третьего бара на графике ::ResetLastError(); if(::CopyTime(symbol,timeframe,index+2,1,array)!=1) { ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+2,::GetLastError()); return LINE_STATE_NONE; } //--- Получаем индекс третьего бара в буфере объекта-индикатора по времени открытия бара на графике bar2=::iBarShift(this.m_symbol,this.m_timeframe,array[0]); if(bar2==WRONG_VALUE) { ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError()); return LINE_STATE_NONE; } //--- Получаем значения линии индикатора со смещением (0,1,2) относительно переданного индекса const double value0=this.GetData(buffer_num,array_num,bar0); const double value1=this.GetData(buffer_num,array_num,bar1); const double value2=this.GetData(buffer_num,array_num,bar2); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Разворот линии вверх (value2>value1 && value0>value1) if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_TURN_UP; //--- Направление линии вверх (value2<=value1 && value0>value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0) return LINE_STATE_UP; //--- Остановка направления линии вверх (value2<=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_UP; //--- Разворот линии вниз (value2<value1 && value0<value1) if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_TURN_DOWN; //--- Направление линии вниз (value2>=value1 && value0<value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0) return LINE_STATE_DOWN; //--- Остановка направления линии вниз (value2>=value1 && value0==value1) else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0) return LINE_STATE_STOP_DOWN; //--- Неопределённое состояние return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Возвращает состояние линии относительно указанного уровня | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Получаем значения линии индикатора со смещением (0,1) относительно переданного индекса const double value0=this.GetData(buffer_num,array_num,index); const double value1=this.GetData(buffer_num,array_num,index+1); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Определяем второй сравниваемый уровень double level=(level1==EMPTY_VALUE ? level0 : level1); //--- Линия находится под уровнем (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- Линия находится над уровнем (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- Линия пересекла уровень снизу-вверх (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- Линия пересекла уровень сверху-вниз (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- Линия коснулась уровня снизу (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия коснулась уровня сверху (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия равна значению уровня (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Неопределённое состояние return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Возвращает состояние линии относительно указанного уровня | //| на указанном символе/периоде графика | //+------------------------------------------------------------------+ ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE) { //--- Определяем переданные в метод символ/период графика string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from); ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from); //--- Получаем значения линии индикатора со смещением (0,1) относительно переданного индекса const double value0=this.GetDataTo(symbol,timeframe,buffer_num,array_num,index); const double value1=this.GetDataTo(symbol,timeframe,buffer_num,array_num,index+1); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Определяем второй сравниваемый уровень double level=(level1==EMPTY_VALUE ? level0 : level1); //--- Линия находится под уровнем (value1<level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_BELOW; //--- Линия находится над уровнем (value1>level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_ABOVE; //--- Линия пересекла уровень снизу-вверх (value1<=level && value0>level0) if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0) return LINE_STATE_CROSS_UP; //--- Линия пересекла уровень сверху-вниз (value1>=level && value0<level0) if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0) return LINE_STATE_CROSS_DOWN; //--- Линия коснулась уровня снизу (value1<level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия коснулась уровня сверху (value1>level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия равна значению уровня (value1==level0 && value0==level0) if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0) return LINE_STATE_EQUALS; //--- Неопределённое состояние return LINE_STATE_NONE; }
Методы, возвращающие данные цветного буфера из массива индексов цвета:
//+------------------------------------------------------------------+ //| Возвращает данные указанного буфера индексов цвета как есть | //+------------------------------------------------------------------+ double CIndMSTF::GetColorData(const uint buffer_num,const int index) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем 0 if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Если это не цветной буфер - сообщаем об этом в журнал и возвращаем 0 if(!this.IsColoredBuffer(buffer_num)) { ::PrintFormat("%s: Buffer %lu is not a color buffer",__FUNCTION__,buffer_num); return 0; } //--- Если указан не правильный индекс - возвращаем "пустое" значение указанного буфера цвета if(index<0 || index>(int)this.DataTotal(buffer_num,4)-1) return this.BufferInitColorIndex(buffer_num); //--- Рассчитываем реальный индекс в массиве-буфере цвета и возвращаем значение по этому индексу int n=int(this.DataTotal(buffer_num,4)-1-index); return this.m_buffers[buffer_num].color_indexes[n]; } //+------------------------------------------------------------------+ //| Возвращает данные указанного буфера индексов цвета | //| на указанный символ/таймфрейм | //+------------------------------------------------------------------+ double CIndMSTF::GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const { //--- Если указан текущий символ/период графика if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol()) return this.GetColorData(buffer_num,index); //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем 0 if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Если это не цветной буфер - сообщаем об этом в журнал и возвращаем 0 if(!this.IsColoredBuffer(buffer_num)) { ::PrintFormat("%s: Buffer %lu is not a color buffer",__FUNCTION__,buffer_num); return 0; } //--- Узнаём какому времени данного класса принадлежит бар текущего таймфрейма графика, соответствующий индексу цикла datetime array[]; if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1) return this.BufferInitColorIndex(buffer_num); //--- По времени бара текущего таймфрейма графика находим соответствующий индекс бара периода графика данного класса int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]); //--- Если бар не найден - возвращаем "пустое" значение, установленное для буфера цвета if(bar==WRONG_VALUE) return this.BufferInitColorIndex(buffer_num); //--- Возвращаем значение из буфера цвета объекта-индикатора по найденному индексу return this.GetColorData(buffer_num,bar); //--- Рассчитываем реальный индекс в массиве-буфере цвета и возвращаем значение по этому индексу int n=int(this.DataTotal(buffer_num,4)-1-bar); return this.m_buffers[buffer_num].color_indexes[n]; }
Методы, обращающиеся к каким-либо данным буфера, теперь делают это через указание массива требуемого буфера:
//+------------------------------------------------------------------+ //| Отключает индексацию массивов буферов как у таймсерии | //+------------------------------------------------------------------+ void CIndMSTF::SetAsSeriesOff(void) { //--- В цикле по всем буферам индикатора отключаем флаг серийности массивов for(int i=0;i<(int)this.BuffersTotal();i++) { ::ArraySetAsSeries(this.m_buffers[i].array0,false); ::ArraySetAsSeries(this.m_buffers[i].array1,false); ::ArraySetAsSeries(this.m_buffers[i].array2,false); ::ArraySetAsSeries(this.m_buffers[i].array3,false); ::ArraySetAsSeries(this.m_buffers[i].color_indexes,false); } } //+------------------------------------------------------------------+ //| Возвращает флаг серийности указанного буфера | //+------------------------------------------------------------------+ bool CIndMSTF::IsSeries(const uint buffer_num,const uint array_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем false if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return false; } //--- Возвращаем флаг серийности массива указанного буфера switch(array_num) { case 0 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array0); case 1 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array1); case 2 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array2); case 3 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array3); case 4 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].color_indexes); default: break; } return false; } //+------------------------------------------------------------------+ //| Возвращает количество данных указанного буфера | //+------------------------------------------------------------------+ uint CIndMSTF::DataTotal(const uint buffer_num,const uint array_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем ноль if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Возвращаем размер массива указанного буфера switch(array_num) { case 0 : return this.m_buffers[buffer_num].array0.Size(); case 1 : return this.m_buffers[buffer_num].array1.Size(); case 2 : return this.m_buffers[buffer_num].array2.Size(); case 3 : return this.m_buffers[buffer_num].array3.Size(); case 4 : return this.m_buffers[buffer_num].color_indexes.Size(); default: break; } return 0; }
Метод, возвращающий количество цветов, установленных буферу:
//+------------------------------------------------------------------+ //| Возвращает количество цветов, установленных буферу | //+------------------------------------------------------------------+ uint CIndMSTF::ColorsTotal(const uint buffer_num) const { //--- Проверяем корректность переданного в метод номера буфера и, если номер не верный, сообщаем об этом в журнал и возвращаем ноль if(buffer_num>this.BuffersTotal()-1) { string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1)); ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit); return 0; } //--- Возвращаем размер массива цветов указанного буфера return this.m_buffers[buffer_num].clrs.Size(); }
Классы стандартных технических индикаторов также были доработаны. Теперь в конструкторе класса указываются стили рисования каждого буфера индикатора и индекс исходного массива, на котором строится буфер класса индикатора:
//+------------------------------------------------------------------+ //| Класс индикатора Accelerator Oscillator | //+------------------------------------------------------------------+ class CIndAC : public CIndMSTF { public: //--- Конструктор CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe) { //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("AC"); this.SetDescription("Accelerator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0); //--- Зададим для цветного буфера 0 два цвета по умолчанию this.SetBufferColorToIndex(0,0,clrGreen); this.SetBufferColorToIndex(0,1,clrRed); //--- Установим инициализирующий индекс цвета по умолчанию this.SetBufferInitColorIndex(0,0); } };
Для цветных буферов также устанавливаются цвета линии по умолчанию как в соответствующем стандартном индикаторе и индекс цвета, которым изначально инициализируется буфер.
Листинг классов остальных стандартных индикаторов (некоторые классы индикаторов ещё не доработаны):
//+------------------------------------------------------------------+ //| Класс индикатора Accumulation/Distribution | //+------------------------------------------------------------------+ class CIndAD : public CIndMSTF { public: //--- Конструктор CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // используемый объем ) : CIndMSTF(IND_AD,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("A/D"); this.SetDescription("Accumulation/Distribution"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average Directional Movement Index | //+------------------------------------------------------------------+ class CIndADX : public CIndMSTF { public: //--- Конструктор CIndADX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // период усреднения ) : CIndMSTF(IND_ADX,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("ADX"); this.SetDescription("Average Directional Movement Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- записываем описания буферов линий MAIN_LINE, PLUSDI_LINE и MINUSDI_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); //--- Установим стиль рисования для буферов 0, 1, 2 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE); this.SetBufferDrawType(1,DRAW_LINE,PLUSDI_LINE); this.SetBufferDrawType(2,DRAW_LINE,MINUSDI_LINE); //--- Зададим для буферов 0, 1 и 2 цвета по умолчанию this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen); this.SetBufferColorToIndex(PLUSDI_LINE,0,clrYellowGreen); this.SetBufferColorToIndex(MINUSDI_LINE,0,clrWheat); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average Directional Movement Index Wilder | //+------------------------------------------------------------------+ class CIndADXW : public CIndMSTF { public: //--- Конструктор CIndADXW(const string symbol,const ENUM_TIMEFRAMES timeframe, const int adx_period // период усреднения ) : CIndMSTF(IND_ADXW,3,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("ADX Wilder"); this.SetDescription("Average Directional Movement Index Wilder"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=2; //--- записываем описания буферов линий MAIN_LINE, PLUSDI_LINE и MINUSDI_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(PLUSDI_LINE,"+DI"); this.SetBufferDescription(MINUSDI_LINE,"-DI"); //--- Установим стиль рисования для буферов 0, 1, 2 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE); this.SetBufferDrawType(1,DRAW_LINE,PLUSDI_LINE); this.SetBufferDrawType(2,DRAW_LINE,MINUSDI_LINE); //--- Зададим для буферов 0, 1 и 2 цвета по умолчанию this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen); this.SetBufferColorToIndex(PLUSDI_LINE,0,clrYellowGreen); this.SetBufferColorToIndex(MINUSDI_LINE,0,clrWheat); } }; //+------------------------------------------------------------------+ //| Класс индикатора Alligator | //+------------------------------------------------------------------+ class CIndAlligator : public CIndMSTF { public: //--- Конструктор CIndAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // период для расчета челюстей const int jaw_shift, // смещение челюстей по горизонтали const int teeth_period, // период для расчета зубов const int teeth_shift, // смещение зубов по горизонтали const int lips_period, // период для расчета губ const int lips_shift, // смещение губ по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_ALLIGATOR,3,symbol,timeframe) { // Номера буферов: 0 - GATORJAW_LINE, 1 - GATORTEETH_LINE, 2 - GATORLIPS_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- период для расчета челюстей this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- смещение челюстей по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- период для расчета зубов this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- смещение зубов по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- период для расчета губ this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- смещение губ по горизонтали this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- тип сглаживания this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- тип цены или handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("Alligator"); this.SetDescription("Alligator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описания буферов линий GATORJAW_LINE, GATORTEETH_LINE и GATORLIPS_LINE this.SetBufferDescription(GATORJAW_LINE,::StringFormat("Jaws(%s%lu)", (current ? "" : symbol_period+":"),jaw_period)); this.SetBufferDescription(GATORTEETH_LINE,::StringFormat("Teeth(%s%lu)",(current ? "" : symbol_period+":"),teeth_period)); this.SetBufferDescription(GATORLIPS_LINE,::StringFormat("Lips(%s%lu)", (current ? "" : symbol_period+":"),lips_period)); //--- Записываем смещения в буферы GATORJAW_LINE, GATORTEETH_LINE и GATORLIPS_LINE this.SetBufferShift(GATORJAW_LINE,jaw_shift); this.SetBufferShift(GATORTEETH_LINE,teeth_shift); this.SetBufferShift(GATORLIPS_LINE,lips_shift); //--- Установим стиль рисования для буферов 0, 1, 2 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,GATORJAW_LINE); this.SetBufferDrawType(1,DRAW_LINE,GATORTEETH_LINE); this.SetBufferDrawType(2,DRAW_LINE,GATORLIPS_LINE); //--- Зададим для буферов 0, 1 и 2 цвета по умолчанию this.SetBufferColorToIndex(GATORJAW_LINE,0,clrBlue); this.SetBufferColorToIndex(GATORTEETH_LINE,0,clrRed); this.SetBufferColorToIndex(GATORLIPS_LINE,0,clrLime); } }; //+------------------------------------------------------------------+ //| Класс индикатора Adaptive Moving Average | //+------------------------------------------------------------------+ class CIndAMA : public CIndMSTF { public: //--- Конструктор CIndAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period, // период AMA const int fast_ma_period, // период быстрой скользящей const int slow_ma_period, // период медленной скользящей const int ama_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_AMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- период AMA this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ama_period<1 ? 9 : ama_period); //--- период быстрой скользящей this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(fast_ma_period<1 ? 2 : fast_ma_period); //--- период медленной скользящей this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slow_ma_period<1 ? 30 : slow_ma_period); //--- смещение индикатора по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=ama_shift; //--- тип цены или handle this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),ama_period,fast_ma_period,slow_ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("AMA"); this.SetDescription("Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ama_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Awesome Oscillator | //+------------------------------------------------------------------+ class CIndAO : public CIndMSTF { public: //--- Конструктор CIndAO(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AO,1,symbol,timeframe) { //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("AO"); this.SetDescription("Awesome Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0); //--- Зададим для цветного буфера 0 два цвета по умолчанию this.SetBufferColorToIndex(0,0,clrGreen); this.SetBufferColorToIndex(0,1,clrRed); //--- Установим инициализирующий индекс цвета по умолчанию this.SetBufferInitColorIndex(0,0); } }; //+------------------------------------------------------------------+ //| Класс индикатора Average True Range | //+------------------------------------------------------------------+ class CIndATR : public CIndMSTF { public: //--- Конструктор CIndATR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_ATR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("ATR"); this.SetDescription("Average True Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bears Power | //+------------------------------------------------------------------+ class CIndBears : public CIndMSTF { public: //--- Конструктор CIndBears(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_BEARS,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bears"); this.SetDescription("Bears Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_HISTOGRAM,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrSilver); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bulls Power | //+------------------------------------------------------------------+ class CIndBulls : public CIndMSTF { public: //--- Конструктор CIndBulls(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_BULLS,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bulls"); this.SetDescription("Bulls Power"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_HISTOGRAM,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrSilver); } }; //+------------------------------------------------------------------+ //| Класс индикатора Bollinger Bands® | //+------------------------------------------------------------------+ class CIndBands : public CIndMSTF { public: //--- Конструктор CIndBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period, // период для расчета средней линии const int bands_shift, // смещение индикатора по горизонтали const double deviation, // кол-во стандартных отклонений const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_BANDS,3,symbol,timeframe) { // Номера буферов: 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период для расчета средней линии this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(bands_period<1 ? 20 : bands_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=bands_shift; //--- кол-во стандартных отклонений this.m_param[2].type=TYPE_DOUBLE; this.m_param[2].double_value=deviation; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),bands_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Bands"); this.SetDescription("Bollinger Bands"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //---Описание буферов линий BASE_LINE, UPPER_BAND и LOWER_BAND this.SetBufferDescription(BASE_LINE,this.m_title+" Middle"); this.SetBufferDescription(UPPER_BAND,this.m_title+" Upper"); this.SetBufferDescription(LOWER_BAND,this.m_title+" Lower"); //--- Записываем смещения в буферы BASE_LINE, UPPER_BAND и LOWER_BAND this.SetBufferShift(BASE_LINE,bands_shift); this.SetBufferShift(UPPER_BAND,bands_shift); this.SetBufferShift(LOWER_BAND,bands_shift); //--- Установим стиль рисования для буферов 0, 1, 2 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,BASE_LINE); this.SetBufferDrawType(1,DRAW_LINE,UPPER_BAND); this.SetBufferDrawType(2,DRAW_LINE,LOWER_BAND); //--- Зададим для буферов 0, 1 и 2 цвета по умолчанию this.SetBufferColorToIndex(BASE_LINE,0,clrMediumSeaGreen); this.SetBufferColorToIndex(UPPER_BAND,0,clrMediumSeaGreen); this.SetBufferColorToIndex(LOWER_BAND,0,clrMediumSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Commodity Channel Index | //+------------------------------------------------------------------+ class CIndCCI : public CIndMSTF { public: //--- Конструктор CIndCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_CCI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("CCI"); this.SetDescription("Commodity Channel Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Chaikin Oscillator | //+------------------------------------------------------------------+ class CIndCHO : public CIndMSTF { public: //--- Конструктор CIndCHO(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period, // быстрый период const int slow_ma_period, // медленный период const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_VOLUME applied_volume // используемый объем ) : CIndMSTF(IND_CHAIKIN,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- быстрый период this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ma_period<1 ? 3 : fast_ma_period); //--- медленный период this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ma_period<1 ? 10 : slow_ma_period); //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- используемый объем this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),slow_ma_period,fast_ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("CHO"); this.SetDescription("Chaikin Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Double Exponential Moving Average | //+------------------------------------------------------------------+ class CIndDEMA : public CIndMSTF { public: //--- Конструктор CIndDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_DEMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("DEMA"); this.SetDescription("Double Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора DeMarker | //+------------------------------------------------------------------+ class CIndDeM : public CIndMSTF { public: //--- Конструктор CIndDeM(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_DEMARKER,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("DeM"); this.SetDescription("DeMarker"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Envelopes | //+------------------------------------------------------------------+ class CIndEnvelopes : public CIndMSTF { public: //--- Конструктор CIndEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период для расчета средней линии const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price, // тип цены или handle const double deviation // отклонение границ от средней линии ) : CIndMSTF(IND_ENVELOPES,2,symbol,timeframe) { // Номера буферов: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- период для расчета средней линии this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; //--- отклонение границ от средней линии this.m_param[4].type=TYPE_DOUBLE; this.m_param[4].double_value=deviation; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Envelopes"); this.SetDescription("Envelopes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Описание буферов линий UPPER_LINE и LOWER_LINE this.SetBufferDescription(UPPER_LINE,this.m_title+" Upper"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Lower"); //--- Записываем смещение в буферы this.SetBufferShift(0,ma_shift); this.SetBufferShift(1,ma_shift); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,UPPER_LINE); this.SetBufferDrawType(1,DRAW_LINE,LOWER_LINE); //--- Зададим для буферов 0 и 1 цвета по умолчанию this.SetBufferColorToIndex(UPPER_LINE,0,clrBlue); this.SetBufferColorToIndex(LOWER_LINE,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Force Index | //+------------------------------------------------------------------+ class CIndForce : public CIndMSTF { public: //--- Конструктор CIndForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_FORCE,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period); //--- тип сглаживания this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=ma_method; //--- тип объема для расчета this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Force"); this.SetDescription("Force Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Fractals | //+------------------------------------------------------------------+ class CIndFractals : public CIndMSTF { public: //--- Конструктор CIndFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_FRACTALS,2,symbol,timeframe) { // Номера буферов: 0 - UPPER_LINE, 1 - LOWER_LINE //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("Fractals"); this.SetDescription("Fractals"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Описание буферов линий UPPER_LINE и LOWER_LINE this.SetBufferDescription(UPPER_LINE,this.m_title+" Up"); this.SetBufferDescription(LOWER_LINE,this.m_title+" Down"); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_ARROW,UPPER_LINE); this.SetBufferDrawType(1,DRAW_ARROW,LOWER_LINE); //--- Зададим для буферов 0 и 1 цвета по умолчанию this.SetBufferColorToIndex(UPPER_LINE,0,clrGray); this.SetBufferColorToIndex(LOWER_LINE,0,clrGray); } }; //+------------------------------------------------------------------+ //| Класс индикатора Fractal Adaptive Moving Average | //+------------------------------------------------------------------+ class CIndFrAMA : public CIndMSTF { public: //--- Конструктор CIndFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_FRAMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("FRAMA"); this.SetDescription("Fractal Adaptive Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrBlue); } }; //+------------------------------------------------------------------+ //| Класс индикатора Gator Oscillator | //+------------------------------------------------------------------+ class CIndGator : public CIndMSTF { public: //--- Конструктор CIndGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, // период для расчета челюстей const int jaw_shift, // смещение челюстей по горизонтали const int teeth_period, // период для расчета зубов const int teeth_shift, // смещение зубов по горизонтали const int lips_period, // период для расчета губ const int lips_shift, // смещение губ по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_GATOR,2,symbol,timeframe) { // Номера буферов: 0 - UPPER_HISTOGRAM, 1- цветовой буфер верхней гистограммы, 2 - LOWER_HISTOGRAM, 3- цветовой буфер нижней гистограммы //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,8)==8) { ::ZeroMemory(this.m_param); //--- период для расчета челюстей this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period); //--- смещение челюстей по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=jaw_shift; //--- период для расчета зубов this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period); //--- смещение зубов по горизонтали this.m_param[3].type=TYPE_INT; this.m_param[3].integer_value=teeth_shift; //--- период для расчета губ this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period); //--- смещение губ по горизонтали this.m_param[5].type=TYPE_INT; this.m_param[5].integer_value=lips_shift; //--- тип сглаживания this.m_param[6].type=TYPE_UINT; this.m_param[6].integer_value=ma_method; //--- тип цены или handle this.m_param[7].type=TYPE_UINT; this.m_param[7].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Gator"); this.SetDescription("Gator Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; this.m_digits=::Digits()+1; //--- Описание буферов линий UPPER_HISTOGRAM, буфер цвета верхней гистограммы, LOWER_HISTOGRAM и буфер цвета нижней гистограммы this.SetBufferDescription(0,this.m_title+" Up"); this.SetBufferDescription(1,this.m_title+" Down"); //--- Записываем смещения в буферы UPPER_HISTOGRAM, 1, LOWER_HISTOGRAM и 2 this.SetBufferShift(0,teeth_shift); this.SetBufferShift(1,lips_shift); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,UPPER_HISTOGRAM); this.SetBufferDrawType(1,DRAW_COLOR_HISTOGRAM,LOWER_HISTOGRAM); //--- Зададим для цветных буферов цвета по умолчанию this.SetBufferColorToIndex(0,0,clrGreen); this.SetBufferColorToIndex(0,1,clrRed); this.SetBufferColorToIndex(1,0,clrGreen); this.SetBufferColorToIndex(1,1,clrRed); //--- Установим инициализирующий индекс цвета по умолчанию this.SetBufferInitColorIndex(0,0); this.SetBufferInitColorIndex(1,0); } }; //+------------------------------------------------------------------+ //| Класс индикатора Ichimoku Kinko Hyo | //+------------------------------------------------------------------+ class CIndIchimoku : public CIndMSTF { public: //--- Конструктор CIndIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen, // период Tenkan-sen const int kijun_sen, // период Kijun-sen const int senkou_span_b // период Senkou Span B ) : CIndMSTF(IND_ICHIMOKU,5,symbol,timeframe) { // Номера буферов: 0 - TENKANSEN_LINE, 1 - KIJUNSEN_LINE, 2 - SENKOUSPANA_LINE, 3 - SENKOUSPANB_LINE, 4 - CHIKOUSPAN_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период Tenkan-sen this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(tenkan_sen<1 ? 9 : tenkan_sen); //--- период Kijun-sen this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(kijun_sen<1 ? 26 : kijun_sen); //--- период Senkou Span B this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(senkou_span_b<1 ? 52 : senkou_span_b); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),tenkan_sen,kijun_sen,senkou_span_b); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Ichimoku"); this.SetDescription("Ichimoku Kinko Hyo"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Описание буферов линий TENKANSEN_LINE, KIJUNSEN_LINE, SENKOUSPANA_LINE, SENKOUSPANB_LINE и CHIKOUSPAN_LINE this.SetBufferDescription(TENKANSEN_LINE,::StringFormat("Tenkan-sen(%lu)",tenkan_sen)); this.SetBufferDescription(KIJUNSEN_LINE,::StringFormat("Kijun-sen(%lu)",kijun_sen)); this.SetBufferDescription(SENKOUSPANA_LINE,"Senkou Span A"); this.SetBufferDescription(SENKOUSPANB_LINE,::StringFormat("Senkou Span B(%lu)",senkou_span_b)); this.SetBufferDescription(CHIKOUSPAN_LINE,"Chikou Span"); //--- Записываем смещения в буферы SENKOUSPANA_LINE, SENKOUSPANB_LINE и CHIKOUSPAN_LINE //this.SetBufferShift(SENKOUSPANA_LINE,kijun_sen); //this.SetBufferShift(SENKOUSPANB_LINE,kijun_sen); //this.SetBufferShift(CHIKOUSPAN_LINE,kijun_sen-senkou_span_b); } }; //+------------------------------------------------------------------+ //| Класс индикатора Market Facilitation Index | //+------------------------------------------------------------------+ class CIndBWMFI : public CIndMSTF { public: //--- Конструктор CIndBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_BWMFI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема для расчета this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("BW MFI"); this.SetDescription("Market Facilitation Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_WILLIAMS; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0); //--- Зададим для цветного буфера 0 четыре цвета по умолчанию this.SetBufferColorToIndex(0,0,clrLime); this.SetBufferColorToIndex(0,1,clrSaddleBrown); this.SetBufferColorToIndex(0,2,clrBlue); this.SetBufferColorToIndex(0,3,clrPink); //--- Установим инициализирующий индекс цвета по умолчанию this.SetBufferInitColorIndex(0,0); } }; //+------------------------------------------------------------------+ //| Класс индикатора Momentum | //+------------------------------------------------------------------+ class CIndMomentum : public CIndMSTF { public: //--- Конструктор CIndMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MOMENTUM,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(mom_period<1 ? 14 : mom_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),mom_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Momentum"); this.SetDescription("Momentum"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrDodgerBlue); } }; //+------------------------------------------------------------------+ //| Класс индикатора Money Flow Index | //+------------------------------------------------------------------+ class CIndMFI : public CIndMSTF { public: //--- Конструктор CIndMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_MFI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- тип объема для расчета this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("MFI"); this.SetDescription("Money Flow Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrDodgerBlue); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Average | //+------------------------------------------------------------------+ class CIndMA : public CIndMSTF { public: //--- Конструктор CIndMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("MA"); this.SetDescription("Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Average of Oscillator | //+------------------------------------------------------------------+ class CIndOsMA : public CIndMSTF { public: //--- Конструктор CIndOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // период быстрой средней const int slow_ema_period, // период медленной средней const int signal_period, // период усреднения разности const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_OSMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период быстрой средней this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- период медленной средней this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- период усреднения разности this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period<2 ? 2 : signal_period); //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("OsMA"); this.SetDescription("Moving Average of Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_HISTOGRAM,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrSilver); } }; //+------------------------------------------------------------------+ //| Класс индикатора Moving Averages Convergence/Divergence | //+------------------------------------------------------------------+ class CIndMACD : public CIndMSTF { public: //--- Конструктор CIndMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, // период быстрой средней const int slow_ema_period, // период медленной средней const int signal_period, // период усреднения разности const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_MACD,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период быстрой средней this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period); //--- период медленной средней this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period); //--- период усреднения разности this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period); //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("MACD"); this.SetDescription("Moving Averages Convergence/Divergence"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=::Digits()+1; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_HISTOGRAM,MAIN_LINE); this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE); //--- Зададим для буферов 0 и 1 цвета по умолчанию this.SetBufferColorToIndex(MAIN_LINE,0,clrSilver); this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора On Balance Volume | //+------------------------------------------------------------------+ class CIndOBV : public CIndMSTF { public: //--- Конструктор CIndOBV(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема для расчета ) : CIndMSTF(IND_OBV,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема для расчета this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("OBV"); this.SetDescription("On Balance Volume"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLightSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Parabolic Stop and Reverse system | //+------------------------------------------------------------------+ class CIndSAR : public CIndMSTF { public: //--- Конструктор CIndSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step, // шаг изменения цены - коэффициент ускорения const double maximum // максимальный шаг ) : CIndMSTF(IND_SAR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- шаг изменения цены - коэффициент ускорения this.m_param[0].type=TYPE_DOUBLE; this.m_param[0].double_value=step; //--- максимальный шаг this.m_param[1].type=TYPE_DOUBLE; this.m_param[1].double_value=maximum; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%.2f,%.2f)",symbol_period,(current ? "" : ":"),step,maximum); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("SAR"); this.SetDescription("Parabolic SAR"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_ARROW,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrLime); } }; //+------------------------------------------------------------------+ //| Класс индикатора Relative Strength Index | //+------------------------------------------------------------------+ class CIndRSI : public CIndMSTF { public: //--- Конструктор CIndRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_RSI,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("RSI"); this.SetDescription("Relative Strength Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrDodgerBlue); } }; //+------------------------------------------------------------------+ //| Класс индикатора Relative Vigor Index | //+------------------------------------------------------------------+ class CIndRVI : public CIndMSTF { public: //--- Конструктор CIndRVI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period // период усреднения ) : CIndMSTF(IND_RVI,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("RVI"); this.SetDescription("Relative Vigor Index"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=3; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE); this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE); //--- Зададим для буферов 0 и 1 цвета по умолчанию this.SetBufferColorToIndex(MAIN_LINE,0,clrGreen); this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Standard Deviation | //+------------------------------------------------------------------+ class CIndStdDev : public CIndMSTF { public: //--- Конструктор CIndStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_STDDEV,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 20 : ma_period<2 ? 2 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип сглаживания this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=ma_method; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("StdDev"); this.SetDescription("Standard Deviation"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrMediumSeaGreen); } }; //+------------------------------------------------------------------+ //| Класс индикатора Stochastic Oscillator | //+------------------------------------------------------------------+ class CIndStoch : public CIndMSTF { public: //--- Конструктор CIndStoch(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod, // K-период (количество баров для расчетов) const int Dperiod, // D-период (период первичного сглаживания) const int slowing, // окончательное сглаживание const ENUM_MA_METHOD ma_method, // тип сглаживания const ENUM_STO_PRICE price_field // способ расчета стохастика ) : CIndMSTF(IND_STOCHASTIC,2,symbol,timeframe) { // Номера буферов: 0 - MAIN_LINE, 1 - SIGNAL_LINE //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,5)==5) { ::ZeroMemory(this.m_param); //--- K-период (количество баров для расчетов) this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(Kperiod<1 ? 5 : Kperiod); //--- D-период (период первичного сглаживания) this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(Dperiod<1 ? 3 : Dperiod); //--- окончательное сглаживание this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=(slowing<1 ? 3 : slowing); //--- тип сглаживания this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=ma_method; //--- способ расчета стохастика this.m_param[4].type=TYPE_UINT; this.m_param[4].integer_value=price_field; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),Kperiod,Dperiod,slowing); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Stoch"); this.SetDescription("Stochastic Oscillator"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Описание буферов линии MAIN_LINE и SIGNAL_LINE this.SetBufferDescription(MAIN_LINE,this.m_title); this.SetBufferDescription(SIGNAL_LINE,"Signal"); //--- Установим стиль рисования для буферов 0, 1 и номера буферов данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE); this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE); //--- Зададим для буферов 0 и 1 цвета по умолчанию this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen); this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Triple Exponential Moving Average | //+------------------------------------------------------------------+ class CIndTEMA : public CIndMSTF { public: //--- Конструктор CIndTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_TEMA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,3)==3) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period); //--- смещение индикатора по горизонтали this.m_param[1].type=TYPE_INT; this.m_param[1].integer_value=ma_shift; //--- тип цены или handle this.m_param[2].type=TYPE_UINT; this.m_param[2].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("TEMA"); this.SetDescription("Triple Exponential Moving Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Triple Exponential Moving Averages Oscillator | //+------------------------------------------------------------------+ class CIndTriX : public CIndMSTF { public: //--- Конструктор CIndTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, // период усреднения const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_TRIX,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,2)==2) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period); //--- тип цены или handle this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName("TRIX"); this.SetDescription("Triple Exponential Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Larry Williams' Percent Range | //+------------------------------------------------------------------+ class CIndWPR : public CIndMSTF { public: //--- Конструктор CIndWPR(const string symbol,const ENUM_TIMEFRAMES timeframe, const int calc_period // период усреднения ) : CIndMSTF(IND_WPR,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- период усреднения this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(calc_period<1 ? 14 : calc_period); } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),calc_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("%R"); this.SetDescription("Williams' Percent Range"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_OSCILLATOR; this.m_digits=2; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrAqua); } }; //+------------------------------------------------------------------+ //| Класс индикатора Variable Index Dynamic Average | //+------------------------------------------------------------------+ class CIndVIDyA : public CIndMSTF { public: //--- Конструктор CIndVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period, // период Chande Momentum const int ema_period, // период фактора сглаживания const int ma_shift, // смещение индикатора по горизонтали const ENUM_APPLIED_PRICE applied_price // тип цены или handle ) : CIndMSTF(IND_VIDYA,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,4)==4) { ::ZeroMemory(this.m_param); //--- период Chande Momentum this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=(cmo_period<1 ? 9 : cmo_period); //--- период фактора сглаживания this.m_param[1].type=TYPE_UINT; this.m_param[1].integer_value=(ema_period<1 ? 12 : ema_period); //--- смещение индикатора по горизонтали this.m_param[2].type=TYPE_INT; this.m_param[2].integer_value=ma_shift; //--- тип цены или handle this.m_param[3].type=TYPE_UINT; this.m_param[3].integer_value=applied_price; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),cmo_period,ema_period); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("VIDYA"); this.SetDescription("Variable Index Dynamic Average"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_TREND; this.m_digits=::Digits()+1; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Записываем смещение в буфер 0 this.SetBufferShift(0,ma_shift); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_LINE,0); //--- Зададим для буфера 0 цвет по умолчанию this.SetBufferColorToIndex(0,0,clrRed); } }; //+------------------------------------------------------------------+ //| Класс индикатора Volumes | //+------------------------------------------------------------------+ class CIndVolumes : public CIndMSTF { public: //--- Конструктор CIndVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume // тип объема ) : CIndMSTF(IND_VOLUMES,1,symbol,timeframe) { //--- Устанавливаем размер массива параметров и заполняем его ::ResetLastError(); if(::ArrayResize(this.m_param,1)==1) { ::ZeroMemory(this.m_param); //--- тип объема this.m_param[0].type=TYPE_UINT; this.m_param[0].integer_value=applied_volume; } else ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError()); //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок, категорию и Digits индикатора this.SetParameters(param); this.SetName("Volumes"); this.SetDescription("Volumes"); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_VOLUME; this.m_digits=0; //--- Записываем описание буфера линии this.SetBufferDescription(0,this.m_title); //--- Установим стиль рисования для буфера 0 и номер буфера данных расчётной части this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0); //--- Зададим для цветного буфера 0 два цвета по умолчанию this.SetBufferColorToIndex(0,0,clrGreen); this.SetBufferColorToIndex(0,1,clrRed); //--- Установим инициализирующий индекс цвета по умолчанию this.SetBufferInitColorIndex(0,0); } }; //+------------------------------------------------------------------+ //| Класс пользовательского индикатора | //+------------------------------------------------------------------+ class CIndCustom : public CIndMSTF { public: //--- Конструктор CIndCustom(const string symbol,const ENUM_TIMEFRAMES timeframe, const string path, // путь к индикатору (например, "Examples\\MACD.ex5") const string name, // имя пользовательского индикатора const uint buffers, // количество буферов индикатора const MqlParam ¶m[] // массив параметров пользовательского индикатора ) : CIndMSTF(IND_CUSTOM,buffers,symbol,timeframe) { //--- Если передан пустой массив параметров - сообщаем об этом в журнал int total=(int)param.Size(); if(total==0) ::PrintFormat("%s Error. Passed an empty array",__FUNCTION__); //--- Если массив не пустой и его размер увеличен на 1 (в первый параметр типа string должно быть записано имя индикатора) ResetLastError(); if(total>0 && ::ArrayResize(this.m_param,total+1)==total+1) { //--- Обнуляем данные в массиве и вписываем имя (путь к файлу и имя .ex5 файла) ::ZeroMemory(this.m_param); //--- имя пользовательского индикатора this.m_param[0].type=TYPE_STRING; this.m_param[0].string_value=path; //--- заполняем массив параметров индикатора for(int i=0;i<total;i++) { this.m_param[i+1].type=param[i].type; this.m_param[i+1].double_value=param[i].double_value; this.m_param[i+1].integer_value=param[i].integer_value; this.m_param[i+1].string_value=param[i].string_value; } //--- Создаём описание параметров. //--- Если символ или период графика не текущие, то к параметрам добавляются их описания bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period()); string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription())); string param=(current ? "" : StringFormat("(%s)",symbol_period)); //--- Записываем описание параметров, наименование индикатора, его описание, заголовок и категорию this.SetParameters(param); this.SetName(name); this.SetDescription(name); this.m_title=this.Name()+this.Parameters(); this.m_category=IND_CATEGORY_CUSTOM; //--- Записываем описание первого буфера линии this.SetBufferDescription(0,this.m_title); } } };
По стилю рисования, установленному для буфера, мы можем определить цветной это буфер, или нет, и соответственно использовать те, или иные методы для отрисовки буфера. Указывая индекс буфера расчётной части и записывая его в буфер класса индикатора, мы даём возможность легко определить с какого буфера расчётной части производить копирование данных. Также, если это цветной буфер, то, помня о том, что буфер цвета всегда идёт следующим за буфером данных расчётной части, мы можем точно знать с какого буфера получать данные о цвете линии — просто прибавляя к индексу буфера расчётной части единицу для получения нужного индекса цвета. И все эти данные уже записаны в буфер класса индикатора, что достаточно удобно.
В классе-коллекции индикаторов тоже необходимо внести доработки в методы и добавить новые.
//+------------------------------------------------------------------+ //| Класс-коллекция индикаторов | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> class CMSTFIndicators { private: CArrayObj m_list; //--- Создаёт индикатор для переданного объекта bool CreateIndicator(CIndMSTF *ind_obj); //--- Добавляет указанный индикатор в коллекцию int AddNewIndicator(CIndMSTF *ind_obj,const string source); public: //--- Возвращает (1) объект индикатора по хэндлу, (2) количество индикаторов в коллекции CIndMSTF *GetIndicatorObj(const int ind_handle,const string source) const; uint IndicatorsTotal(void) const { return this.m_list.Total(); } //--- Заполняет данными буферы (1) индикатора по хэндлу, (2) всех индикаторов в коллекции bool Calculate(const int ind_handle); bool Calculate(void); //--- Устанавливает (1) указанное, (2) по умолчанию описание, (3) цвета линии буфера индикатора void SetPlotLabel(const uint plot_index,const string descript); void SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num); void SetPlotColorsFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num); //--- Устанавливает смещение указанному рисуемому буферу void SetPlotShift(const uint plot_index,const int shift); //--- (1) Устанавливает (2) возвращает инициализирующее значение указанного буфера указанного по хэндлу индикатора void SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value); double BufferInitValue(const int ind_handle,const uint buffer_num) const; //--- (1) Устанавливает (2) возвращает инициализирующее значение индекса цвета для указанного буфера void SetBufferInitColorIndex(const int ind_handle,const uint buffer_num,const uchar index); uchar BufferInitColorIndex(const int ind_handle,const uint buffer_num) const; //--- (1) Устанавливает, (2) возвращает значение цвета по индексу для указанного буфера void SetBufferColorToIndex(const int ind_handle,const uint buffer_num,const uchar color_idx,const color clr); color BufferColorByIndex(const int ind_handle,const uint buffer_num,const uchar color_idx) const; //--- Возвращает флаг цветного буфера bool IsColoredBuffer(const int ind_handle,const uint buffer_num) const; //--- Возвращает данные индикатора по хэндлу из указанного буфера по индексу (1) как есть, (2) на указанный символ/таймфрейм double GetData(const int ind_handle,const uint buffer_num,const uint array_num,const uint index); double GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const uint index); //--- Возвращает данные индексов цвета индикатора по хэндлу из указанного буфера по индексу (1) как есть, (2) на указанный символ/таймфрейм double GetColorData(const int ind_handle,const uint buffer_num,const uint index); double GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index); //--- (1) Копирует данные указанного буфера расчётной части указанного по хэндлу индикатора в буфер индикатора с учётом символа/периода графика, //--- (2) Копирует данные указанного цветного буфера расчётной части указанного по хэндлу индикатора в цветной буфер индикатора с учётом символа/периода графика, //--- (2) возвращает количество данных в укакзанном буфере указанного по хэндлу индикатора bool DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &buffer[]); bool DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]); uint DataTotal(const int ind_handle,const uint buffer_num) const; //--- Возвращает (1) описание буфера, (2) состояние данных линии указанного буфера указанного по хэндлу индикатора на указанном баре //--- (3) состояние линии индикатора с учётом символа/периода графика, (4) состояние отношения линии индикатора с указанным уровнем, //--- (5) состояние отношения линии индикатора с указанным уровнем с учётом символа/периода графика, (6) описание категории индикатора string BufferDescription(const int ind_handle,const uint buffer_num); ENUM_LINE_STATE BufferLineState(const int ind_handle,const uint buffer_num,const uint array_num,const int index); ENUM_LINE_STATE BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const uint array_num,const int index); ENUM_LINE_STATE BufferLineStateRelative(const int ind_handle,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE); ENUM_LINE_STATE BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE); string CategoryDescription(const int ind_handle); //--- Устанавливает (1) идентификатор, (2) Digits, (3) пользовательское описание, (4) описание буфера void SetID(const int ind_handle,const int id); void SetDigits(const int ind_handle,const int digits); void SetDescription(const int ind_handle,const string descr); void SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr); //--- Возвращает флаг серийности указанного буфера, (2) синхронизированности исторических данных по символу/периоду bool IsSeries(const int ind_handle,const uint buffer_num,const uint array_num) const; bool IsSynchronized(const int ind_handle) const; //--- ... //--- ... //--- ... //--- Таймер void OnTimer(void) { //--- В цикле по всем индикаторам коллекции int total=this.m_list.Total(); for(int i=0;i<total;i++) { //--- получаем указатель на очередной объект-индикатор //--- и вызываем его таймер CIndMSTF *obj=this.m_list.At(i); if(obj!=NULL) obj.OnTimer(); } } //--- Конструктор/Деструктор CMSTFIndicators(void){ this.m_list.Clear(); } ~CMSTFIndicators(void){;} };
Во всех методах, где требуется указание индекса массива, уже сделаны такие доработки:
//+------------------------------------------------------------------+ //| Возвращает данные индикатора по хэндлу | //| из указанного буфера по индексу как есть | //+------------------------------------------------------------------+ double CMSTFIndicators::GetData(const int ind_handle,const uint buffer_num,const uint array_num,const uint index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Возвращаем данные из указанного буфера индикатора по индексу, переданному в метод return obj.GetData(buffer_num,array_num,index); }
Реализация вновь объявленных методов:
//+------------------------------------------------------------------+ //| Возвращает данные индексов цвета индикатора по хэндлу | //| из указанного буфера по индексу как есть | //+------------------------------------------------------------------+ double CMSTFIndicators::GetColorData(const int ind_handle,const uint buffer_num,const uint index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Возвращаем данные индекса цвета из указанного буфера индикатора по индексу, переданному в метод return obj.GetColorData(buffer_num,index); } //+------------------------------------------------------------------+ //| Возвращает данные индексов цвета индикатора по хэндлу | //| из указанного буфера по индексу на указанный символ/таймфрейм | //+------------------------------------------------------------------+ double CMSTFIndicators::GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return EMPTY_VALUE; } //--- Возвращаем данные индекса цвета из указанного буфера индикатора по индексу, переданному в метод return obj.GetColorDataTo(symbol_to,timeframe_to,buffer_num,index); }
//+------------------------------------------------------------------+ //| Заполняет переданный цветной буфер индикатора данными | //+------------------------------------------------------------------+ bool CMSTFIndicators::DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Заполняем переданный в метод цветной массив-буфер из указанного цветного буфера индикатора return obj.DataToColorBuffer(symbol_to,timeframe_to,buffer_num,array_num,limit,plot_buffer,color_buffer); }
//+------------------------------------------------------------------+ //| Устанавливает цвета линии буфера индикатора | //+------------------------------------------------------------------+ void CMSTFIndicators::SetPlotColorsFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем в указанный рисуемый буфер цвета указанного цветного буфера индикатора uint colors=obj.ColorsTotal(buffer_num); if(colors==0) return; ::PlotIndexSetInteger(plot_index,PLOT_COLOR_INDEXES,colors); for(int i=0;i<(int)colors;i++) ::PlotIndexSetInteger(plot_index,PLOT_LINE_COLOR,i,obj.BufferColorByIndex(buffer_num,(uchar)i)); }
//+------------------------------------------------------------------+ //| Устанавливает инициализирующее значение индекса цвета | //| для указанного буфера указанного по хэндлу индикатора | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferInitColorIndex(const int ind_handle,const uint buffer_num,const uchar index) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем для указанного буфера инициализирующее значение индекса цвета obj.SetBufferInitColorIndex(buffer_num,index); } //+------------------------------------------------------------------+ //| Возвращает инициализирующее значение индекса цвета | //| для указанного буфера указанного по хэндлу индикатора | //+------------------------------------------------------------------+ uchar CMSTFIndicators::BufferInitColorIndex(const int ind_handle,const uint buffer_num) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем инициализирующее значение индекса цвета, установленное для указанного буфера return obj.BufferInitColorIndex(buffer_num); } //+------------------------------------------------------------------+ //| Устанавливает значение цвета по индексу для указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ void CMSTFIndicators::SetBufferColorToIndex(const int ind_handle,const uint buffer_num,const uchar color_idx,const color clr) { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return; } //--- Устанавливаем для указанного буфера значение цвета по индексу obj.SetBufferColorToIndex(buffer_num,color_idx,clr); } //+------------------------------------------------------------------+ //| Возвращает значение цвета по индексу для указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ color CMSTFIndicators::BufferColorByIndex(const int ind_handle,const uint buffer_num,const uchar color_idx) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return WRONG_VALUE; } //--- Возвращаем значение цвета по индексу, установленное для указанного буфера return obj.BufferColorByIndex(buffer_num,color_idx); } //+------------------------------------------------------------------+ //| Возвращает флаг цветности указанного буфера | //| указанного по хэндлу индикатора | //+------------------------------------------------------------------+ bool CMSTFIndicators::IsColoredBuffer(const int ind_handle,const uint buffer_num) const { //--- Получаем указатель на объект-индикатор по хэндлу, переданному в метод CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__); if(obj==NULL) { ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__); return false; } //--- Возвращаем значение флаг цветности, установленный для указанного буфера return obj.IsColoredBuffer(buffer_num); }
В методы добавления объектов-индикаторов в коллекцию внесены доработки, позволяющие сразу установить для созданного индикатора Digits и инициализирующее "пустое значение" буфера данных и буфера цвета:
//+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Accelerator Oscillator | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndAC *ind_obj=new CIndAC(symbol,timeframe); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create AC indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Получаем результат добавления созданного объекта-индикатора в список коллекцию (хэндл индикатора) int handle=this.AddNewIndicator(ind_obj,__FUNCTION__); //--- Если индикатор успешно создан и добавлен в коллекцию, установим параметры его отображения if(handle!=INVALID_HANDLE && ::CheckPointer(ind_obj)!=POINTER_INVALID) { ::IndicatorSetInteger(INDICATOR_DIGITS,ind_obj.Digits()); ind_obj.SetBufferInitValue(0,EMPTY_VALUE); ind_obj.SetBufferInitColorIndex(0,0); } //--- Возвращаем хэндл созданного индикатора, либо INVALID_HANDLE return handle; }
Где необходимо, также устанавливается количество уровней в индикаторе и их значения:
//+------------------------------------------------------------------+ //| Добавляет в коллекцию индикатор Commodity Channel Index | //+------------------------------------------------------------------+ int CMSTFIndicators::AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period=14, const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL) { //--- Создаём новый объект индикатора. При ошибке сообщаем об этом в журнал и возвращаем INVALID_HANDLE CIndCCI *ind_obj=new CIndCCI(symbol,timeframe,ma_period,applied_price); if(ind_obj==NULL) { ::PrintFormat("%s: Error. Failed to create CCI indicator object",__FUNCTION__); return INVALID_HANDLE; } //--- Получаем результат добавления созданного объекта-индикатора в список коллекцию (хэндл индикатора) int handle=this.AddNewIndicator(ind_obj,__FUNCTION__); //--- Если индикатор успешно создан и добавлен в коллекцию, установим параметры его отображения if(handle!=INVALID_HANDLE && ::CheckPointer(ind_obj)!=POINTER_INVALID) { ::IndicatorSetInteger(INDICATOR_LEVELS,2); ::IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-100.0); ::IndicatorSetDouble(INDICATOR_LEVELVALUE,1, 100.0); ::IndicatorSetInteger(INDICATOR_DIGITS,ind_obj.Digits()); ind_obj.SetBufferInitValue(0,EMPTY_VALUE); } //--- Возвращаем хэндл созданного индикатора, либо INVALID_HANDLE return handle; }
Во все аналогичные методы уже внесены такие доработки, и их можно посмотреть в прикрепляемых к статье файлах. Ранее методы просто возвращали результат создания и добавления объекта-индикатора в список коллекции — хэндл созданного индикатора, либо INVALID_HANDLE при неудаче. Сейчас же, если объект индикатора удачно создан и указатель на объект в списке валидный, устанавливаем для индикатора на графике Digits и уровни и устанавливаем в объект созданного индикатора "пустые значения" для его буферов.
Все доработки в библиотеку мультисимвольных мультипериодных индикаторов внесены. Полностью все исправления можно посмотреть в прикреплённом к статье файле IndMSTF.mqh.
Тестирование
В тестовых индикаторах будем использовать класс информационной панели Dashboard.mqh, созданной как раз для тестирования мульти- индикаторов.
Файл класса панели прикреплён к статье и должен располагаться по пути \MQL5\Include\Dashboard\Dashboard.mqh.
Тестовый индикатор, рисующий на графике выбранную в списке мультисимвольную мультипериодную скользящую среднюю, мы уже создавали в прошлой статье. Теперь на основе этого файла сделаем некоторые другие мультисимвольные мультипериодные стандартные индикаторы, в том числе и с цветными буферами. Тестовый индикатор организован таким образом, чтобы на одном графике нарисовать линию данных индикатора с текущего символа и периода графика, и на этом же графике нарисовать вторую линию, но с данными, полученными от выбранных в настройках символе и периоде этого же индикатора. Линия со старшего таймфрейма будет рисоваться более толстой.
Некоторые индикаторы не будут корректно выглядеть при выводе в одно окно данных с разных таймфреймов. Например, некоторые индикаторы объёма, отображающие объём за выбранный период графика. На старшем таймфрейме тиковый объём однозначно больше, чем на младшем, и линия с младшего таймфрейма будет практически прямой на фоне линии со старшего. Поэтому в таких индикаторах будет выводиться только одна линия — с выбранного символа и периода в его настройках.
Индикатор Accumulation/Distribution:
//+------------------------------------------------------------------+ //| TestMSTFAccDistribution.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 1 #property indicator_plots 1 //--- enums //--- plot MSTF A/D #property indicator_label1 "MSTF A/D" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input ENUM_APPLIED_VOLUME InpVolume = VOLUME_TICK; /* Applied Volume */ // Используемый объём для расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferAD[]; //--- global variables int handle_ad; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferAD,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferAD,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_ad=indicators.AddNewAD(InpSymbol,InpTimeframe,InpVolume); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_ad==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_ad,0); //--- Панель //--- Создаём панель int width=220; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ad,0,0,limit,BufferAD)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_ad), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_ad,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ad)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_ad), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ad)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Индикатор Accelerator Oscillator:
//+------------------------------------------------------------------+ //| TestMSTFAcceleratorOscillator.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 4 #property indicator_plots 2 //--- enums //--- plot AC1 #property indicator_label1 "AC1" #property indicator_type1 DRAW_COLOR_HISTOGRAM #property indicator_color1 clrGreen,clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot AC2 #property indicator_label2 "AC2" #property indicator_type2 DRAW_COLOR_HISTOGRAM #property indicator_color2 clrGreen,clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferAC1[]; double BufferClrAC1[]; double BufferAC2[]; double BufferClrAC2[]; //--- global variables int handle_ac1; int handle_ac2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 2 массивы BufferAC1 и BufferAC2 соответственно, //--- а буферам 1 и 3 массивы цвета BufferClrAC1 и BufferClrAC2 SetIndexBuffer(0,BufferAC1,INDICATOR_DATA); SetIndexBuffer(1,BufferClrAC1,INDICATOR_COLOR_INDEX); SetIndexBuffer(2,BufferAC2,INDICATOR_DATA); SetIndexBuffer(3,BufferClrAC2,INDICATOR_COLOR_INDEX); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferAC1,InpAsSeries); ArraySetAsSeries(BufferClrAC1,InpAsSeries); ArraySetAsSeries(BufferAC2,InpAsSeries); ArraySetAsSeries(BufferClrAC2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_ac1=indicators.AddNewAC(NULL,PERIOD_CURRENT); handle_ac2=indicators.AddNewAC(InpSymbol,InpTimeframe); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_ac1==INVALID_HANDLE || handle_ac2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_ac1,0); indicators.SetPlotLabelFromBuffer(1,handle_ac2,0); //--- Панель //--- Создаём панель int width=247; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ac1,0,0,limit,BufferAC1,BufferClrAC1)) return 0; if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ac2,0,0,limit,BufferAC2,BufferClrAC2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_ac1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_ac1,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ac1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ac1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_ac2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ac2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ac1,0,0,index,value2,value21); string ma1=indicators.Name(handle_ac1); string ma2=indicators.Name(handle_ac2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Индикатор Alligator:
//+------------------------------------------------------------------+ //| TestMSTFAlligator.mq5.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_chart_window #property indicator_buffers 6 #property indicator_plots 6 //--- enums //--- plot Jaws1 #property indicator_label1 "Jaws1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_width1 1 //--- plot Teeth1 #property indicator_label2 "Teeth1" #property indicator_type2 DRAW_LINE #property indicator_color2 clrOrangeRed #property indicator_width2 1 //--- plot Lips1 #property indicator_label3 "Lips1" #property indicator_type3 DRAW_LINE #property indicator_color3 clrLime #property indicator_width3 1 //--- plot Jaws2 #property indicator_label4 "Jaws2" #property indicator_type4 DRAW_LINE #property indicator_color4 clrBlue #property indicator_width4 1 //--- plot Teeth2 #property indicator_label5 "Teeth" #property indicator_type5 DRAW_LINE #property indicator_color5 clrRed #property indicator_width5 1 //--- plot Lips2 #property indicator_label6 "Lips" #property indicator_type6 DRAW_LINE #property indicator_color6 clrLimeGreen #property indicator_width6 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ скользящей средней input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм скользящей средней input int InpJawsPeriod = 13; /* Jaws Period */ // Период расчёта челюстей input int InpJawsShift = 8; /* Jaws Shift */ // Сдвиг челюстей input int InpTeethPeriod = 8; /* Teeth Period */ // Период расчёта зубов input int InpTeethShift = 5; /* Teeth Shift */ // Сдвиг зубов input int InpLipsPeriod = 5; /* Lips Period */ // Период расчёта губ input int InpLipsShift = 3; /* Lips Shift */ // Сдвиг губ input ENUM_MA_METHOD InpMethod = MODE_SMMA; /* Method */ // Метод расчёта input ENUM_APPLIED_PRICE InpPrice = PRICE_MEDIAN; /* Applied Price */ // Используемая цена для расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferJaws1[]; double BufferTeeth1[]; double BufferLips1[]; double BufferJaws2[]; double BufferTeeth2[]; double BufferLips2[]; //--- global variables int handle_alligator1; int handle_alligator2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0, 1 и 2 массивы BufferBandsUp1, BufferBandsDn1 и BufferBandsMd1 соответственно SetIndexBuffer(0,BufferJaws1,INDICATOR_DATA); SetIndexBuffer(1,BufferTeeth1,INDICATOR_DATA); SetIndexBuffer(2,BufferLips1,INDICATOR_DATA); //--- Назначаем рисуемым буферам 3, 4 и 5 массивы BufferBandsUp2, BufferBandsDn2 и BufferBandsMd2 соответственно SetIndexBuffer(3,BufferJaws2,INDICATOR_DATA); SetIndexBuffer(4,BufferTeeth2,INDICATOR_DATA); SetIndexBuffer(5,BufferLips2,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2); //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferJaws1,InpAsSeries); ArraySetAsSeries(BufferTeeth1,InpAsSeries); ArraySetAsSeries(BufferLips1,InpAsSeries); ArraySetAsSeries(BufferJaws2,InpAsSeries); ArraySetAsSeries(BufferTeeth2,InpAsSeries); ArraySetAsSeries(BufferLips2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_alligator1=indicators.AddNewAlligator(NULL,PERIOD_CURRENT,InpJawsPeriod,InpJawsShift,InpTeethPeriod,InpTeethShift,InpLipsPeriod,InpLipsShift,InpMethod,InpPrice); handle_alligator2=indicators.AddNewAlligator(InpSymbol,InpTimeframe,InpJawsPeriod,InpJawsShift,InpTeethPeriod,InpTeethShift,InpLipsPeriod,InpLipsShift,InpMethod,InpPrice); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_alligator1==INVALID_HANDLE || handle_alligator2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_alligator1,0); indicators.SetPlotLabelFromBuffer(1,handle_alligator1,1); indicators.SetPlotLabelFromBuffer(2,handle_alligator1,2); indicators.SetPlotLabelFromBuffer(3,handle_alligator2,0); indicators.SetPlotLabelFromBuffer(4,handle_alligator2,1); indicators.SetPlotLabelFromBuffer(5,handle_alligator2,2); //--- Устанавливаем смещения линиям индикатора indicators.SetPlotShift(0,InpJawsShift); indicators.SetPlotShift(1,InpTeethShift); indicators.SetPlotShift(2,InpLipsShift); indicators.SetPlotShift(3,InpJawsShift); indicators.SetPlotShift(4,InpTeethShift); indicators.SetPlotShift(5,InpLipsShift); //--- Панель //--- Создаём панель int width=321; panel=new CDashboard(1,20,20,width,264); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,0,0,limit,BufferJaws1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,1,0,limit,BufferTeeth1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,2,0,limit,BufferLips1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,0,0,limit,BufferJaws2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,1,0,limit,BufferTeeth2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,2,0,limit,BufferLips2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_alligator1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_alligator1,0,0,index+InpJawsShift); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_alligator1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,150); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_alligator1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,150); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_alligator2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_alligator2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,150); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,150); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_alligator1,0,0,index,value2,value21); string ma1=indicators.Name(handle_alligator1); string ma2=indicators.Name(handle_alligator2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,150); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Индикатор Average Directional Movement Index:
//+------------------------------------------------------------------+ //| TestMSTFAverageDirectionalMovementIndex.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 6 #property indicator_plots 6 //--- enums //--- plot ADX1 #property indicator_label1 "ADX1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot +DI1 #property indicator_label2 "+DI1" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGreen #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot -DI1 #property indicator_label3 "-DI1" #property indicator_type3 DRAW_LINE #property indicator_color3 clrRed #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot ADX2 #property indicator_label4 "ADX2" #property indicator_type4 DRAW_LINE #property indicator_color4 clrBlue #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot +DI2 #property indicator_label5 "+DI2" #property indicator_type5 DRAW_LINE #property indicator_color5 clrGreen #property indicator_style5 STYLE_SOLID #property indicator_width5 1 //--- plot -DI2 #property indicator_label6 "-DI2" #property indicator_type6 DRAW_LINE #property indicator_color6 clrRed #property indicator_style6 STYLE_SOLID #property indicator_width6 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input int InpPeriod = 14; /* Period */ // Период расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferADX1[]; double BufferDIPlus1[]; double BufferDIMinus1[]; double BufferADX2[]; double BufferDIPlus2[]; double BufferDIMinus2[]; //--- global variables int handle_adx1; int handle_adx2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferADX1,INDICATOR_DATA); SetIndexBuffer(1,BufferDIPlus1,INDICATOR_DATA); SetIndexBuffer(2,BufferDIMinus1,INDICATOR_DATA); SetIndexBuffer(3,BufferADX2,INDICATOR_DATA); SetIndexBuffer(4,BufferDIPlus2,INDICATOR_DATA); SetIndexBuffer(5,BufferDIMinus2,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferADX1,InpAsSeries); ArraySetAsSeries(BufferDIPlus1,InpAsSeries); ArraySetAsSeries(BufferDIMinus1,InpAsSeries); ArraySetAsSeries(BufferADX2,InpAsSeries); ArraySetAsSeries(BufferDIPlus2,InpAsSeries); ArraySetAsSeries(BufferDIMinus2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_adx1=indicators.AddNewADX(NULL,PERIOD_CURRENT,InpPeriod); handle_adx2=indicators.AddNewADX(InpSymbol,InpTimeframe,InpPeriod); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_adx1==INVALID_HANDLE || handle_adx2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_adx1,0); indicators.SetPlotLabelFromBuffer(1,handle_adx1,1); indicators.SetPlotLabelFromBuffer(2,handle_adx1,2); indicators.SetPlotLabelFromBuffer(3,handle_adx2,0); indicators.SetPlotLabelFromBuffer(4,handle_adx2,1); indicators.SetPlotLabelFromBuffer(5,handle_adx2,2); //--- Панель //--- Создаём панель int width=301; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,0,0,limit,BufferADX1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,1,0,limit,BufferDIPlus1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,2,0,limit,BufferDIMinus1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,0,0,limit,BufferADX2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,1,0,limit,BufferDIPlus2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,2,0,limit,BufferDIMinus2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_adx1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_adx1,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_adx1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adx1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_adx2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_adx2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_adx1,0,0,index,value2,value21); string ma1=indicators.Name(handle_adx1); string ma2=indicators.Name(handle_adx2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Индикатор Average Directional Movement Index Wilder:
//+------------------------------------------------------------------+ //| TestMSTFAverageDirectionalMovementIndexWilder.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 6 #property indicator_plots 6 //--- enums //--- plot ADXW1 #property indicator_label1 "ADXW1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot +DI1 #property indicator_label2 "+DI1" #property indicator_type2 DRAW_LINE #property indicator_color2 clrGreen #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot -DI1 #property indicator_label3 "-DI1" #property indicator_type3 DRAW_LINE #property indicator_color3 clrRed #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot ADXW2 #property indicator_label4 "ADXW2" #property indicator_type4 DRAW_LINE #property indicator_color4 clrBlue #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot +DI2 #property indicator_label5 "+DI2" #property indicator_type5 DRAW_LINE #property indicator_color5 clrGreen #property indicator_style5 STYLE_SOLID #property indicator_width5 1 //--- plot -DI2 #property indicator_label6 "-DI2" #property indicator_type6 DRAW_LINE #property indicator_color6 clrRed #property indicator_style6 STYLE_SOLID #property indicator_width6 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input int InpPeriod = 14; /* Period */ // Период расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferADXW1[]; double BufferDIPlus1[]; double BufferDIMinus1[]; double BufferADXW2[]; double BufferDIPlus2[]; double BufferDIMinus2[]; //--- global variables int handle_adxw1; int handle_adxw2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferADXW1,INDICATOR_DATA); SetIndexBuffer(1,BufferDIPlus1,INDICATOR_DATA); SetIndexBuffer(2,BufferDIMinus1,INDICATOR_DATA); SetIndexBuffer(3,BufferADXW2,INDICATOR_DATA); SetIndexBuffer(4,BufferDIPlus2,INDICATOR_DATA); SetIndexBuffer(5,BufferDIMinus2,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2); PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferADXW1,InpAsSeries); ArraySetAsSeries(BufferDIPlus1,InpAsSeries); ArraySetAsSeries(BufferDIMinus1,InpAsSeries); ArraySetAsSeries(BufferADXW2,InpAsSeries); ArraySetAsSeries(BufferDIPlus2,InpAsSeries); ArraySetAsSeries(BufferDIMinus2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_adxw1=indicators.AddNewADX(NULL,PERIOD_CURRENT,InpPeriod); handle_adxw2=indicators.AddNewADX(InpSymbol,InpTimeframe,InpPeriod); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_adxw1==INVALID_HANDLE || handle_adxw2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_adxw1,0); indicators.SetPlotLabelFromBuffer(1,handle_adxw1,1); indicators.SetPlotLabelFromBuffer(2,handle_adxw1,2); indicators.SetPlotLabelFromBuffer(3,handle_adxw2,0); indicators.SetPlotLabelFromBuffer(4,handle_adxw2,1); indicators.SetPlotLabelFromBuffer(5,handle_adxw2,2); //--- Панель //--- Создаём панель int width=301; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,0,0,limit,BufferADXW1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,1,0,limit,BufferDIPlus1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,2,0,limit,BufferDIMinus1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,0,0,limit,BufferADXW2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,1,0,limit,BufferDIPlus2)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,2,0,limit,BufferDIMinus2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_adxw1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_adxw1,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_adxw1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adxw1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_adxw2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_adxw2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_adxw1,0,0,index,value2,value21); string ma1=indicators.Name(handle_adxw1); string ma2=indicators.Name(handle_adxw2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Индикатор Average True Range:
//+------------------------------------------------------------------+ //| TestMSTFAverageTrueRange.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 //--- enums //--- plot ATR1 #property indicator_label1 "ATR1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot ATR2 #property indicator_label2 "ATR2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input int InpPeriod = 14; /* Period */ // Период расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferATR1[]; double BufferATR2[]; //--- global variables int handle_atr1; int handle_atr2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferATR1,INDICATOR_DATA); SetIndexBuffer(1,BufferATR2,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferATR1,InpAsSeries); ArraySetAsSeries(BufferATR2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_atr1=indicators.AddNewATR(NULL,PERIOD_CURRENT,InpPeriod); handle_atr2=indicators.AddNewATR(InpSymbol,InpTimeframe,InpPeriod); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_atr1==INVALID_HANDLE || handle_atr2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_atr1,0); indicators.SetPlotLabelFromBuffer(1,handle_atr2,0); //--- Панель //--- Создаём панель int width=237; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_atr1,0,0,limit,BufferATR1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_atr2,0,0,limit,BufferATR2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_atr1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_atr1,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_atr1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_atr1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_atr2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_atr2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_atr1,0,0,index,value2,value21); string ma1=indicators.Name(handle_atr1); string ma2=indicators.Name(handle_atr2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+
После компиляции и запуска индикатора на графике М1 и выбранном периоде графика для расчёта М5, видим:
Иногда, для более быстрой прорисовки индикатора можно переключить таймфрейм графика.
Индикатор Awesome Oscillator:
//+------------------------------------------------------------------+ //| TestMSTFAwesomeOscillator.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 4 #property indicator_plots 2 //--- enums //--- plot AC1 #property indicator_label1 "AO1" #property indicator_type1 DRAW_COLOR_HISTOGRAM #property indicator_color1 clrGreen,clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot AC2 #property indicator_label2 "AO2" #property indicator_type2 DRAW_COLOR_HISTOGRAM #property indicator_color2 clrGreen,clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include <IndMSTF\IndMSTF.mqh> #include <Dashboard\Dashboard.mqh> //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferAO1[]; double BufferClrAO1[]; double BufferAO2[]; double BufferClrAO2[]