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));
| |||
}
| |||
//+------------------------------------------------------------------+
|