Discussion of article "Extending MQL5 Standard Library and reusing code" - page 2

 
Tango_X:


Help me understand how the indexing direction of the indicator buffer array is set here, i.e. the same as ArraySetAsSeries. The default direction is from present to past, but I need to make it from past to present. I've been struggling with this question since yesterday! Help!

It doesn't need it, as it uses the standard ZigZag.

//--- create
   m_handle=iCustom(symbol,period,"zigzag",depth,deviation_create,backstep);

Look for the place where the direction is set in this ZigZag , but it's still unclear why you need it - you can change the indexing direction yourself at any time - https://www.mql5.com/en/docs/series.

Документация по MQL5: Доступ к таймсериям и индикаторам
Документация по MQL5: Доступ к таймсериям и индикаторам
  • www.mql5.com
Доступ к таймсериям и индикаторам - справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 
Rashid Umarov:

It doesn't need it, as it uses the standard ZigZag

In this ZigZag , look for the place where the direction is set. But it's still unclear why you need it - you can change the direction of indexing yourself at any time - https://www.mql5.com/en/docs/series.


Thanks for the information, we'll look into it!

 
Rashid Umarov:

It doesn't need it, as it uses the standard ZigZag

In this ZigZag look for the place where the direction is set. But still it's not clear why you need it - you can change the indexing direction yourself at any time - https://www.mql5.com/en/docs/series.


I'm sorry, but it's still not clear how to change the indexing direction, for example, if you don't have access to the Zigzag source. The indexing direction is set by ArraySetAsSeries() - where the input parameter is an array by reference,

but we don't have this array, but only a pointer to the indicator buffer array in the form of

//--- create buffers
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
 
//+------------------------------------------------------------------+
//|OOO_ZIGZAG.mq5 |
//| Copyright 2017, MetaQuotes Software Corp. | |
//|https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#include <..\Include\Indicators\Indicator.mqh>


//--- input parameters
input ENUM_TIMEFRAMES   EAPeriod=PERIOD_CURRENT; //Schedule period
input string            CurrencyPair="EURUSD.m"; //Symbol

//+------------------------------------------------------------------+
//| Class CiZigZag.|
//| Purpose: ZigZag indicator class. ||
//| Output from the CIndicator class.|
//+------------------------------------------------------------------+
class CiZigZag : public CIndicator
  {
protected:
   int               m_depth;
   int               m_deviation;
   int               m_backstep;

public:
                     CiZigZag(void);
                    ~CiZigZag(void);
   //--- methods of access to protected data
   int               Depth(void)          const { return(m_depth);      }
   int               Deviation(void)      const { return(m_deviation);  }
   int               Backstep(void)       const { return(m_backstep);   }
   //--- creation method
   bool              Create(const string symbol,const ENUM_TIMEFRAMES period,
                            const int depth,const int deviation_create,const int backstep);
   //--- methods of access to indicator data
   double            ZigZag(const int index) const;
   double            High(const int index) const;
   double            Low(const int index) const;
   //--- identification method
   virtual int       Type(void) const { return(IND_CUSTOM); }

protected:
   //--- customisation methods
   virtual bool      Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[]);
   bool              Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                                const int depth,const int deviation_init,const int backstep);
  };
//+------------------------------------------------------------------+
//| Constructor|
//+------------------------------------------------------------------+
CiZigZag::CiZigZag(void) : m_depth(-1),
                         m_deviation(-1),
                         m_backstep(-1)
  {
  }
//+------------------------------------------------------------------+
//| Destructor|
//+------------------------------------------------------------------+
CiZigZag::~CiZigZag(void)
  {
  }
//+------------------------------------------------------------------+
//|| Create the "Zig Zag" indicator|
//+------------------------------------------------------------------+
bool CiZigZag::Create(const string symbol,const ENUM_TIMEFRAMES period,
                      const int depth,const int deviation_create,const int backstep)
  {
//--- check history
   if(!SetSymbolPeriod(symbol,period))
      return(false);
//--- create
   m_handle=iCustom(symbol,period,"Examples\\ZigZag",depth,deviation_create,backstep);
//--- check the result
   if(m_handle==INVALID_HANDLE)
      return(false);
//--- indicator successfully created
   if(!Initialize(symbol,period,depth,deviation_create,backstep))
     {
      //--- initialisation error
      IndicatorRelease(m_handle);
      m_handle=INVALID_HANDLE;
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialise the indicator with universal parameters |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])
  {
   return(Initialize(symbol,period,(int)params[0].integer_value,(int)params[1].integer_value,(int)params[2].integer_value));
  }
//+------------------------------------------------------------------+
//| Initialise the indicator with special parameters |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                        const int depth,const int deviation_init,const int backstep)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- rendering status line
      m_name  ="ZigZag";
      m_status="("+symbol+","+PeriodDescription()+","+
               IntegerToString(depth)+","+IntegerToString(deviation_init)+","+
               IntegerToString(backstep)+") H="+IntegerToString(m_handle);
      //--- save settings
      m_depth=depth;
      m_deviation=deviation_init;
      m_backstep=backstep;       
      //--- create buffers
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
      //--- ok
      return(true);
     }
