195 lines
6.8 KiB
MQL5
195 lines
6.8 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| Indicator.mqh |
| |
//| Copyright 2026, Concrete Goonies |
| |
//| https://concrete-goonies.web.app |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2026, Concrete Goonies"
| |
#property link "https://concrete-goonies.web.app"
| |
#property version "1.00"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class Indicator
| |
{
| |
private:
| |
| |
string m_symbol;
| |
| |
ENUM_TIMEFRAMES m_tf;
| |
int m_handle;
| |
| |
| |
MqlParam m_params[];
| |
double m_buffers[]; // flat: buffersCount * barsCount
| |
| |
bool RecreateHandle();
| |
bool Initialize(string symbol, ENUM_TIMEFRAMES tf, string name, int handle, int buffersCount, int initialBars, bool asSeries);
| |
| |
public:
| |
Indicator();
| |
~Indicator();
| |
int m_barsCount;
| |
int m_buffersCount;
| |
bool m_asSeries;
| |
string m_name;
| |
| |
bool Initialize(string symbol, ENUM_TIMEFRAMES tf, string name, int buffersCount, int initialBars, bool asSeries = true);
| |
bool Initialize(string symbol, ENUM_TIMEFRAMES tf, string name, int buffersCount, int initialBars, const MqlParam ¶ms[], bool asSeries = true);
| |
bool Update(int barsCount = 3);
| |
| |
double Value(int bufferIndex, int pShift);
| |
| |
};
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
Indicator::Indicator(): m_handle(INVALID_HANDLE),
| |
m_buffersCount(0),
| |
m_barsCount(0),
| |
m_asSeries(true),
| |
m_symbol(""),
| |
m_name(""),
| |
m_tf(PERIOD_CURRENT)
| |
{
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
Indicator::~Indicator()
| |
{
| |
if(m_handle != INVALID_HANDLE)
| |
{
| |
IndicatorRelease(m_handle);
| |
m_handle = INVALID_HANDLE;
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
bool Indicator::Initialize(string symbol, ENUM_TIMEFRAMES tf, string name, int handle, int buffersCount, int initialBars, bool asSeries)
| |
{
| |
m_symbol = symbol;
| |
m_tf = tf;
| |
m_name = name;
| |
m_handle = handle;
| |
m_buffersCount = buffersCount;
| |
m_asSeries = asSeries;
| |
| |
ArrayFree(m_params);
| |
| |
if(m_handle == INVALID_HANDLE)
| |
{
| |
PrintFormat("IndicatorSeries::Initialize failed: invalid handle | %s %s | %s",
| |
m_symbol, EnumToString(m_tf), m_name);
| |
return false;
| |
}
| |
| |
return Update(initialBars);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Overload 2: iCustom without extra parameters |
| |
//+------------------------------------------------------------------+
| |
bool Indicator::Initialize(string symbol, ENUM_TIMEFRAMES tf, string name,
| |
int buffersCount, int initialBars, bool asSeries)
| |
{
| |
int handle = iCustom(symbol, tf, name);
| |
| |
if(handle == INVALID_HANDLE)
| |
{
| |
PrintFormat("IndicatorSeries::Initialize failed: iCustom | %s %s | %s | Error=%d",
| |
symbol, EnumToString(tf), name, GetLastError());
| |
return false;
| |
}
| |
| |
return Initialize(symbol, tf, name, handle, buffersCount, initialBars, asSeries);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Overload 3: Initialization with MqlParam array (custom indicator)|
| |
//+------------------------------------------------------------------+
| |
bool Indicator::Initialize(string symbol, ENUM_TIMEFRAMES tf, string name, int buffersCount, int initialBars, const MqlParam ¶ms[], bool asSeries)
| |
{
| |
m_symbol = symbol;
| |
m_tf = tf;
| |
m_name = name;
| |
m_buffersCount = buffersCount;
| |
m_asSeries = asSeries;
| |
| |
ArrayFree(m_params);
| |
| |
int srcSize = ArraySize(params);
| |
if(ArrayResize(m_params, srcSize + 1) != srcSize + 1)
| |
return false;
| |
| |
// First parameter = custom indicator name (required for IndicatorCreate)
| |
m_params[0].type = TYPE_STRING;
| |
m_params[0].string_value = m_name;
| |
| |
// Copy the remaining parameters
| |
for(int i = 0; i < srcSize; i++)
| |
m_params[i + 1] = params[i];
| |
| |
if(!RecreateHandle())
| |
{
| |
PrintFormat("IndicatorSeries::Initialize failed: RecreateHandle | %s %s | %s",
| |
m_symbol, EnumToString(m_tf), m_name);
| |
return false;
| |
}
| |
| |
return Update(initialBars);
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool Indicator::Update(int barsCount = 3)
| |
{
| |
if(barsCount <= 0 || m_buffersCount <= 0)
| |
return false;
| |
| |
if(m_handle == INVALID_HANDLE /*&& !RecreateHandle()*/)
| |
return false;
| |
| |
m_barsCount = barsCount;
| |
ArrayResize(m_buffers, m_buffersCount * m_barsCount);
| |
| |
// Temporary buffer – its series flag is set to match m_asSeries
| |
double tempBuffer[];
| |
ArraySetAsSeries(tempBuffer, m_asSeries);
| |
| |
for(int i = 0; i < m_buffersCount; i++)
| |
{
| |
int copied = CopyBuffer(m_handle, i, 0, m_barsCount, tempBuffer);
| |
if(copied != m_barsCount)
| |
return false;
| |
| |
int offset = i * m_barsCount;
| |
for(int j = 0; j < m_barsCount; j++)
| |
m_buffers[offset + j] = tempBuffer[j];
| |
}
| |
| |
return true;
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool Indicator::RecreateHandle()
| |
{
| |
if(ArraySize(m_params) > 0)
| |
m_handle = IndicatorCreate(m_symbol, m_tf, IND_CUSTOM, ArraySize(m_params), m_params);
| |
else
| |
m_handle = iCustom(m_symbol, m_tf, m_name);
| |
| |
return (m_handle != INVALID_HANDLE);
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
double Indicator::Value(int bufferIndex, int pShift)
| |
{
| |
if(bufferIndex < 0 || bufferIndex >= m_buffersCount ||
| |
pShift < 0 || pShift >= m_barsCount)
| |
return 0.0;
| |
| |
return m_buffers[(bufferIndex * m_barsCount) + pShift];
| |
}
| |
//+------------------------------------------------------------------+
|