Files
2021-04-28 17:27:12 +02:00

364 lines
14 KiB
Plaintext

//+------------------------------------------------------------------+
//| CMAOnRingBuffer.mqh |
//| Copyright 2012, Konstantin Gruzdev |
//| https://login.mql5.com/ru/users/Lizar |
//| Revision 30 Nov 2012 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, Konstantin Gruzdev"
#property link "https://login.mql5.com/ru/users/Lizar"
//--- Class for working with the ring buffer of data:
#include <IncOnRingBuffer\CArrayRing.mqh>
//+------------------------------------------------------------------+
//| Class CMAOnRingBuffer |
//| Appointment: class is designed to calculate a moving averages |
//| using the class for working with the ring |
//| buffer. |
//| Link: http://www.mql5.com/ru/code/1342 |
//+------------------------------------------------------------------+
class CMAOnRingBuffer :public CArrayRing
{
private:
CArrayRing *m_array_in; // ring buffer for input data
int m_ma_period; // number of elements to analyze
ENUM_MA_METHOD m_ma_method; // MA calculation method
bool m_as_series; // true, if the indexing as in time series
double m_k1,m_k2;
double m_LK[];
string m_name; // indicator name
int m_bars_required; // number of elements required to calculate
int m_start; // index of element to start the calculation
int m_index; // current element index
public:
CMAOnRingBuffer() {}
~CMAOnRingBuffer();
//--- initialization method:
bool Init(int ma_period=14,ENUM_MA_METHOD ma_method=MODE_SMA, int size_buffer=256, bool as_series=false);
//--- basic methods:
int MainOnArray(const int rates_total, const int prev_calculated,const double &array[]);
double MainOnValue(const int rates_total, const int prev_calculated, const int begin, const double value, const int index);
//--- methods to get access to private data:
int BarsRequired() { return(m_bars_required); }
string Name() { return(m_name); }
string MAMethod() { return(MethodToString(m_ma_method)); }
int MAPeriod() { return(m_ma_period); }
//--- returns the value of element with the specified index:
double operator [](const int index) const { return(At(index)); }
private:
//--- methods of calculation based on the array of input data:
void SMAOnArray (const int rates_total, const int prev_calculated, const double &array[]);
void EMAOnArray (const int rates_total, const int prev_calculated, const double &array[]);
void LWMAOnArray(const int rates_total, const int prev_calculated, const double &array[]);
//--- methods to calculate the sequential values ??of the indicator elements:
double SMAOnValue (const int prev_calculated, const int begin, const double value, const int index);
double EMAOnValue (const int prev_calculated, const int begin, const double value, const int index);
double LWMAOnValue(const int prev_calculated, const int begin, const double value, const int index);
//--- auxiliary methods:
int Begin(const int rates_total,const double &array[]);
bool FillArrayIn(const int prev_calculated, const double value);
string MethodToString(ENUM_MA_METHOD method);
};
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
void CMAOnRingBuffer:: ~CMAOnRingBuffer()
{
if(CheckPointer(m_array_in)!=POINTER_INVALID) delete m_array_in;
}
//+------------------------------------------------------------------+
//| Indicator on array |
//+------------------------------------------------------------------+
int CMAOnRingBuffer:: MainOnArray(const int rates_total,const int prev_calculated,const double &array[])
{
//--- save as_series flags
bool as_series=ArrayGetAsSeries(array);
if(as_series) ArraySetAsSeries(array,false);
//--- main calculation:
switch(m_ma_method)
{
case MODE_SMA: SMAOnArray(rates_total,prev_calculated,array); break;
case MODE_EMA:
case MODE_SMMA: EMAOnArray(rates_total,prev_calculated,array); break;
case MODE_LWMA: LWMAOnArray(rates_total,prev_calculated,array); break;
}
//--- restore as_series flags
if(as_series) ArraySetAsSeries(array,true);
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Indicator on value |
//+------------------------------------------------------------------+
double CMAOnRingBuffer:: MainOnValue(const int rates_total, const int prev_calculated, const int begin, const double value, const int index)
{
//--- check as_series flags:
if(m_as_series) m_index=rates_total-1-index;
else m_index=index;
//--- check begin:
if(m_index<begin) return(EMPTY_VALUE);
//--- main calculation:
switch(m_ma_method)
{
case MODE_SMA: return(SMAOnValue(prev_calculated,begin,value,index));
case MODE_EMA:
case MODE_SMMA: return(EMAOnValue(prev_calculated,begin,value,index));
case MODE_LWMA: return(LWMAOnValue(prev_calculated,begin,value,index));
}
//--- result:
return(EMPTY_VALUE);
}
//+------------------------------------------------------------------+
//| Simple moving average on array |
//+------------------------------------------------------------------+
void CMAOnRingBuffer:: SMAOnArray(const int rates_total, const int prev_calculated, const double &array[])
{
//--- first calculation:
if(prev_calculated==0)
{
m_start=Begin(rates_total,array)+m_ma_period-1;
double sum=0.0;
for(int i=m_start;i>m_start-m_ma_period;i--) sum+=array[i];
Last(sum/m_ma_period);
}
//--- number of bars was changed:
else
{
m_start=prev_calculated-1;
Last(At(1)-(array[m_start-m_ma_period]-array[m_start])/m_ma_period);
}
//--- main loop
for(int i=m_start+1;i<rates_total && !IsStopped();i++)
Add(Last()-(array[i-m_ma_period]-array[i])/m_ma_period);
}
//+------------------------------------------------------------------+
//| Exponential moving average on array |
//+------------------------------------------------------------------+
void CMAOnRingBuffer:: EMAOnArray(const int rates_total,const int prev_calculated,const double &array[])
{
//--- first calculation:
if(prev_calculated==0)
{
m_start=Begin(rates_total,array);
Last(array[m_start]);
}
//--- number of bars was changed:
else
{
m_start=prev_calculated-1;
Last(m_k1*array[m_start]+m_k2*At(1));
}
//--- main loop:
for(int i=m_start+1;i<rates_total && !IsStopped();i++)
Add(m_k1*array[i]+m_k2*Last());
}
//+------------------------------------------------------------------+
//| Linear weighted moving average on array |
//+------------------------------------------------------------------+
void CMAOnRingBuffer:: LWMAOnArray(const int rates_total, const int prev_calculated, const double &array[])
{
//--- first calculation:
if(prev_calculated==0)
m_start=Begin(rates_total,array)+m_ma_period-1;
//--- number of bars was changed:
else m_start=prev_calculated-1;
double volue=0.0;
for(int j=0;j<m_ma_period && !IsStopped();j++)
volue+=array[m_start-j]*m_LK[j];
Last(volue);
//--- main loop
for(int i=m_start+1;i<rates_total && !IsStopped();i++)
{
volue=0.0;
for(int j=0;j<m_ma_period && !IsStopped();j++)
volue+=array[i-j]*m_LK[j];
Add(volue);
}
}
//+------------------------------------------------------------------+
//| Simple moving average on value |
//+------------------------------------------------------------------+
double CMAOnRingBuffer:: SMAOnValue(const int prev_calculated, const int begin, const double value, const int index)
{
//--- fill the ring buffer of input data:
if(!FillArrayIn(prev_calculated,value)) return(EMPTY_VALUE);
//--- initial calculation:
m_start=begin+m_ma_period-1;
if(m_index<m_start) return (EMPTY_VALUE);
else if(m_index==m_start)
{
double sum=0.0;
for(int i=0;i<m_ma_period && !IsStopped();i++) sum+=m_array_in[i];
Last(sum/m_ma_period);
return(Last());
}
//--- main calculation:
if(prev_calculated-1==m_index)
Last(At(1)-(m_array_in[m_ma_period]-value)/m_ma_period);
else
Add(Last()-(m_array_in[m_ma_period]-value)/m_ma_period);
//--- result:
return(Last());
}
//+------------------------------------------------------------------+
//| Exponential moving average on value |
//+------------------------------------------------------------------+
double CMAOnRingBuffer:: EMAOnValue(const int prev_calculated, const int begin, const double value, const int index)
{
//--- initial calculation:
if(m_index==begin)
{
Last(value);
return(value);
}
//--- main calculation:
if(prev_calculated-1==m_index)
Last(m_k1*value+m_k2*At(1));
else
Add(m_k1*value+m_k2*Last());
//--- result:
return(Last());
}
//+------------------------------------------------------------------+
//| Linear weighted moving average on value |
//+------------------------------------------------------------------+
double CMAOnRingBuffer:: LWMAOnValue(const int prev_calculated, const int begin, const double value, const int index)
{
//--- fill the ring buffer of input data:
if(!FillArrayIn(prev_calculated,value)) return(EMPTY_VALUE);
//--- initial calculation:
if(m_index<begin+m_ma_period-1) return (EMPTY_VALUE);
//--- main calculation:
double volue=0.0;
for(int j=0;j<m_ma_period && !IsStopped();j++)
volue+=m_array_in[j]*m_LK[j];
if(prev_calculated-1==m_index) Last(volue);
else Add(volue);
//--- result:
return(Last());
}
//+------------------------------------------------------------------+
//| Defines the index of the first element for calculation |
//+------------------------------------------------------------------+
int CMAOnRingBuffer:: Begin(const int rates_total,const double &array[])
{
//--- looking the start of significant data:
int i=-1;
while(++i<rates_total && !IsStopped())
{
if(array[i]!=0 && array[i]!=EMPTY_VALUE) break;
}
//--- Return the index of the element from which start calculations:
return(MathMax(i,rates_total-Size()-m_bars_required));
}
//+------------------------------------------------------------------+
//| Fill the ring buffer by input data |
//+------------------------------------------------------------------+
bool CMAOnRingBuffer:: FillArrayIn(const int prev_calculated, const double value)
{
//--- check pointer:
if(CheckPointer(m_array_in)==POINTER_INVALID)
{
if((m_array_in=new CArrayRing())==NULL) return false;
if(!m_array_in.Init(Size())) return false;
}
//--- fill the ring buffer of input data:
if(prev_calculated-1==m_index) m_array_in.Last(value);
else m_array_in.Add(value);
//--- successful
return true;
}
//+------------------------------------------------------------------+
//| Initialization method |
//+------------------------------------------------------------------+
bool CMAOnRingBuffer:: Init(int ma_period=14,ENUM_MA_METHOD ma_method=MODE_SMA, int size_buffer=256, bool as_series=false)
{
//--- check for input values
if(ma_period<=0)
{
m_ma_period=14;
printf("Input parameter ma_period has incorrect value (%d). Indicator will use value %d for calculations.",
ma_period,m_ma_period);
}
else m_ma_period=ma_period;
if(size_buffer<=m_ma_period)
{
printf("Input parameter size_buffer has incorrect value (%d). Indicator will use value %d for calculations.",
size_buffer,m_ma_period);
size_buffer=m_ma_period;
}
//--- initialization of the ring buffer for the indicator data:
if(!CArrayRing::Init(size_buffer)) return false;
//--- data initialization:
int coeff_required=10;
m_as_series=as_series;
m_ma_method=ma_method;
switch(m_ma_method)
{
case MODE_SMA:
{
m_bars_required=m_ma_period;
break;
}
case MODE_EMA:
{
m_k1=2.0/(m_ma_period+1.0);
m_k2=1.0-m_k1;
m_bars_required=m_ma_period*coeff_required;
break;
}
case MODE_SMMA:
{
m_k1=1.0/m_ma_period;
m_k2=1.0-m_k1;
m_bars_required=m_ma_period*coeff_required;
break;
}
case MODE_LWMA:
{
ArrayResize(m_LK,m_ma_period);
double sum=0;
for(int j=0;j<m_ma_period;j++) sum+=m_LK[j]=m_ma_period-j;
for(int j=0;j<m_ma_period;j++) m_LK[j]/=sum;
sum=0;
for(int j=0;j<m_ma_period;j++) sum+=m_LK[j];
m_bars_required=m_ma_period;
break;
}
default:
break;
}
m_name=MethodToString(m_ma_method)+"("+IntegerToString(m_ma_period)+")";
//--- successful
return true;
}
//+------------------------------------------------------------------+
//| Transformation of moving method in the text representation |
//+------------------------------------------------------------------+
string CMAOnRingBuffer:: MethodToString(ENUM_MA_METHOD method)
{
switch(method)
{
case MODE_SMA: return("SMA");
case MODE_EMA: return("EMA");
case MODE_LWMA: return("LWMA");
case MODE_SMMA: return("SMMA");
}
return(EnumToString(method));
}