//--- error
   return(false);
  }
//+------------------------------------------------------------------+
//| Access to the ZigZag buffer of the "Zig Zag" indicator |
//+------------------------------------------------------------------+
double CiZigZag::ZigZag(const int index) const
  {
   CIndicatorBuffer *buffer=At(0);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Access to the High buffer of the "Zig Zag" indicator |
//+------------------------------------------------------------------+
double CiZigZag::High(const int index) const
  {
   CIndicatorBuffer *buffer=At(1);
   //--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Access to the Low buffer of the "Zig Zag" indicator |
//+------------------------------------------------------------------+
double CiZigZag::Low(const int index) const
  {
   CIndicatorBuffer *buffer=At(2);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+



CiZigZag *Zig;
//+------------------------------------------------------------------+
//| Custom indicator initialisation function |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   Zig=new CiZigZag;
   Zig.Create(CurrencyPair,EAPeriod,12,5,3);
//---
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   delete(Zig);
  }  
//+------------------------------------------------------------------+
//| 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;
   if(prev_calculated==0)limit=0;
   else
     limit=prev_calculated-1; 
     
   for(int i=limit;i<rates_total && !IsStopped();i++)
      {
       Zig.Refresh();
       if (Zig.ZigZag(i)!=0) Print(Zig.ZigZag(i)," ",time[i]);  
      }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Here is the full code of the indicator, where the output of indicator values is from the present to the past - and it is necessary vice versa

 
Tango_X:

Sorry, but still not clear how to change the direction of indexing, for example, if there is no access to the source Zigzag. The indexing direction is set by ArraySetAsSeries() - where the input parameter is an array by reference,

but we don't have this array, but only a pointer to the indicator buffer array in the form of

The CIndicator base class has a GetData method, which can be used to get data from the indicator buffer.

Gets data from the indicator buffer by start position and number

int GetData(
const intstart_pos, // position
const intcount, // number
const int buffer_num, // buffer number
double&buffer[]// array
) const



After that, set the desired indexing direction for your array using ArraySetAsSeries

 
Rashid Umarov:

The CIndicator base class has a GetData method that can be used to get data from the indicator buffer.

Gets data from the indicator buffer by start position and number of

int GetData(
const intstart_pos, // position
const intcount, // number
const int buffer_num, // buffer number
double&buffer[]// array
) const



After that, set the desired indexing direction for your array.

So it turns out to access the indicator buffer twice, but in different ways? After all, here below we already have access to the values of the indicator buffer? We get an intermediate array double &buffer[] I understand you correctly?

//+------------------------------------------------------------------+
//| Access to the ZigZag buffer of the "Zig Zag" indicator |
//+------------------------------------------------------------------+
double CiZigZag::ZigZag(const int index) const
  {
   CIndicatorBuffer *buffer=At(0);
//--- check
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
 
Rashid Umarov:

The CIndicator base class has a GetData method that can be used to get data from the indicator buffer.

Gets data from the indicator buffer by start position and number of

int GetData(
const intstart_pos, // position
const intcount, // number
const int buffer_num, // buffer number
double&buffer[]// array
) const



After that, set the desired indexing direction for your array using ArraySetAsSeries

Have I understood you correctly?

CiZigZag *Zig;
double ArrZig[];
//+------------------------------------------------------------------+
//| Custom indicator initialisation function |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   Zig=new CiZigZag;
   Zig.Create(CurrencyPair,EAPeriod,12,5,3);

   SetIndexBuffer(0,ArrZig,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(ArrZig,false);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   delete(Zig);
  }
//+------------------------------------------------------------------+
//| 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;
   if(prev_calculated==0) limit=0;
   else
      limit=prev_calculated-1;

   Zig.Refresh();
   Zig.GetData(0,rates_total-1,0,ArrZig);

   for(int i=limit;i<rates_total-1 && !IsStopped();i++)
     {

      //if (Zig.ZigZag(i)!=0) Print(Zig.ZigZag(i)," ",time[i]); 
      if(ArrZig[i]!=0) Print(ArrZig[i]," ",time[i]);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
It turns out that you need to copy the whole history on each tick?
 
Tango_X:

Am I understanding you correctly???

It turns out that it is necessary to copy the whole history on each tick?

1. You can do it at the opening of a new bar

2. Why do you need to get all indicator values every time, and at the same time take care of the indexing direction? What is the task at all?

 

Why wrapping a simple indicator into a class if it is used later either in a chart or via iCustom?

Второе решение лучше, потому что является объектно-ориентированным

OOP for OOP's sake, okay.

 
Rashid Umarov:

1. It is possible to open a new bar

2. Why do you need to get all the indicator values every time, and at the same time care about the indexing direction? What is the task at all?


The problem was solved by the loop conditions, now everything works as desired. thanks!