ArrayMaximum

Ищет максимальный элемент в первом измерении многомерного числового массива.

int  ArrayMaximum(
   const void&   array[],             // массив для поиска
   int           start=0,             // с какого индекса начинаем поиск
   int           count=WHOLE_ARRAY    // количество проверяемых
   );

Параметры

array[]

[in]  Числовой массив, в котором производится поиск.

start=0

[in]  Начальный индекс для поиска.

count=WHOLE_ARRAY

[in]  Количество элементов для поиска. По умолчанию, ищет во всем массиве (count=WHOLE_ARRAY).

Возвращаемое значение

Функция возвращает индекс найденного элемента с учетом серийности массива. В случае неудачи функция возвращает -1.

Примечание

Поиск максимального элемента производится с учетом значения флага AS_SERIES.

Функции ArrayMaximum и ArrayMinimum принимают в качестве параметра массив любой размерности, при этом поиск происходит только по первому (нулевому) измерению.

Пример:

#property description "Индикатор отображает свечи со старшего таймфрейма на текущем."
//--- настройки индикатора
#property indicator_chart_window
#property indicator_buffers 16
#property indicator_plots   8
//---- plot 1
#property indicator_label1  "BearBody"
#property indicator_color1  clrSeaGreen,clrSeaGreen
//---- plot 2
#property indicator_label2  "BearBodyEnd"
#property indicator_color2  clrSeaGreen,clrSeaGreen
//---- plot 3
#property indicator_label3  "BearShadow"
#property indicator_color3  clrSalmon,clrSalmon
//---- plot 4
#property indicator_label4  "BearShadowEnd"
#property indicator_color4  clrSalmon,clrSalmon
//---- plot 5
#property indicator_label5  "BullBody"
#property indicator_color5  clrOlive,clrOlive
//---- plot 6
#property indicator_label6  "BullBodyEnd"
#property indicator_color6  clrOlive,clrOlive
//---- plot 7
#property indicator_label7  "BullShadow"
#property indicator_color7  clrSkyBlue,clrSkyBlue
//---- plot 8
#property indicator_label8  "BullShadowEnd"
#property indicator_color8  clrSkyBlue,clrSkyBlue
//--- предопределенная константа
#define INDICATOR_EMPTY_VALUE 0.0
//--- входные параметры
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4;              // Таймфрейм для расчета индикатора
input datetime        InpDateStart=D'2013.01.01 00:00'; // Дата начала анализа
//--- индикаторные буферы для медвежьих свечей
double   ExtBearBodyFirst[];
double   ExtBearBodySecond[];
double   ExtBearBodyEndFirst[];
double   ExtBearBodyEndSecond[];
double   ExtBearShadowFirst[];
double   ExtBearShadowSecond[];
double   ExtBearShadowEndFirst[];
double   ExtBearShadowEndSecond[];
//--- индикаторные буферы для бычьих свечей
double   ExtBullBodyFirst[];
double   ExtBullBodySecond[];
double   ExtBullBodyEndFirst[];
double   ExtBullBodyEndSecond[];
double   ExtBullShadowFirst[];
double   ExtBullShadowSecond[];
double   ExtBullShadowEndFirst[];
double   ExtBullShadowEndSecond[];
//--- глобальные переменные
datetime ExtTimeBuff[];      // буфер для времени с высшего таймфрейма
int      ExtSize=0;          // размер буфера времени
int      ExtCount=0;         // индекс внутри буфера времени
int      ExtStartPos=0;      // начальная позиция для расчета индикатора
bool     ExtStartFlag=true;  // вспомогательный флаг для получения начальной позиции
datetime ExtCurrentTime[1];  // последнее время формирования бара со старшего таймфрейма
datetime ExtLastTime;        // последнее время со старшего таймфрейма, для которого произведен расчет
bool     ExtBearFlag=true;   // флаг для определения порядка записи данных в медвежьи индикаторные буферы
bool     ExtBullFlag=true;   // флаг для определения порядка записи данных в бычьи индикаторные буферы
int      ExtIndexMax=0;      // индекс максимального элемента в массиве
int      ExtIndexMin=0;      // индекс минимального элемента в массиве
int      ExtDirectionFlag=0; // направление движения цены у текущей свечи
//--- отступ между ценой открытия и закрытия свечи для правильной отрисовки
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| Закрашивание основной части свечи                                |
//+------------------------------------------------------------------+
void FillCandleMain(const double &open[],const double &close[],
                    const double &high[],const double &low[],
                    const int start,const int last,const int fill_index,
                    int &index_max,int &index_min)
  {
//--- найдем индексы максимального и минимального элементов в массивах
   index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // максимум в High
   index_min=ArrayMinimum(low,ExtStartPos,last-start+1);  // минимум в Low
//--- определим сколько баров с текущего таймфрейма будем закрашивать
   int count=fill_index-start+1;
//--- если цена закрытия на первом баре больше цены закрытия на последнем - свеча медвежья
   if(open[start]>close[last])
     {
      //--- если до этого свеча была бычьей, то очищаем значения бычьих индикаторных буферов
      if(ExtDirectionFlag!=-1)
         ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
      //--- медвежья свеча
      ExtDirectionFlag=-1;
      //--- формируем свечку
      FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
                     close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
      //--- выход из функции
      return;
     }
//--- если цена закрытия на первом баре меньше цены закрытия на последнем - свеча бычья
   if(open[start]<close[last])
     {
      //--- если до этого свеча была медвежьей, то очищаем значения медвежьих индикаторных буферов
      if(ExtDirectionFlag!=1)
         ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
      //--- бычья свеча
      ExtDirectionFlag=1;
      //--- формируем свечку
      FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
                     open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
      //--- выход из функции             
      return;
     }
//--- если попали в эту часть функции, то значит цена открытия на первом баре равняется
//--- цене закрытия на последнем баре; будем считать такую свечу медвежьей
//--- если до этого свеча была бычьей, то очищаем значения бычьих индикаторных буферов
   if(ExtDirectionFlag!=-1)
      ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- медвежья свеча
   ExtDirectionFlag=-1;
//--- если цены закрытия и цены открытия равны, то используем сдвиг для корректного отображения
   if(high[index_max]!=low[index_min])
      FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
                     open[start]-ExtEmptyBodySize,high[index_max],low[index_min],start,count,ExtBearFlag);
   else
      FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,
                     open[start],open[start]-ExtEmptyBodySize,high[index_max],
                     high[index_max]-ExtEmptyBodySize,start,count,ExtBearFlag);
  }
