Отрисовка n последних баров в индикаторе.

 

Просмотрел индикаторы в CodeBase, почитал статьи. Не пойму, как организовать отрисовку индикаторных буферов только заданное количество последних баров и начиная с первого.

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

Код скрипта:

//--- input parameters
input int    History=100;
input double Hd     =0.3;
input double Ld     =0.6;
input double Hl     =0.3;
input double Ll     =0.1;

//--------------------
double   Open   [];
double   Hight  [];
double   Low    [];
double   Close  [];
datetime Time   [];
datetime Ti     [];
double   Peaks  [];

double HightBuffer [];
double LowBuffer   [];
int    BWDWT_handle;
//--------------------
//+------------------------------------------------------------------+
void OnStart()
{
  ArraySetAsSeries(Open,true);  CopyOpen (NULL,0,0,History+2,Open);
  ArraySetAsSeries(Hight,true); CopyHigh (NULL,0,0,History+2,Hight);
  ArraySetAsSeries(Low,true);   CopyLow  (NULL,0,0,History+2,Low);
  ArraySetAsSeries(Close,true); CopyClose(NULL,0,0,History+2,Close);
  ArraySetAsSeries(Time,true);  CopyTime (NULL,0,0,History+2,Time);
  //-----------------------------------------------------------
  double DeltaLen=0.0;
  double DeltaAve=0.0;
  double BarLen  =0.0;
  double Hi;
  double Lo;
  double Ave=0.0,AvePrev=0.0;
  double SumAve=0.0;
  double x=0.0;

  ObjectsDeleteAll(0,-1,-1);
  //1-й этап
  SumAve=(Hight[0]+Low[0])/2.0;

  x=Hight[0]-Low[0];
  DeltaLen=((2.0/(1.0+MathPow(2.0,-x*(10/Ll))))-1.0)*Hl/2.0;
  //DeltaLen=x/2.0;
  Hi=NormalizeDouble(SumAve+DeltaLen,Digits());
  Lo=NormalizeDouble(SumAve-DeltaLen,Digits());

  ObjectCreate    (0,"AltBar0",OBJ_TREND,0,Time[0],Hi,Time[0],Lo);
  if(Open[0]>Close[0])
    ObjectSetInteger(0,"AltBar0",OBJPROP_COLOR,Yellow);
  else
    ObjectSetInteger(0,"AltBar0",OBJPROP_COLOR,Green);
  ObjectSetInteger(0,"AltBar0",OBJPROP_SELECTABLE,true);
  ObjectSetInteger(0,"AltBar0",OBJPROP_WIDTH,3);

  //-------
  for(int V=1;V<History;V++)
  {
    //2-й этап
    Ave    =(Hight[V-1]+Low[V-1])/2.0;
    AvePrev=(Hight[V]  +Low[V])  /2.0;
    x=Ave-AvePrev;
    DeltaAve=((2.0/(1.0+MathPow(2.0,-x*(10/Ld))))-1.0)*Hd/2.0;

    SumAve-=DeltaAve;

    x=Hight[V]-Low[V];
    DeltaLen=((2.0/(1.0+MathPow(2.0,-x*(10/Ll))))-1.0)*Hl/2.0;
    Hi=NormalizeDouble(SumAve+DeltaLen,Digits());
    Lo=NormalizeDouble(SumAve-DeltaLen,Digits());

    ObjectCreate      (0,"AltBar"+V,OBJ_TREND,0,Time[V],Hi,Time[V],Lo);

    if(Open[V]>Close[V])
      ObjectSetInteger(0,"AltBar"+V,OBJPROP_COLOR,Yellow);
    else
      ObjectSetInteger(0,"AltBar"+V,OBJPROP_COLOR,Green);
    ObjectSetInteger  (0,"AltBar"+V,OBJPROP_SELECTABLE,true);
    ObjectSetInteger  (0,"AltBar"+V,OBJPROP_WIDTH,3);

    //-------
    ChartRedraw(0);
  }
  ChartRedraw(0);
  //-----------------------------------------------------------
}
//+------------------------------------------------------------------+
Усреднение ценовых рядов без дополнительных буферов для промежуточных расчетов
Усреднение ценовых рядов без дополнительных буферов для промежуточных расчетов
  • 2010.10.25
  • Nikolay Kositsin
  • www.mql5.com
