221 lines
6.1 KiB
MQL5
221 lines
6.1 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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
|