mql5/Experts/Advisors/DualEA/Include/CIndicatorCache.mqh

221 lines
6.1 KiB
MQL5
Raw Permalink Normal View History

2026-02-24 12:47:37 -05:00
//+------------------------------------------------------------------+
//| CIndicatorCache.mqh - Technical Indicator Cache |
//| Pre-warms and caches indicator values for performance |
//+------------------------------------------------------------------+
#ifndef CINDICATORCACHE_MQH
#define CINDICATORCACHE_MQH
#include "CDualEAController.mqh" // For ENUM_INDICATOR_TYPE
//+------------------------------------------------------------------+
//| Indicator Cache Entry |
//+------------------------------------------------------------------+
struct SIndicatorCacheEntry
{
string symbol;
ENUM_TIMEFRAMES timeframe;
ENUM_INDICATOR_TYPE type;
int period;
double value;
datetime last_update;
int handle;
bool valid;
};
//+------------------------------------------------------------------+
//| Indicator Cache Class |
//+------------------------------------------------------------------+
class CIndicatorCache
{
private:
SIndicatorCacheEntry m_entries[];
int m_entry_count;
int m_max_entries;
int m_cache_ttl_seconds;
int FindEntry(const string symbol, ENUM_TIMEFRAMES tf, ENUM_INDICATOR_TYPE type, int period)
{
for(int i = 0; i < m_entry_count; i++)
{
if(m_entries[i].symbol == symbol &&
m_entries[i].timeframe == tf &&
m_entries[i].type == type &&
m_entries[i].period == period)
{
return i;
}
}
return -1;
}
double CalculateIndicator(ENUM_INDICATOR_TYPE type, int period, const string symbol, ENUM_TIMEFRAMES tf)
{
double result = 0.0;
switch(type)
{
case INDI_MA:
{
int handle = iMA(symbol, tf, period, 0, MODE_SMA, PRICE_CLOSE);
if(handle != INVALID_HANDLE)
{
double ma[];
if(CopyBuffer(handle, 0, 0, 1, ma) > 0)
result = ma[0];
IndicatorRelease(handle);
}
break;
}
case INDI_RSI:
{
int handle = iRSI(symbol, tf, period, PRICE_CLOSE);
if(handle != INVALID_HANDLE)
{
double rsi[];
if(CopyBuffer(handle, 0, 0, 1, rsi) > 0)
result = rsi[0];
IndicatorRelease(handle);
}
break;
}
case INDI_ATR:
{
int handle = iATR(symbol, tf, period);
if(handle != INVALID_HANDLE)
{
double atr[];
if(CopyBuffer(handle, 0, 0, 1, atr) > 0)
result = atr[0];
IndicatorRelease(handle);
}
break;
}
case INDI_MACD:
{
int handle = iMACD(symbol, tf, 12, 26, 9, PRICE_CLOSE);
if(handle != INVALID_HANDLE)
{
double macd[];
if(CopyBuffer(handle, 0, 0, 1, macd) > 0)
result = macd[0];
IndicatorRelease(handle);
}
break;
}
case INDI_ADX:
{
int handle = iADX(symbol, tf, period);
if(handle != INVALID_HANDLE)
{
double adx[];
if(CopyBuffer(handle, 0, 0, 1, adx) > 0)
result = adx[0];
IndicatorRelease(handle);
}
break;
}
default:
result = 0.0;
}
return result;
}
public:
CIndicatorCache()
{
m_entry_count = 0;
m_max_entries = 100;
m_cache_ttl_seconds = 5;
ArrayResize(m_entries, 0);
}
~CIndicatorCache()
{
Clear();
}
void Clear()
{
// Release all indicator handles
for(int i = 0; i < m_entry_count; i++)
{
if(m_entries[i].handle != INVALID_HANDLE)
{
IndicatorRelease(m_entries[i].handle);
}
}
ArrayResize(m_entries, 0);
m_entry_count = 0;
}
bool PreWarmIndicator(const string symbol, ENUM_TIMEFRAMES tf, ENUM_INDICATOR_TYPE type, int period)
{
// Check if already cached
int idx = FindEntry(symbol, tf, type, period);
if(idx >= 0)
return true;
// Add new entry
if(m_entry_count >= m_max_entries)
{
Print("[IndicatorCache] Warning: Cache full, cannot pre-warm " + IntegerToString(type));
return false;
}
idx = m_entry_count;
ArrayResize(m_entries, idx + 1);
m_entries[idx].symbol = symbol;
m_entries[idx].timeframe = tf;
m_entries[idx].type = type;
m_entries[idx].period = period;
m_entries[idx].value = CalculateIndicator(type, period, symbol, tf);
m_entries[idx].last_update = TimeCurrent();
m_entries[idx].handle = INVALID_HANDLE;
m_entries[idx].valid = true;
m_entry_count++;
return true;
}
double GetIndicatorValue(const string symbol, ENUM_TIMEFRAMES tf, ENUM_INDICATOR_TYPE type, int period)
{
int idx = FindEntry(symbol, tf, type, period);
if(idx >= 0)
{
// Check if cache is still valid
datetime now = TimeCurrent();
if(now - m_entries[idx].last_update < m_cache_ttl_seconds)
{
return m_entries[idx].value;
}
// Refresh cache
m_entries[idx].value = CalculateIndicator(type, period, symbol, tf);
m_entries[idx].last_update = now;
return m_entries[idx].value;
}
// Not in cache, calculate directly
return CalculateIndicator(type, period, symbol, tf);
}
void InvalidateCache()
{
for(int i = 0; i < m_entry_count; i++)
{
m_entries[i].valid = false;
}
}
int GetCacheSize() const { return m_entry_count; }
void SetCacheTTL(int seconds) { m_cache_ttl_seconds = seconds; }
};
// Global pointer for P0-P5 integration
CIndicatorCache* g_indicator_cache = NULL;
#endif // CINDICATORCACHE_MQH