Скользящая средняя(SMA) в количестве 2000 шт. расчитать при минимальных затрат ресурсов. - страница 3

 
Top2n:
2000 с разными периодами

Тогда не надо хранить старые значения. На каждой итерации делаем 2000 сложений. Меньше никак. 

Если надо не с периода 1 или 2 начать, тогда для минимального периода применять ускоренный алгоритм с хранением старого значения, а дальше только прибавлять.

Ускоренный алгоритм это два действия - отнять старое, прибавить новое. Значит если минимальный период больше от 4, то есть смысл в его использовании для минимального периода.

 

 Здравствуйте. один вопрос, подскажите пожалуйста, как в эксперт перенести данные индикатора.

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property indicator_label1  "Lx"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input int      Pmax=2000;
input int      numMa=51;
//--- indicator buffers
double         Lx[];


#include <SMA_Greed.mqh>  
CSMA_Greed sm;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   SetIndexBuffer(0,Lx);
   PlotIndexSetInteger(0,PLOT_ARROW,159);
   sm.Init(Pmax);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
sm.Solve(rates_total,prev_calculated,price);


 for(int a=prev_calculated>Pmax?prev_calculated:Pmax;a<rates_total;a++)
   {
   Lx[a]=sm.d[numMa-1].m[rates_total-1]; //  значения - sm.d[numMa-1] - задается период SMA, m[rates_total-1] - задается значение бара
ВООБЩЕМ ВЫВОДИТ ЗНАЧЕНИЕ ЦЕНЫ MA на основании объявленного периода и номера бара
   }
 
Top2n:

 Здравствуйте. один вопрос, подскажите пожалуйста, как в эксперт перенести данные индикатора.

iCustom не подходит?
 
Andrey Khatimlianskii:
iCustom не подходит?

Данные выходят не те, работает как счетчик тиков похоже.

Файлы:
SMA_Greed.mqh  3 kb
Top.mq5  2 kb
 
Top2n:

Данные выходят не те, работает как счетчик тиков похоже.

Не понимаю.

И не вижу кода с попыткой вызова. И собственных исследований тоже не вижу.

Пример есть в справке. 

 

Я когда-то давно написал для себя самый простой, но весьма быстрый SMA (один из первым классов у меня был, чтобы научиться).

Может быть пригодится кому такой вариант:

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Sma.mqh 
 Fry
 smart-lab.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#property copyright "Fry"
#property link      "smart-lab.ru"

// SMA класс:
class CSma
{
private:
   double SmaBuf[];    // буфер усреднения
   double total;       // сумма SМА
      int p;           // указатель буфера
      int countMA;     // счётчик кол-ва проходов
      int PeriodMA;    // период
      int digits;      // точность
  
public:
   // Конструктор объекта
   // ma_period - период SMA, digits_ - точность результата (кол-во знаков после запятой)
    CSma(){Set(10,5);}
   ~CSma(){ArrayFree(SmaBuf);}
   
   // Этот метод необходим при любом обновлении кривой (всегда от начала)
   // ma_period - период SMA, digits_ - точность результата (кол-во знаков после запятой)
   void Set(const int ma_period, const int digits_)
   {
      digits=digits_;
      PeriodMA=ma_period;
      ArrayResize(SmaBuf,PeriodMA);
      for(int i=0; i<PeriodMA;i++) SmaBuf[i]=0;
      total=0; p=0; countMA=0;
   }
   
   // метод расчёта закрытых баров. Он обычно вызывается как .Bar(Buf[i-1]) - (-1), потому что не на текущий тик, а на закрытую свечку
   // Вход : очередной элемент из цепи для сглаживания
   // Выход: значение SMA для элемента цепи с точностью результата до digits_
   double Bar(const double Input)
   {
      total += Input-SmaBuf[p];                // получаем новую сумму из цепи входных значений (от 0 до PeriodMA-1 значений)
      SmaBuf[p]=Input;                         // обновляем значение в малой цепи

      if (p<1) p=PeriodMA;                     // закольцовка указателя SmaBuf
               p--;

      countMA++;
      if (countMA>PeriodMA) countMA=PeriodMA;  // макс состояние счётчика = PeriodMA
      return (NormalizeDouble(total/countMA,digits));
   }
   // метод расчёта открытых баров. Использовать только для расчёта свежих тиков, а когда свеча закрывается её надо обязательно пересчитать в Bar
   double Tick(const double Input) {return (NormalizeDouble((total+Input-SmaBuf[p])/countMA,digits));}
   
   // Инициализация цепочки SMA (расчёт на глубину периода)
   // метод можно вызвать в начале калькуляции, чтобы дальше расчёт SMA строго соответствовал ma_period
   // суть: от массива Input[] на отрезке [i-ma_period-2]...[i-2] считает цепочку SMA, где i - указатель на старшее значение массива (обычно это текущий бар)
   // вернёт false, если в массиве недостаточно значений
   bool Start(const double &Input[])
   {
      int limit=ArraySize(Input)-3;
      int i=limit-PeriodMA;
      if(i<0) return(false);
      for(;i<limit;i++) Bar(Input[i]);   // пересчитываем цепочку SMA на глубину MaPeriod
      return (true);
   }
   
};

