//+------------------------------------------------------------------+ //| VolatilityManager.mqh | //| Copyright 2025, EscapeEA Team | //| https://www.escapeea.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, EscapeEA Team" #property link "https://www.escapeea.com" #property version "1.00" #property strict #include //+------------------------------------------------------------------+ //| Volatility Calculation Methods | //+------------------------------------------------------------------+ enum ENUM_VOLATILITY_METHOD { VOL_ATR, // Average True Range VOL_STD_DEV, // Standard Deviation VOL_PARKINSON, // Parkinson's volatility VOL_GK, // Garman-Klass volatility VOL_RS, // Rogers-Satchell volatility VOL_YZ // Yang-Zhang volatility }; //+------------------------------------------------------------------+ //| Volatility Manager Class | //+------------------------------------------------------------------+ class CVolatilityManager { private: // Configuration ENUM_TIMEFRAMES m_timeframe; // Default timeframe for calculations int m_period; // Default period for calculations ENUM_VOLATILITY_METHOD m_method; // Default calculation method // State bool m_initialized; // Initialization flag // Cache double m_lastValues[]; // Cache of last calculated values datetime m_lastUpdate; // Last update time public: //--- Constructor/Destructor CVolatilityManager(void); ~CVolatilityManager(void); //--- Initialization bool Initialize(void); void Shutdown(void); //--- Volatility Calculation double GetVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method, const int shift=0); double GetCurrentVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method); double GetAverageVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int bars, const ENUM_VOLATILITY_METHOD method); //--- Configuration void SetDefaultTimeframe(const ENUM_TIMEFRAMES timeframe) { m_timeframe = timeframe; } void SetDefaultPeriod(const int period) { m_period = period; } void SetDefaultMethod(const ENUM_VOLATILITY_METHOD method) { m_method = method; } private: //--- Calculation Methods double CalculateATR(const string symbol, const int period, const int shift); double CalculateStdDev(const string symbol, const int period, const int shift); double CalculateParkinson(const string symbol, const int period, const int shift); double CalculateGarmanKlass(const string symbol, const int period, const int shift); double CalculateRogersSatchell(const string symbol, const int period, const int shift); double CalculateYangZhang(const string symbol, const int period, const int shift); //--- Helper Methods void UpdateCache(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method); string GenerateCacheKey(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method) const; double GetCachedValue(const string key); void SetCachedValue(const string key, const double value); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CVolatilityManager::CVolatilityManager(void) : m_timeframe(PERIOD_CURRENT), m_period(14), m_method(VOL_ATR), m_initialized(false), m_lastUpdate(0) { ArrayResize(m_lastValues, 0); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CVolatilityManager::~CVolatilityManager(void) { Shutdown(); } //+------------------------------------------------------------------+ //| Initialize the volatility manager | //+------------------------------------------------------------------+ bool CVolatilityManager::Initialize(void) { if(m_initialized) return true; // Initialize any required resources m_initialized = true; return true; } //+------------------------------------------------------------------+ //| Shutdown the volatility manager | //+------------------------------------------------------------------+ void CVolatilityManager::Shutdown(void) { if(!m_initialized) return; // Clean up resources ArrayFree(m_lastValues); m_initialized = false; } //+------------------------------------------------------------------+ //| Get volatility using specified parameters | //+------------------------------------------------------------------+ double CVolatilityManager::GetVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method, const int shift) { // Check for valid parameters if(period <= 0) { CErrorHandler::HandleError(ERR_INVALID_PARAMETER, "Invalid period: " + IntegerToString(period)); return 0.0; } // Use default values if not specified ENUM_TIMEFRAMES tf = (timeframe == PERIOD_CURRENT) ? m_timeframe : timeframe; int p = (period <= 0) ? m_period : period; ENUM_VOLATILITY_METHOD m = (method == -1) ? m_method : method; // Calculate volatility based on selected method double volatility = 0.0; switch(m) { case VOL_ATR: volatility = CalculateATR(symbol, p, shift); break; case VOL_STD_DEV: volatility = CalculateStdDev(symbol, p, shift); break; case VOL_PARKINSON: volatility = CalculateParkinson(symbol, p, shift); break; case VOL_GK: volatility = CalculateGarmanKlass(symbol, p, shift); break; case VOL_RS: volatility = CalculateRogersSatchell(symbol, p, shift); break; case VOL_YZ: volatility = CalculateYangZhang(symbol, p, shift); break; default: CErrorHandler::HandleError(ERR_INVALID_PARAMETER, "Unknown volatility method: " + IntegerToString(m)); break; } return volatility; } //+------------------------------------------------------------------+ //| Get current volatility | //+------------------------------------------------------------------+ double CVolatilityManager::GetCurrentVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method) { return GetVolatility(symbol, timeframe, period, method, 0); } //+------------------------------------------------------------------+ //| Get average volatility over a number of bars | //+------------------------------------------------------------------+ double CVolatilityManager::GetAverageVolatility(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const int bars, const ENUM_VOLATILITY_METHOD method) { if(bars <= 0) { CErrorHandler::HandleError(ERR_INVALID_PARAMETER, "Invalid number of bars: " + IntegerToString(bars)); return 0.0; } double sum = 0.0; int count = 0; // Calculate average volatility over the specified number of bars for(int i = 0; i < bars; i++) { double vol = GetVolatility(symbol, timeframe, period, method, i); if(vol > 0) { sum += vol; count++; } } return (count > 0) ? sum / count : 0.0; } //+------------------------------------------------------------------+ //| Calculate Average True Range (ATR) | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateATR(const string symbol, const int period, const int shift) { double atr = iATR(symbol, m_timeframe, period, shift); if(atr == 0) { CErrorHandler::HandleError(ERR_INDICATOR_CALCULATION, "Failed to calculate ATR for " + symbol); return 0.0; } return atr; } //+------------------------------------------------------------------+ //| Calculate Standard Deviation | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateStdDev(const string symbol, const int period, const int shift) { double close[]; ArraySetAsSeries(close, true); // Get close prices if(CopyClose(symbol, m_timeframe, shift, period, close) != period) { CErrorHandler::HandleError(ERR_HISTORY_NOT_FOUND, "Failed to get close prices for " + symbol); return 0.0; } // Calculate mean double sum = 0.0; for(int i = 0; i < period; i++) sum += close[i]; double mean = sum / period; // Calculate variance double variance = 0.0; for(int i = 0; i < period; i++) variance += MathPow(close[i] - mean, 2); variance /= period; // Standard deviation is the square root of variance return MathSqrt(variance); } //+------------------------------------------------------------------+ //| Calculate Parkinson Volatility | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateParkinson(const string symbol, const int period, const int shift) { double high[], low[]; ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); // Get high and low prices if(CopyHigh(symbol, m_timeframe, shift, period, high) != period || CopyLow(symbol, m_timeframe, shift, period, low) != period) { CErrorHandler::HandleError(ERR_HISTORY_NOT_FOUND, "Failed to get price data for Parkinson"); return 0.0; } // Calculate Parkinson volatility double sum = 0.0; for(int i = 0; i < period; i++) { if(high[i] > 0 && low[i] > 0) sum += MathLog(high[i] / low[i]) * MathLog(high[i] / low[i]); } return MathSqrt(sum / (4 * period * MathLog(2))); } //+------------------------------------------------------------------+ //| Calculate Garman-Klass Volatility | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateGarmanKlass(const string symbol, const int period, const int shift) { double open[], high[], low[], close[]; ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); // Get price data if(CopyOpen(symbol, m_timeframe, shift, period, open) != period || CopyHigh(symbol, m_timeframe, shift, period, high) != period || CopyLow(symbol, m_timeframe, shift, period, low) != period || CopyClose(symbol, m_timeframe, shift, period, close) != period) { CErrorHandler::HandleError(ERR_HISTORY_NOT_FOUND, "Failed to get price data for Garman-Klass"); return 0.0; } // Calculate Garman-Klass volatility double sum = 0.0; for(int i = 0; i < period; i++) { if(open[i] > 0 && high[i] > 0 && low[i] > 0 && close[i] > 0) { double u = MathLog(high[i] / open[i]); double d = MathLog(low[i] / open[i]); double c = MathLog(close[i] / open[i]); sum += 0.511 * (u - d) * (u - d) - 0.019 * (c * (u + d) - 2 * u * d) - 0.383 * c * c; } } return MathSqrt(sum / period); } //+------------------------------------------------------------------+ //| Calculate Rogers-Satchell Volatility | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateRogersSatchell(const string symbol, const int period, const int shift) { double open[], high[], low[], close[]; ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); // Get price data if(CopyOpen(symbol, m_timeframe, shift, period, open) != period || CopyHigh(symbol, m_timeframe, shift, period, high) != period || CopyLow(symbol, m_timeframe, shift, period, low) != period || CopyClose(symbol, m_timeframe, shift, period, close) != period) { CErrorHandler::HandleError(ERR_HISTORY_NOT_FOUND, "Failed to get price data for Rogers-Satchell"); return 0.0; } // Calculate Rogers-Satchell volatility double sum = 0.0; for(int i = 0; i < period; i++) { if(open[i] > 0 && high[i] > 0 && low[i] > 0 && close[i] > 0) { double u = MathLog(high[i] / open[i]); double d = MathLog(low[i] / open[i]); double c = MathLog(close[i] / open[i]); sum += u * (u - c) + d * (d - c); } } return MathSqrt(sum / period); } //+------------------------------------------------------------------+ //| Calculate Yang-Zhang Volatility | //+------------------------------------------------------------------+ double CVolatilityManager::CalculateYangZhang(const string symbol, const int period, const int shift) { double open[], close[]; ArraySetAsSeries(open, true); ArraySetAsSeries(close, true); // Get open and close prices if(CopyOpen(symbol, m_timeframe, shift, period, open) != period || CopyClose(symbol, m_timeframe, shift-1, period+1, close) != period+1) { CErrorHandler::HandleError(ERR_HISTORY_NOT_FOUND, "Failed to get price data for Yang-Zhang"); return 0.0; } // Calculate Yang-Zhang volatility double sum_var = 0.0; double sum_mean = 0.0; for(int i = 0; i < period; i++) { if(open[i] > 0 && close[i] > 0 && close[i+1] > 0) { double o = MathLog(open[i] / close[i+1]); double c = MathLog(close[i] / open[i]); double u = MathLog(high[i] / open[i]); double d = MathLog(low[i] / open[i]); double rs = u * (u - c) + d * (d - c); double o_c = o * o; double c_c = c * c; sum_var += 0.511 * rs - 0.019 * (c * (u + d) - 2 * u * d) - 0.383 * c_c; sum_mean += o_c; } } double k = 0.34 / (1.34 + (period + 1) / (period - 1)); return MathSqrt(sum_var / period + k * sum_mean / (period - 1)); } //+------------------------------------------------------------------+ //| Update the cache with latest values | //+------------------------------------------------------------------+ void CVolatilityManager::UpdateCache(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method) { // Implementation for caching would go here // This is a placeholder for actual caching logic } //+------------------------------------------------------------------+ //| Generate a cache key | //+------------------------------------------------------------------+ string CVolatilityManager::GenerateCacheKey(const string symbol, const ENUM_TIMEFRAMES timeframe, const int period, const ENUM_VOLATILITY_METHOD method) const { return symbol + "_" + IntegerToString(timeframe) + "_" + IntegerToString(period) + "_" + IntegerToString(method); } //+------------------------------------------------------------------+ //| Get a value from cache | //+------------------------------------------------------------------+ double CVolatilityManager::GetCachedValue(const string key) { // Implementation for getting cached values would go here // This is a placeholder for actual caching logic return 0.0; } //+------------------------------------------------------------------+ //| Set a value in cache | //+------------------------------------------------------------------+ void CVolatilityManager::SetCachedValue(const string key, const double value) { // Implementation for setting cached values would go here // This is a placeholder for actual caching logic } //+------------------------------------------------------------------+