//+------------------------------------------------------------------+
 //|                                                  Demo_iForce.mq5 |
 //|                        Copyright 2011, MetaQuotes Software Corp. |
 //|                                             https://www.mql5.com |
 //+------------------------------------------------------------------+
 #property copyright "Copyright 2000-2024, MetaQuotes Ltd."
 #property link      "https://www.mql5.com"
 #property version   "1.00"
 #property description "Индикатор демонстрирует как нужно получать данные"
 #property description "индикаторных буферов для технического индикатора iForce."
 #property description "Символ и таймфрейм, на котором рассчитывается индикатор,"
 #property description "задаются параметрами symbol и period."
 #property description "Способ создания хэндла задается параметром 'type' (тип функции)."
  
 #property indicator_separate_window
 #property indicator_buffers 1
 #property indicator_plots   1
 //--- построение iForce
 #property indicator_label1  "iForce"
 #property indicator_type1   DRAW_LINE
 #property indicator_color1  clrLightSeaGreen
 #property indicator_style1  STYLE_SOLID
 #property indicator_width1  1
 //+------------------------------------------------------------------+
 //| Перечисление способов создания хэндла                            |
 //+------------------------------------------------------------------+
 enum Creation
   {
    Call_iForce,            // использовать iForce
    Call_IndicatorCreate    // использовать IndicatorCreate
   };
 //--- входные параметры
 input Creation             type=Call_iForce;             // тип функции 
 input int                  ma_period=13;                 // период усреднения
 input ENUM_MA_METHOD       ma_method=MODE_SMA;           // тип сглаживания
 input ENUM_APPLIED_VOLUME  applied_volume=VOLUME_TICK;   // тип объема
 input string               symbol=" ";                   // символ 
 input ENUM_TIMEFRAMES      period=PERIOD_CURRENT;        // таймфрейм
 //--- индикаторный буфер
 double         iForceBuffer[];
 //--- переменная для хранения хэндла индикатора iForce
 int    handle;
 //--- переменная для хранения 
 string name=symbol;
 //--- имя индикатора на графике
 string short_name;
 //--- будем хранить количество значений в индикаторе Force
 int    bars_calculated=0;
 //+------------------------------------------------------------------+
 //| Custom indicator initialization function                         |
 //+------------------------------------------------------------------+
 int OnInit()
   {
 //--- привязка массива к индикаторному буферу
    SetIndexBuffer(0,iForceBuffer,INDICATOR_DATA);
 //--- определимся с символом, на котором строится индикатор
    name=symbol;
 //--- удалим пробелы слева и справа
    StringTrimRight(name);
    StringTrimLeft(name);
 //--- если после этого длина строки name нулевая
    if(StringLen(name)==0)
      {
       //--- возьмем символ с графика, на котором запущен индикатор
       name=_Symbol;
      }
 //--- создадим хэндл индикатора
    if(type==Call_iForce)
       handle=iForce(name,period,ma_period,ma_method,applied_volume);
    else
      {
       //--- заполним структуру значениями параметров индикатора
       MqlParam pars[3];
       //--- период средней
       pars[0].type=TYPE_INT;
       pars[0].integer_value=ma_period;
       //--- тип сглаживания
       pars[1].type=TYPE_INT;
       pars[1].integer_value=ma_method;
       //--- тип объема
       pars[2].type=TYPE_INT;
       pars[2].integer_value=applied_volume;
       //--- тип цены
       handle=IndicatorCreate(name,period,IND_FORCE,3,pars);
      }
 //--- если не удалось создать хэндл
    if(handle==INVALID_HANDLE)
      {
       //--- сообщим о неудаче и выведем номер ошибки
       PrintFormat("Не удалось создать хэндл индикатора iForce для пары %s/%s, код ошибки %d",
                   name,
                   EnumToString(period),
                   GetLastError());
       //--- работа индикатора завершается досрочно
       return(INIT_FAILED);
      }
 //--- покажем на какой паре символ/таймфрейм рассчитан индикатор Force
    short_name=StringFormat("iForce(%s/%s, %d, %s, %s)",name,EnumToString(period),
                            ma_period,EnumToString(ma_method),EnumToString(applied_volume));
    IndicatorSetString(INDICATOR_SHORTNAME,short_name);
 //--- нормальное выполнение инициализации индикатора  
    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[])
   {
 //--- количество копируемых значений из индикатора iForce
    int values_to_copy;
 //--- узнаем количество рассчитанных значений в индикаторе
    int calculated=BarsCalculated(handle);
    if(calculated<=0)
      {
       PrintFormat("BarsCalculated() вернул %d, код ошибки %d",calculated,GetLastError());
       return(0);
      }
 //--- если это первый запуск вычислений нашего индикатора или изменилось количество значений в индикаторе iForce
 //--- или если необходимо рассчитать индикатор для двух или более баров (значит что-то изменилось в истории)
    if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1)
      {
       //--- если массив iForceBuffer больше, чем значений в индикаторе iForce на паре symbol/period, то копируем не все 
       //--- в противном случае копировать будем меньше, чем размер индикаторных буферов
       if(calculated>rates_total) values_to_copy=rates_total;
       else                       values_to_copy=calculated;
      }
    else
      {
       //--- значит наш индикатор рассчитывается не в первый раз и с момента последнего вызова OnCalculate())
       //--- для расчета добавилось не более одного бара
       values_to_copy=(rates_total-prev_calculated)+1;
      }
 //--- заполняем массив iForceBuffer  значениями из индикатора Force
 //--- если FillArrayFromBuffer вернула false, значит данные не готовы - завершаем работу
    if(!FillArrayFromBuffer(iForceBuffer,handle,values_to_copy)) return(0);
 //--- сформируем сообщение
    string comm=StringFormat("%s ==>  Обновлено значений в индикаторе %s: %d",
                             TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS),
                             short_name,
                             values_to_copy);
 //--- выведем на график служебное сообщение
    Comment(comm);
 //--- запомним количество значений в индикаторе Force
    bars_calculated=calculated;
 //--- вернем значение prev_calculated для следующего вызова
    return(rates_total);
   }
 //+------------------------------------------------------------------+
 //| Заполняем индикаторный буфер из индикатора iForce                |
 //+------------------------------------------------------------------+
 bool FillArrayFromBuffer(double &values[],  // индикаторный буфер значений Force Index
                          int ind_handle,    // хэндл индикатора iForce
                          int amount         // количество копируемых значений
                          )
   {
 //--- сбросим код ошибки
    ResetLastError();
 //--- заполняем часть массива iForceBuffer значениями из индикаторного буфера под индексом 0
    if(CopyBuffer(ind_handle,0,0,amount,values)<0)
      {
       //--- если копирование не удалось, сообщим код ошибки
       PrintFormat("Не удалось скопировать данные из индикатора iForce, код ошибки %d",GetLastError());
       //--- завершим с нулевым результатом - это означает, что индикатор будет считаться нерассчитанным
       return(false);
      }
 //--- все получилось
    return(true);
   }
 //+------------------------------------------------------------------+
 //| Indicator deinitialization function                              |
 //+------------------------------------------------------------------+
 void OnDeinit(const int reason)
   {
    if(handle!=INVALID_HANDLE)
       IndicatorRelease(handle);
 //--- почистим график при удалении индикатора
    Comment("");
   } 
 |