Его можно дополнить легко если надо обёрткой, так чтобы тики обрабатывать тем же методом и вообще можно развивать.

 
Fry_Антон:

Я когда-то давно написал для себя самый простой, но весьма быстрый SMA (один из первым классов у меня был, чтобы научиться).

Может быть пригодится кому такой вариант:

Его можно дополнить легко если надо обёрткой, так чтобы тики обрабатывать тем же методом и вообще можно развивать.

А как его подключить - класс объявил в #include <Sma.mqh> , что ещё надо сделать, что б он заработал? Для четверки будет работать? Быстрей iMA работает, или преимущество в экономии памяти?
 
Andrey Khatimlianskii:

Не понимаю.

И не вижу кода с попыткой вызова. И собственных исследований тоже не вижу.

Пример есть в справке. 

Дело то в том, что нечего интересного я не придумал. 

input int      Pmax=2000;
input int      numMa=51;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

void OnTick()
  {
//---
   double as = iCustom(NULL,0,"Top",Pmax,numMa,0,1);
   Comment("as ",as); //
  }

 Вообще задача в том чтоб появилась возможность, по заданным параметрам:

- № бара

-№ период МА

Определить значение периода МА на заданном баре в Эксперте через индикатор

Файлы:
0x9.mq5  2 kb
 
Top2n:

Дело то в том, что нечего интересного я не придумал. 

 Вообще задача в том чтоб появилась возможность, по заданным параметрам:

- № бара

-№ период МА

Определить значение периода МА на заданном баре в Эксперте через индикатор

Придумали, придумали )

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

Все работает:

input int      Pmax=2000;
input int      numMa=51;
int handle = -1;

int OnInit()
{
        //--- create timer
        handle = iCustom(_Symbol,PERIOD_CURRENT,"Top",Pmax,numMa);
        if ( handle == INVALID_HANDLE ) return(INIT_FAILED);
        //---
        return(INIT_SUCCEEDED);
}

void OnTick()
{
        double array[];
        int copy=CopyBuffer(handle,0,0,1,array); 
        Comment("as ",array[0]); //
}

 

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

 
-Aleks-:
А как его подключить - класс объявил в #include <Sma.mqh> , что ещё надо сделать, что б он заработал? Для четверки будет работать? Быстрей iMA работает, или преимущество в экономии памяти?

*Выше в коде у меня был серьёзный баг! Сейчас увидел и исправил (две строки местами переставил).

Когда я это написал в четвёрке не было никаких классов и не планировалось даже близко, а сейчас у меня нет четвёрки, так что проверить не могу. Работает быстро и экономно, но окупается по настоящему если алгоритм не простой SMA вставить, а какой-нибудь сложный расчёт. Вот тогда разница офигенная.

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

Вообще можно статически объявить объект... Индюк для примера (тоже очень давно кодил):

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_SMA_.mq5
 Fry
 smart-lab.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include <Sma.mqh> // класс SMA
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#property version     "1.000"
#property description "Simple Moving Average"
#property link        "smart-lab.ru"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrGray
#property indicator_style1  STYLE_SOLID
#property indicator_applied_price PRICE_CLOSE
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
input int sma_period=12  ; //Период
input int      Shift=0   ; //Смещение по оси времени
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
double   buf_sma[];  // indicator buffer
CSma     sma;        // Объект расчёта цепочки SMA
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int OnInit()
{   
   string label="SMA("+(string)sma_period+")";
   
   IndicatorSetString (INDICATOR_SHORTNAME,label);       // set shortname 
   PlotIndexSetString (0,PLOT_LABEL       ,label);       // and change label
   SetIndexBuffer     (0,buf_sma,INDICATOR_DATA);        // set buffer
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);        // set accuracy
   PlotIndexSetInteger(0,PLOT_SHIFT,Shift);              // set index shift
   return(INIT_SUCCEEDED);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
   if(ArrayGetAsSeries(price)) ArraySetAsSeries(price,false);   //!!! в доке написано, что надо, а надо ли?
   
   if(begin>rates_total) return(0);                             // исключаем случай, когда начало отрисовки больше, чем баров в истории
   if(begin!=0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,begin);   // begin определяет кол-во баров в истории слева, которые не надо отрисовывать
   
   int i=prev_calculated-1;                                     // detect position
   if(i<begin)                                                  // если требуется полный пересчёт индикатора (бывает довольно часто)
   {
      i=begin;
      sma.Set(sma_period,_Digits);                              // первичная инициализация объекта
   }
   for(; i<rates_total-1 && !IsStopped(); i++)                  // Цикл расчёта закрытых баров (расчёт истории)
   {
      buf_sma[i]=sma.Bar(price[i]);
   }
   buf_sma[i]=sma.Tick(price[i]);                               // Расчёт свежего тика отличается, чтобы не искажать цепочку SMA тиками
   
   return(rates_total);
}

Для автора топика здесь самое полезное, то, что не надо создавать 2000 буферов индикатора если нет нужды графику всю это на каждый бар накладывать. Можно создать 2000 экземпляров объекта и сам расчёт будет весьма экономным во всех смыслах.

Другое дело, что я абсолютно согласен с Андреем (Andrey Khatimlianskii) - столько мувингов не нужно =)

Причина обращения: