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