Статья о традиционных и не совсем традиционных алгоритмах усреднения, упакованных в максимально простые и достаточно однотипные классы. Они задумывались для универсального использования в практических разработках индикаторов. Надеюсь, что предложенные классы в определенных ситуациях могут оказаться достаточно актуальной альтернативой громоздким, в некотором смысле, вызовам пользовательских и технических индикаторов.
 
Да уж, на MQL5 форуме, похоже, помощи не дождешся.
 
joo:
Да уж, на MQL5 форуме, похоже, помощи не дождешся.

Не понятна цель

При инициализации нарисовать  -это сделано в скрипте уже.

что еще надо? 

Всегда отрисовывать только 100?

вывести в отельную фунцию и вызывать в

void OnStart() // инициализация

  {

// тут вызов
  }
и в  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 &TickVolume[],
                const long &Volume[],
                const int &Spread[])
  {int i;

// тут вызов
  return(i);
}
 - при тике
 

 

может все дело в тайм сериях и организации доступа к данным

тут все немного иначе

 

Пришел к такому, заднепроходному решению. Есть варианты получше?

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   4
//--- plot Source
#property indicator_label1  "Source"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Etalon
#property indicator_label2  "Etalon"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Yellow
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Normalised
#property indicator_label3  "Normalised"
#property indicator_type3   DRAW_LINE
#property indicator_color3  DarkGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Label4
#property indicator_label4  "Label4"
#property indicator_type4   DRAW_LINE
#property indicator_color4  Red
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- input parameters
input int      Clusters              =100;
input int      History               =1000;
input int      Input3;
input int      Input4;

input double   HdifferenceBetweenBars =0.005;
input double   LdifferenceBetweenBars =0.01;

