516 lines
19 KiB
MQL5
516 lines
19 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Indicator.mqh |
|
|
//| Copyright 2000-2025, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "Series.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Class CIndicatorBuffer. |
|
|
//| Purpose: Class for access to data of buffers of |
|
|
//| technical indicators. |
|
|
//| Derives from class CDoubleBuffer. |
|
|
//+------------------------------------------------------------------+
|
|
class CIndicatorBuffer : public CDoubleBuffer
|
|
{
|
|
protected:
|
|
int m_offset; // shift along the time axis (in bars)
|
|
string m_name; // name of buffer
|
|
|
|
public:
|
|
CIndicatorBuffer(void);
|
|
~CIndicatorBuffer(void);
|
|
//--- methods of access to protected data
|
|
int Offset(void) const { return(m_offset); }
|
|
void Offset(const int offset) { m_offset=offset; }
|
|
string Name(void) const { return(m_name); }
|
|
void Name(const string name) { m_name=name; }
|
|
//--- methods of access to data
|
|
double At(const int index) const;
|
|
//--- method of refreshing of data in buffer
|
|
bool Refresh(const int handle,const int num);
|
|
bool RefreshCurrent(const int handle,const int num);
|
|
|
|
private:
|
|
virtual bool Refresh(void) { return(CDoubleBuffer::Refresh()); }
|
|
virtual bool RefreshCurrent(void) { return(CDoubleBuffer::RefreshCurrent()); }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CIndicatorBuffer::CIndicatorBuffer(void) : m_offset(0),
|
|
m_name("")
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CIndicatorBuffer::~CIndicatorBuffer(void)
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Access to data in a specified position |
|
|
//+------------------------------------------------------------------+
|
|
double CIndicatorBuffer::At(const int index) const
|
|
{
|
|
return(CDoubleBuffer::At(index+m_offset));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Refreshing of data in buffer |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicatorBuffer::Refresh(const int handle,const int num)
|
|
{
|
|
//--- check
|
|
if(handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(false);
|
|
}
|
|
//---
|
|
m_data_total=CopyBuffer(handle,num,-m_offset,m_size,m_data);
|
|
//---
|
|
return(m_data_total>0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Refreshing of the data in buffer |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicatorBuffer::RefreshCurrent(const int handle,const int num)
|
|
{
|
|
double array[1];
|
|
//--- check
|
|
if(handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(false);
|
|
}
|
|
//---
|
|
if(CopyBuffer(handle,num,-m_offset,1,array)>0 && m_data_total>0)
|
|
{
|
|
m_data[0]=array[0];
|
|
return(true);
|
|
}
|
|
//--- error
|
|
return(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Class CIndicator. |
|
|
//| Purpose: Base class of technical indicators. |
|
|
//| Derives from class CSeries. |
|
|
//+------------------------------------------------------------------+
|
|
class CIndicator : public CSeries
|
|
{
|
|
protected:
|
|
int m_handle; // indicator handle
|
|
string m_status; // status of creation
|
|
bool m_full_release; // flag
|
|
bool m_redrawer; // flag
|
|
|
|
public:
|
|
CIndicator(void);
|
|
~CIndicator(void);
|
|
//--- methods of access to protected data
|
|
int Handle(void) const { return(m_handle); }
|
|
string Status(void) const { return(m_status); }
|
|
void FullRelease(const bool flag=true) { m_full_release=flag; }
|
|
void Redrawer(const bool flag=true) { m_redrawer=flag; }
|
|
//--- method for creating
|
|
bool Create(const string symbol,const ENUM_TIMEFRAMES period,
|
|
const ENUM_INDICATOR type,const int num_params,const MqlParam ¶ms[]);
|
|
virtual bool BufferResize(const int size);
|
|
//--- methods of access to data
|
|
int BarsCalculated(void) const;
|
|
double GetData(const int buffer_num,const int index) const;
|
|
int GetData(const int start_pos,const int count,const int buffer_num,double &buffer[]) const;
|
|
int GetData(const datetime start_time,const int count,const int buffer_num,double &buffer[]) const;
|
|
int GetData(const datetime start_time,const datetime stop_time,const int buffer_num,double &buffer[]) const;
|
|
//--- methods for find extremum
|
|
int Minimum(const int buffer_num,const int start,const int count) const;
|
|
double MinValue(const int buffer_num,const int start,const int count,int &index) const;
|
|
int Maximum(const int buffer_num,const int start,const int count) const;
|
|
double MaxValue(const int buffer_num,const int start,const int count,int &index) const;
|
|
//--- method of "freshening" of the data
|
|
virtual void Refresh(const int flags=OBJ_ALL_PERIODS);
|
|
//--- methods for working with chart
|
|
bool AddToChart(const long chart,const int subwin);
|
|
bool DeleteFromChart(const long chart,const int subwin);
|
|
//--- methods of conversion of constants to strings
|
|
static string MethodDescription(const int val);
|
|
static string PriceDescription(const int val);
|
|
static string VolumeDescription(const int val);
|
|
|
|
protected:
|
|
//--- methods of tuning
|
|
bool CreateBuffers(const string symbol,const ENUM_TIMEFRAMES period,const int buffers);
|
|
virtual bool Initialize(const string symbol,const ENUM_TIMEFRAMES period,
|
|
const int num_params,const MqlParam ¶ms[]) {return(false);}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
void CIndicator::CIndicator(void) : m_handle(INVALID_HANDLE),
|
|
m_status(""),
|
|
m_full_release(false),
|
|
m_redrawer(false)
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
void CIndicator::~CIndicator(void)
|
|
{
|
|
//--- indicator handle release
|
|
if(m_full_release && m_handle!=INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_handle);
|
|
m_handle=INVALID_HANDLE;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Creation of the indicator with universal parameters |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicator::Create(const string symbol,const ENUM_TIMEFRAMES period,
|
|
const ENUM_INDICATOR type,const int num_params,const MqlParam ¶ms[])
|
|
{
|
|
//--- check history
|
|
if(!SetSymbolPeriod(symbol,period))
|
|
return(false);
|
|
//--- create
|
|
m_handle=IndicatorCreate(symbol,period,type,num_params,params);
|
|
//--- check result
|
|
if(m_handle==INVALID_HANDLE)
|
|
return(false);
|
|
//--- idicator successfully created
|
|
if(!Initialize(symbol,period,num_params,params))
|
|
{
|
|
//--- initialization failed
|
|
IndicatorRelease(m_handle);
|
|
m_handle=INVALID_HANDLE;
|
|
return(false);
|
|
}
|
|
//--- ok
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Returns the amount of calculated indicator data |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::BarsCalculated(void) const
|
|
{
|
|
if(m_handle==INVALID_HANDLE)
|
|
return(-1);
|
|
//---
|
|
return(::BarsCalculated(m_handle));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| API access method "Copying an element of indicator buffer |
|
|
//| by specifying number of buffer and position of element" |
|
|
//+------------------------------------------------------------------+
|
|
double CIndicator::GetData(const int buffer_num,const int index) const
|
|
{
|
|
CIndicatorBuffer *buffer=At(buffer_num);
|
|
//--- check
|
|
if(buffer==NULL)
|
|
{
|
|
Print(__FUNCTION__,": invalid buffer");
|
|
return(EMPTY_VALUE);
|
|
}
|
|
//---
|
|
return(buffer.At(index));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| API access method "Copying the buffer of indicator by specifying |
|
|
//| a start position and number of elements" |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::GetData(const int start_pos,const int count,const int buffer_num,double &buffer[]) const
|
|
{
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(-1);
|
|
}
|
|
if(buffer_num>=m_buffers_total)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_BUFF_NUM);
|
|
return(-1);
|
|
}
|
|
//---
|
|
return(CopyBuffer(m_handle,buffer_num,start_pos,count,buffer));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| API access method "Copying the buffer of indicator by specifying |
|
|
//| start time and number of elements" |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::GetData(const datetime start_time,const int count,const int buffer_num,double &buffer[]) const
|
|
{
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(-1);
|
|
}
|
|
if(buffer_num>=m_buffers_total)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_BUFF_NUM);
|
|
return(-1);
|
|
}
|
|
//---
|
|
return(CopyBuffer(m_handle,buffer_num,start_time,count,buffer));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| API access method "Copying the buffer of indicator by specifying |
|
|
//| start and final time |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::GetData(const datetime start_time,const datetime stop_time,const int buffer_num,double &buffer[]) const
|
|
{
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(-1);
|
|
}
|
|
if(buffer_num>=m_buffers_total)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_BUFF_NUM);
|
|
return(-1);
|
|
}
|
|
//---
|
|
return(CopyBuffer(m_handle,buffer_num,start_time,stop_time,buffer));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Find minimum of a specified buffer |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::Minimum(const int buffer_num,const int start,const int count) const
|
|
{
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(-1);
|
|
}
|
|
if(buffer_num>=m_buffers_total)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_BUFF_NUM);
|
|
return(-1);
|
|
}
|
|
//---
|
|
CIndicatorBuffer *buffer=At(buffer_num);
|
|
if(buffer==NULL)
|
|
return(-1);
|
|
//---
|
|
return(buffer.Minimum(start,count));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Find minimum of a specified buffer |
|
|
//+------------------------------------------------------------------+
|
|
double CIndicator::MinValue(const int buffer_num,const int start,const int count,int &index) const
|
|
{
|
|
int idx=Minimum(buffer_num,start,count);
|
|
double res=EMPTY_VALUE;
|
|
//--- check
|
|
if(idx!=-1)
|
|
{
|
|
CIndicatorBuffer *buffer=At(buffer_num);
|
|
res=buffer.At(idx);
|
|
index=idx;
|
|
}
|
|
//---
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Find maximum of a specified buffer |
|
|
//+------------------------------------------------------------------+
|
|
int CIndicator::Maximum(const int buffer_num,const int start,const int count) const
|
|
{
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(-1);
|
|
}
|
|
if(buffer_num>=m_buffers_total)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_BUFF_NUM);
|
|
return(-1);
|
|
}
|
|
//---
|
|
CIndicatorBuffer *buffer=At(buffer_num);
|
|
if(buffer==NULL)
|
|
return(-1);
|
|
//---
|
|
return(buffer.Maximum(start,count));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Find maximum of specified buffer |
|
|
//+------------------------------------------------------------------+
|
|
double CIndicator::MaxValue(const int buffer_num,const int start,const int count,int &index) const
|
|
{
|
|
int idx=Maximum(buffer_num,start,count);
|
|
double res=EMPTY_VALUE;
|
|
//--- check
|
|
if(idx!=-1)
|
|
{
|
|
CIndicatorBuffer *buffer=At(buffer_num);
|
|
res=buffer.At(idx);
|
|
index=idx;
|
|
}
|
|
//---
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Creating data buffers of indicator |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicator::CreateBuffers(const string symbol,const ENUM_TIMEFRAMES period,const int buffers)
|
|
{
|
|
bool result=true;
|
|
//--- check
|
|
if(m_handle==INVALID_HANDLE)
|
|
{
|
|
SetUserError(ERR_USER_INVALID_HANDLE);
|
|
return(false);
|
|
}
|
|
if(buffers==0)
|
|
return(false);
|
|
if(!Reserve(buffers))
|
|
return(false);
|
|
//---
|
|
for(int i=0;i<buffers;i++)
|
|
result&=Add(new CIndicatorBuffer);
|
|
//---
|
|
if(result)
|
|
m_buffers_total=buffers;
|
|
//---
|
|
return(result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Set size of buffers of indicator |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicator::BufferResize(const int size)
|
|
{
|
|
if(size>m_buffer_size && !CSeries::BufferResize(size))
|
|
return(false);
|
|
//-- history is avalible
|
|
int total=Total();
|
|
for(int i=0;i<total;i++)
|
|
{
|
|
CIndicatorBuffer *buff=At(i);
|
|
//--- check pointer
|
|
if(buff==NULL)
|
|
return(false);
|
|
buff.Size(size);
|
|
}
|
|
//--- ok
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Refreshing data of indicator |
|
|
//+------------------------------------------------------------------+
|
|
void CIndicator::Refresh(const int flags)
|
|
{
|
|
int i;
|
|
CIndicatorBuffer *buff;
|
|
//--- refreshing buffers
|
|
for(i=0;i<Total();i++)
|
|
{
|
|
buff=At(i);
|
|
if(m_redrawer)
|
|
{
|
|
buff.Refresh(m_handle,i);
|
|
continue;
|
|
}
|
|
if(!(flags&m_timeframe_flags))
|
|
{
|
|
if(m_refresh_current)
|
|
buff.RefreshCurrent(m_handle,i);
|
|
}
|
|
else
|
|
buff.Refresh(m_handle,i);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Adds indicator to chart |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicator::AddToChart(const long chart,const int subwin)
|
|
{
|
|
if(ChartIndicatorAdd(chart,subwin,m_handle))
|
|
{
|
|
m_name=ChartIndicatorName(chart,subwin,ChartIndicatorsTotal(chart,subwin)-1);
|
|
return(true);
|
|
}
|
|
//--- failed
|
|
return(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Deletes indicator from chart |
|
|
//+------------------------------------------------------------------+
|
|
bool CIndicator::DeleteFromChart(const long chart,const int subwin)
|
|
{
|
|
return(ChartIndicatorDelete(chart,subwin,m_name));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Converting value of ENUM_MA_METHOD into string |
|
|
//+------------------------------------------------------------------+
|
|
string CIndicator::MethodDescription(const int val)
|
|
{
|
|
//--- select by value
|
|
switch(val)
|
|
{
|
|
case ENUM_MA_METHOD::MODE_SMA:
|
|
return("SMA");
|
|
case ENUM_MA_METHOD::MODE_EMA:
|
|
return("EMA");
|
|
case ENUM_MA_METHOD::MODE_SMMA:
|
|
return("SMMA");
|
|
case ENUM_MA_METHOD::MODE_LWMA:
|
|
return("LWMA");
|
|
}
|
|
//--- wrong value
|
|
return("MethodUnknown="+IntegerToString(val));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Converting value of ENUM_APPLIED_PRICE into string |
|
|
//+------------------------------------------------------------------+
|
|
string CIndicator::PriceDescription(const int val)
|
|
{
|
|
//--- select by value
|
|
switch(val)
|
|
{
|
|
case ENUM_APPLIED_PRICE::PRICE_CLOSE:
|
|
return("Close");
|
|
case ENUM_APPLIED_PRICE::PRICE_OPEN:
|
|
return("Open");
|
|
case ENUM_APPLIED_PRICE::PRICE_HIGH:
|
|
return("High");
|
|
case ENUM_APPLIED_PRICE::PRICE_LOW:
|
|
return("Low");
|
|
case ENUM_APPLIED_PRICE::PRICE_MEDIAN:
|
|
return("Median");
|
|
case ENUM_APPLIED_PRICE::PRICE_TYPICAL:
|
|
return("Typical");
|
|
case ENUM_APPLIED_PRICE::PRICE_WEIGHTED:
|
|
return("Weighted");
|
|
default:
|
|
//--- is an indicator handle
|
|
if(val>=10)
|
|
return("AppliedHandle="+IntegerToString(val));
|
|
//---
|
|
break;
|
|
}
|
|
//--- wrong value
|
|
return("PriceUnknown="+IntegerToString(val));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Converting value of ENUM_APPLIED_VOLUME into string |
|
|
//+------------------------------------------------------------------+
|
|
string CIndicator::VolumeDescription(const int val)
|
|
{
|
|
//--- select by value
|
|
switch(val)
|
|
{
|
|
case ENUM_APPLIED_VOLUME::VOLUME_TICK:
|
|
return("Tick");
|
|
case ENUM_APPLIED_VOLUME::VOLUME_REAL:
|
|
return("Real");
|
|
}
|
|
//--- wrong value
|
|
return("VolumeUnknown="+IntegerToString(val));
|
|
}
|
|
//+------------------------------------------------------------------+
|