453 lines
17 KiB
MQL5
453 lines
17 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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 <Escape/Common/ErrorHandler.mqh>
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|