//+------------------------------------------------------------------+
//| Закрашивание конца свечи                                         |
//+------------------------------------------------------------------+
void FillCandleEnd(const double &open[],const double &close[],
                   const double &high[],const double &low[],
                   const int start,const int last,const int fill_index,
                   const int index_max,const int index_min)
  {
//--- если всего один бар, то не рисуем
   if(last-start==0)
      return;
//--- если цена закрытия на первом баре больше цены закрытия на последнем - свеча медвежья
   if(open[start]>close[last])
     {
      //--- формируем конец свечи
      FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
                    open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
      //--- выход из функции
      return;
     }
//--- если цена закрытия на первом баре меньше цены закрытия на последнем - свеча бычья
   if(open[start]<close[last])
     {
      //--- формируем конец свечи
      FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
                    close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
      //--- выход из функции
      return;
     }
//--- если попали в эту часть функции, то значит цена открытия на первом баре равняется
//--- цене закрытия на последнем баре; будем считать такую свечу медвежьей
//--- формируем конец свечи
   if(high[index_max]!=low[index_min])
      FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
                    open[start]-ExtEmptyBodySize,high[index_max],low[index_min],fill_index,ExtBearFlag);
   else
      FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
                    open[start]-ExtEmptyBodySize,high[index_max],high[index_max]-ExtEmptyBodySize,fill_index,ExtBearFlag);
  }
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- проверка периода индикатора
   if(!CheckPeriod((int)Period(),(int)InpPeriod))
      return(INIT_PARAMETERS_INCORRECT);
//--- отображение ценовых данных на переднем плане
   ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- привязка индикаторных буферов
   SetIndexBuffer(0,ExtBearBodyFirst);
   SetIndexBuffer(1,ExtBearBodySecond);
   SetIndexBuffer(2,ExtBearBodyEndFirst);
   SetIndexBuffer(3,ExtBearBodyEndSecond);
   SetIndexBuffer(4,ExtBearShadowFirst);
   SetIndexBuffer(5,ExtBearShadowSecond);
   SetIndexBuffer(6,ExtBearShadowEndFirst);
   SetIndexBuffer(7,ExtBearShadowEndSecond);
   SetIndexBuffer(8,ExtBullBodyFirst);
   SetIndexBuffer(9,ExtBullBodySecond);
   SetIndexBuffer(10,ExtBullBodyEndFirst);
   SetIndexBuffer(11,ExtBullBodyEndSecond);
   SetIndexBuffer(12,ExtBullShadowFirst);
   SetIndexBuffer(13,ExtBullShadowSecond);
   SetIndexBuffer(14,ExtBullShadowEndFirst);
   SetIndexBuffer(15,ExtBullShadowEndSecond);
