mql5/Experts/_FrameWork/Market/Indicator.mqh

195 lines
6.8 KiB
MQL5

2026-09-30 09:06:59 +02:00
//+------------------------------------------------------------------+
//| 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 &params[], 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 &params[], 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];
}
//+------------------------------------------------------------------+