diff --git a/Include/MyIncludes/VolumePressure_Calculator.mqh b/Include/MyIncludes/VolumePressure_Calculator.mqh new file mode 100644 index 0000000..eafc570 --- /dev/null +++ b/Include/MyIncludes/VolumePressure_Calculator.mqh @@ -0,0 +1,114 @@ +//+------------------------------------------------------------------+ +//| VolumePressure_Calculator.mqh| +//| Engine for Volume Pressure (Money Flow Multiplier). | +//| Proxy for Tick Volume Delta (-1.0 to 1.0). | +//| Copyright 2026, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2026, xxxxxxxx" + +#include + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class CVolumePressureCalculator + { +protected: + // Optional Smoothing + CMovingAverageCalculator *m_ma; + int m_smooth_period; + + double m_raw_mfm[]; // Raw Money Flow Multiplier + +public: + CVolumePressureCalculator(); + ~CVolumePressureCalculator(); + + bool Init(int smooth_period); + + void Calculate(int rates_total, int prev_calculated, + const double &high[], const double &low[], const double &close[], + double &out_vpres[]); + }; + +//+------------------------------------------------------------------+ +CVolumePressureCalculator::CVolumePressureCalculator() : m_ma(NULL) {} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +CVolumePressureCalculator::~CVolumePressureCalculator() + { + if(CheckPointer(m_ma)==POINTER_DYNAMIC) + delete m_ma; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool CVolumePressureCalculator::Init(int smooth_period) + { + m_smooth_period = (smooth_period < 1) ? 1 : smooth_period; + + if(m_smooth_period > 1) + { + m_ma = new CMovingAverageCalculator(); + // EMA smoothing for reactiveness + if(!m_ma.Init(m_smooth_period, EMA)) + return false; + } + return true; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void CVolumePressureCalculator::Calculate(int rates_total, int prev_calculated, + const double &high[], const double &low[], const double &close[], + double &out_vpres[]) + { + if(rates_total < 2) + return; + + if(ArraySize(m_raw_mfm) != rates_total) + ArrayResize(m_raw_mfm, rates_total); + + int start = (prev_calculated > 0) ? prev_calculated - 1 : 0; + + for(int i = start; i < rates_total; i++) + { + double range = high[i] - low[i]; + double mfm = 0; + + if(range > 1.0e-9) // Prevent div/0 + { + // Formula: ( (C-L) - (H-C) ) / (H-L) + // Simplified: (2*C - H - L) / (H - L) + mfm = (2.0 * close[i] - high[i] - low[i]) / range; + } + else + { + mfm = 0.0; // Flat bar (Doji with no range) + } + + // Clamp just in case + if(mfm > 1.0) + mfm = 1.0; + if(mfm < -1.0) + mfm = -1.0; + + m_raw_mfm[i] = mfm; + + // Direct output if no smoothing + if(m_smooth_period <= 1) + out_vpres[i] = mfm; + } + +// Apply Smoothing if requested + if(m_smooth_period > 1 && CheckPointer(m_ma) != POINTER_INVALID) + { + m_ma.CalculateOnArray(rates_total, prev_calculated, m_raw_mfm, out_vpres); + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+