//--- зададим некоторые значения свойств для построения индикатора
   for(int i=0;i<8;i++)
     {
      PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // тип графического построения
      PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // стиль линии отрисовки
      PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1);           // толщина линии отрисовки
     }
//---
   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[])
  {
//--- если еще нет рассчитанных баров
   if(prev_calculated==0)
     {
      //--- получим время появления баров со старшего таймфрейма
      if(!GetTimeData())
         return(0);
     }
//--- установим прямое направление индексации
   ArraySetAsSeries(time,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(open,false);
   ArraySetAsSeries(close,false);
//--- переменная начала для расчета баров
   int start=prev_calculated;
//--- если бар формируется, то пересчитываем значение индикатора на нем
   if(start!=0 && start==rates_total)
      start--;
//--- цикл расчета значений индикатора
   for(int i=start;i<rates_total;i++)
     {
      //--- заполняем i-ые элементы индикаторных буферов пустыми значениями
      FillIndicatorBuffers(i);
      //--- проводим вычисление для баров начиная с даты InpDateStart
      if(time[i]>=InpDateStart)
        {
         //--- в первый раз определим позицию с которой начнем отображать значения
         if(ExtStartFlag)
           {
            //--- запомним номер начального бара
            ExtStartPos=i;
            //--- определим первую дату со старшего таймфрейма, которая больше time[i]
            while(time[i]>=ExtTimeBuff[ExtCount])
               if(ExtCount<ExtSize-1)
                  ExtCount++;
            //--- изменим значение флага, чтобы больше не попадать в этот блок
            ExtStartFlag=false;
           }
         //--- проверка, есть ли еще в массиве элементы
         if(ExtCount<ExtSize)
           {
            //--- ждем, когда значение времени с текущего таймфрейма достигнет значения со старшего таймфрейма
            if(time[i]>=ExtTimeBuff[ExtCount])
              {
               //--- рисуем главную часть свечи (без закрашивания между последним и предпоследним баром)
               FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
               //--- закрашиваем конец свечи (область между последним и предпоследним баром)
               FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
               //--- сдвигаем начальную позицию для рисования следующей свечи
               ExtStartPos=i;
               //--- увеличиваем счетчик массива
               ExtCount++;
              }
            else
               continue;
           }
         else
           {
            //--- сбрасываем значения ошибки
            ResetLastError();
            //--- получаем последнюю дату со старшего таймфрейма
            if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
              {
               Print("Ошибка копирования данных, код = ",GetLastError());
               return(0);
              }
            //--- если новая дата больше, то значит заканчиваем формирование свечки
            if(ExtCurrentTime[0]>ExtLastTime)
              {
               //--- очистим область между последним и предпоследним баром в главных индикаторных буферах
               ClearEndOfBodyMain(i-1);
               //--- закрасим эту область с помощью вспомогательных индикаторных буферов
               FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
               //--- сдвигаем начальную позицию для рисования следующей свечи
               ExtStartPos=i;
               //--- сбросим флаг направления цены
               ExtDirectionFlag=0;
               //--- запомним новую последнюю дату
               ExtLastTime=ExtCurrentTime[0];
              }
            else
              {
               //--- формируем свечку
               FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
              }
           }
        }
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Проверка введенного периода индикатора на корректность           |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
  {
//--- период индикатора должен быть больше таймфрейма, на котором он отображается
   if(current_period>=high_period)
     {
      Print("Ошибка! Значение периода индикатора должно быть больше значения текущего таймфрейма!");
      return(false);
     }
//--- если период индикатора - одна неделя или месяц, то период корректен
   if(high_period>32768)
      return(true);
//--- приведем значения периодов к минутам
   if(high_period>30)
      high_period=(high_period-16384)*60;
   if(current_period>30)
      current_period=(current_period-16384)*60;
//--- период индикатора должен быть кратен таймфрейму, на котором он отображается
   if(high_period%current_period!=0)
     {
      Print("Ошибка! Значение периода индикатора должно быть кратным значению текущего таймфрейма!");
      return(false);
     }
//--- период индикатора должен превышать значение таймфрейма, на котором он отображается в 3 или более раз
   if(high_period/current_period<3)
     {
      Print("Ошибка! Значение периода индикатора должно превышать значение текущего таймфрейма в 3 или более раз!");
      return(false);
     }
//--- период индикатора корректен для текущего таймфрейма
   return(true);
  }
//+------------------------------------------------------------------+
//| Получение данных времени со старшего таймфрейма                  |
//+------------------------------------------------------------------+
bool GetTimeData(void)
  {
//--- сброс значения ошибки
   ResetLastError();
//--- скопируем все данные на текущее время
   if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
     {
      //--- получим код ошибки
      int code=GetLastError();
      //--- распечатаем текст ошибки
      PrintFormat("Ошибка копирования данных! %s",code==4401
                  ? "История еще подгружается!"
                  : "Код = "+IntegerToString(code));
      //--- вернем false для повторной попытки загрузки данных
      return(false);
     }
//--- получим размер массива
   ExtSize=ArraySize(ExtTimeBuff);
//--- установим индекс цикла для массива равным нулю
   ExtCount=0;
//--- установим позицию текущей свечи на данном таймфрейме равной нулю
   ExtStartPos=0;
   ExtStartFlag=true;
//--- запомним последнее значение времени со старшего таймфрейма
   ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- успешное выполнение
   return(true);
  }
//+------------------------------------------------------------------+
//| Функция формирует основную часть свечи. В зависимости от значения|
//| флага, функция определяет, какие данные в какие массивы должны   |
//| записываться для корректного отображения.                        |
//+------------------------------------------------------------------+
void FormCandleMain(double &body_fst[],double &body_snd[],
                    double &shadow_fst[],double &shadow_snd[],
                    const double fst_value,const double snd_value,
                    const double fst_extremum,const double snd_extremum,
                    const int start,const int count,const bool flag)
  {
//--- проверяем значение флага
   if(flag)
     {
      //--- формируем тело свечи
      FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
      //--- формируем тень свечи
      FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
     }
   else
     {
      //--- формируем тело свечи
      FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
      //--- формируем тень свечи
      FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
     }
  }
//+------------------------------------------------------------------+
//| Функция формирует конец свечи. В зависимости от значения флага,  |
//| функция определяет, какие данные в какие массивы должны          |
//| записываться для корректного отображения.                        |
//+------------------------------------------------------------------+
void FormCandleEnd(double &body_fst[],double &body_snd[],
                   double &shadow_fst[],double &shadow_snd[],
                   const double fst_value,const double snd_value,
                   const double fst_extremum,const double snd_extremum,
                   const int end,bool &flag)
  {
//--- проверяем значение флага
   if(flag)
     {
      //--- формируем конец тела свечи
      FormEnd(body_fst,body_snd,fst_value,snd_value,end);
      //--- формируем конец тени свечи
      FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
      //--- меняем значение флага на противоположное
      flag=false;
     }
   else
     {
      //--- формируем конец тела свечи
      FormEnd(body_fst,body_snd,snd_value,fst_value,end);
      //--- формируем конец тени свечи
      FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
      //--- меняем значение флага на противоположное
      flag=true;
     }
  }
//+------------------------------------------------------------------+
//| Очистка конца свечи (область между последним и предпоследним     |
//| баром)                                                           |
//+------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
  {
   ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
   ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
  }
//+------------------------------------------------------------------+
//| Очистка свечи                                                    |
//+------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
                 double &shadow_snd[],const int start,const int count)
  {
//--- проверка
   if(count!=0)
     {
      //--- заполняем индикаторные буферы пустым значением
      ArrayFill(body_fst,start,count,INDICATOR_EMPTY_VALUE);
      ArrayFill(body_snd,start,count,INDICATOR_EMPTY_VALUE);
      ArrayFill(shadow_fst,start,count,INDICATOR_EMPTY_VALUE);
      ArrayFill(shadow_snd,start,count,INDICATOR_EMPTY_VALUE);
     }
  }
//+------------------------------------------------------------------+
//| Формирование основной части свечи                                |
//+------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
              const double snd_value,const int start,const int count)
  {
//--- проверка
   if(count!=0)
     {
      //--- заполняем индикаторные буферы значениями
      ArrayFill(fst,start,count,fst_value);
      ArrayFill(snd,start,count,snd_value);
     }
  }
//+------------------------------------------------------------------+
//| Формирование конца свечи                                         |
//+------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
             const double snd_value,const int last)
  {
//--- заполняем индикаторные буферы значениями
   ArrayFill(fst,last-1,2,fst_value);
   ArrayFill(snd,last-1,2,snd_value);
  }
//+------------------------------------------------------------------+
//| Заполнение i-ого элемента индикаторных буферов пустыми значениями|
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
  {
//--- устанавливаем пустое значение в ячейку индикаторных буферов
   ExtBearBodyFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBearBodySecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBearShadowFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBearShadowSecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBearBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBearBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBearShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBearShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBullBodyFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBullBodySecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBullShadowFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBullShadowSecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBullBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBullBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
   ExtBullShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
   ExtBullShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
  }