input double   HBarHeight             =0.005;
input double   LBarHeight             =0.01;
//--- indicator buffers
double         SourceBuffer[];
//double         EtalonBuffer[];
//double         NormalisedBuffer[];
//double         Label4Buffer[];
//double         temp[];
//--------------------
double   Open   [];
double   Hight  [];
double   Low    [];
double   Close  [];
datetime Time   [];
datetime Ti     [];
double   Peaks  [];
int      CLUSTER[];
double   BarLength[];
double   DifferenceOfBars[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{ 
  ArraySetAsSeries(Open,true);  CopyOpen (NULL,0,0,History+2,Open);
  ArraySetAsSeries(Hight,true); CopyHigh (NULL,0,0,History+2,Hight);
  ArraySetAsSeries(Low,true);   CopyLow  (NULL,0,0,History+2,Low);
  ArraySetAsSeries(Close,true); CopyClose(NULL,0,0,History+2,Close);
  ArraySetAsSeries(Time,true);  CopyTime (NULL,0,0,History+2,Time);
  //-----------------------------------------------------------
  ArrayResize(CLUSTER,  Clusters);ArrayInitialize(CLUSTER,  0);
  ArrayResize(BarLength,Clusters);ArrayInitialize(BarLength,0);
//--- indicator buffers mapping
  SetIndexBuffer     (0,SourceBuffer,INDICATOR_DATA);
  PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,2);
  PlotIndexSetString (0,PLOT_LABEL,"SourceBuffer");
/*
  SetIndexBuffer     (1,EtalonBuffer,INDICATOR_DATA);
  PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,2);
  PlotIndexSetString (1,PLOT_LABEL,"EtalonBuffer");

  SetIndexBuffer(2,NormalisedBuffer,INDICATOR_DATA);
  SetIndexBuffer(3,Label4Buffer,INDICATOR_DATA);

  ArrayResize(temp,Clusters);
*/
//---
  return(0);
}
//+------------------------------------------------------------------+
//| 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 i=0;

  while (i<rates_total-1)
  {
    SourceBuffer    [i]=0.0;
    //EtalonBuffer    [i]=0.0;
    //NormalisedBuffer[i]=0.0;
    i++;  
  }

  if (Bars(NULL,PERIOD_CURRENT)== rates_total)
  {
    double DeltaLen=0.0;
    double DeltaAve=0.0;
    double BarLen  =0.0;
    double Hi      =0.0;
    double Lo      =0.0;
    double Ave=0.0,AvePrev=0.0;
    double SumAve=0.0;
    double x=0.0;

    ObjectsDeleteAll(0,-1,-1);
    //1-e yoai
    SumAve=(Hight[1]+Low[1])/2.0;

    x=Hight[1]-Low[1];
    DeltaLen=((2.0/(1.0+MathPow(2.0,-x*(10/LBarHeight))))-1.0)*HBarHeight/2.0;

    Hi=NormalizeDouble(SumAve+DeltaLen,Digits());
    Lo=NormalizeDouble(SumAve-DeltaLen,Digits());
    
    //CLUSTER[];
    //BarLength[1]=Hi-Lo;
    ObjectCreate    (0,"AltBar0",OBJ_TREND,0,Time[1],Hi,Time[1],Lo);
    if (Open[1]>Close[1])
      ObjectSetInteger(0,"AltBar0",OBJPROP_COLOR,Yellow);
    else
      ObjectSetInteger(0,"AltBar0",OBJPROP_COLOR,Green);
    ObjectSetInteger(0,"AltBar0",OBJPROP_SELECTABLE,true);
    ObjectSetInteger(0,"AltBar0",OBJPROP_WIDTH,3);

    //-------
    for (int V=2;V<=Clusters;V++)
    {
      //2-e yoai
      Ave    =(Hight[V-1]+Low[V-1])/2.0;
      AvePrev=(Hight[V]  +Low[V])  /2.0;
      x=Ave-AvePrev;
      DeltaAve=((2.0/(1.0+MathPow(2.0,-x*(10/LdifferenceBetweenBars))))-1.0)*HdifferenceBetweenBars/2.0;

      SumAve-=DeltaAve;

      x=Hight[V]-Low[V];
      DeltaLen=((2.0/(1.0+MathPow(2.0,-x*(10/LBarHeight))))-1.0)*HBarHeight/2.0;
      Hi=NormalizeDouble(SumAve+DeltaLen,Digits());
      Lo=NormalizeDouble(SumAve-DeltaLen,Digits());
      
      //BarLength[V]
      ObjectCreate      (0,"AltBar"+(string)V,OBJ_TREND,0,Time[V],Hi,Time[V],Lo);

      if (Open[V]>Close[V])
        ObjectSetInteger(0,"AltBar"+(string)V,OBJPROP_COLOR,Yellow);
      else
        ObjectSetInteger(0,"AltBar"+(string)V,OBJPROP_COLOR,Green);
      ObjectSetInteger  (0,"AltBar"+(string)V,OBJPROP_SELECTABLE,true);
      ObjectSetInteger  (0,"AltBar"+(string)V,OBJPROP_WIDTH,3);
      //-------
    }
    ChartRedraw(0);
    //-----------------------------------------------------------
    for (i=1;i<=Clusters;i++)
      SourceBuffer[rates_total-i-1]=Hight[i]-Low[i];
  }

  return(rates_total);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  ObjectsDeleteAll(0,-1,-1);
  ChartRedraw(0);
}
//+------------------------------------------------------------------+
 

ну да чуствуетсясоль уловил попробуй

сделать тайм сериями буферы

сразу все на место встанет

в отличие от мкл4

тут буферы индексируются от конца к началу

и обязательно надо делать связку 

вот тут почитай

// У меня повилась такая странная ошибка.

 
CoreWinTT :


вот тут почитай

// У меня повилась такая странная ошибка.

   ArraySetAsSeries(AtrBuffer,true);
   ArraySetAsSeries(TempBuffer,true);
   Print("AtrBuffer до",ArrayGetAsSeries(AtrBuffer));
   Print("TempBuffer до",ArrayGetAsSeries(TempBuffer));
   SetIndexBuffer(0,AtrBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,TempBuffer,INDICATOR_CALCULATIONS);
   Print("AtrBuffer после",ArrayGetAsSeries(AtrBuffer));
   Print("TempBuffer после",ArrayGetAsSeries(TempBuffer));


   ArraySetAsSeries(AtrBuffer,false);
   ArraySetAsSeries(TempBuffer,false);
   Print("AtrBuffer до",ArrayGetAsSeries(AtrBuffer));
   Print("TempBuffer до",ArrayGetAsSeries(TempBuffer));
   SetIndexBuffer(0,AtrBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,TempBuffer,INDICATOR_CALCULATIONS);
   Print("AtrBuffer после",ArrayGetAsSeries(AtrBuffer));
   Print("TempBuffer после",ArrayGetAsSeries(TempBuffer));


Я уже сообщил в сервисдеск об этом не соответствии с текстом справки.






 

в справке все нормально =)

тут дело в головах который привыкли к мкл5

кто сказал что при инициализации буфер должен стать тайм серией...

и ваше что он должен


все дело в головах

 
из справки

Примечание

После связывания динамический массив buffer[]  будет иметь индексацию как в обычных массивах, даже если для связываемого массива будет предварительно установлена индексация как в таймсериях. Если необходимо изменить порядок доступа к элементам индикаторного массива, необходимо применить функцию ArraySetAsSeries() после связывания массива функцией SetIndexBuffer().

 

Я же привёл пример, что если до связывания была таймсерия, то и после будет таймсерия!


 
DC2008 :

Я же привёл пример, что если до связывания была таймсерия, то и после будет таймсерия!

и

Rosh:

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

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

и

CoreWinTT:

да я немного понял когда немножко задумался про заполнения буферов и организацию доступа данных.

думаю данное примечание стоит написать не только к функции к SetIndexBuffer()

Теперь, люди добрые, объясните мне, что я именно не понимаю.

Вот код индикатора MQL4

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 DeepSkyBlue
//---- input parameters
extern int       History=100;
//---- buffers
double HiBuffer[];
//-------------------------------------------------------------------
int init()
{
//---- indicators
  SetIndexStyle(0,DRAW_HISTOGRAM);
  SetIndexBuffer(0,HiBuffer);
//----
  return(0);
}
//-------------------------------------------------------------------
int deinit()
{
//----

//----
  return(0);
}
//-------------------------------------------------------------------
int start()
{
  int    counted_bars=IndicatorCounted();
//----
  int i=0;
  while (i<counted_bars)
  {
    if (i<History)
    {
      HiBuffer[i]=High[i];
    } else
    {
      HiBuffer[i]=0.0;
    }

    i++;
  }
//----
  return(0);
}
//-------------------------------------------------------------------

он рисует такую картинку:

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

Теперь посмотрим на код MQL5, того же индикатора:

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Hi
#property indicator_label1  "Hi"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//-------------------------------------------------------------------
input int      History               =100;
//-------------------------------------------------------------------
double         HiBuffer[];
//-------------------------------------------------------------------
int OnInit()
{
  SetIndexBuffer     (0,HiBuffer,INDICATOR_DATA);
  PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,1);
  PlotIndexSetString (0,PLOT_LABEL,"HiBuffer");
  return(0);
}
//-------------------------------------------------------------------
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
  int i=0;
  while (i<rates_total)
  {
    if (i<History)
    {
      HiBuffer[i]=high[i];
    } else
    {
      HiBuffer[i]=0.0;
    }
    i++;
  }
  return(rates_total);
}
//-------------------------------------------------------------------

Он рисует такую картинку:


Обратите внимание, что здесь 0-й индекс буфера индикатора соответствует самому старому бару на графике.

Зачем так? Объясните пожалуйста. Скажете, а в чем проблема, сделай буфер индикатора таймсерией, и всё будет ок.

Ок, делаю:

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Hi
#property indicator_label1  "Hi"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//-------------------------------------------------------------------
input int      History               =100;
//-------------------------------------------------------------------
double         HiBuffer[];
//-------------------------------------------------------------------
int OnInit()
{
  SetIndexBuffer     (0,HiBuffer,INDICATOR_DATA);
  ArraySetAsSeries   (HiBuffer,true);//Сделал как посоветовали. 
  PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,1);
  PlotIndexSetString (0,PLOT_LABEL,"HiBuffer");
  return(0);
}
//-------------------------------------------------------------------
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
  int i=0;
  while (i<rates_total)
  {
    if (i<History)
    {
      HiBuffer[i]=high[i];
    } else
    {
      HiBuffer[i]=0.0;
    }
    i++;
  }
  return(rates_total);
}
//-------------------------------------------------------------------

Получаем такую картинку:

Что мы видим теперь? 0-й индекс буфера индекатоора будет соответствовать также самому старому бару на графике, только отображаются уже в самом конце истории.


Выше я показывал одно из заднепрходных решений. Но оно Заднепроходное!.

Или я что то не понимаю, объясните пожалуйста, как нужно работать с индикаторами, что бы стало "легче".