diff --git a/Include/MyIncludes/BandStop_Calculator.mqh b/Include/MyIncludes/BandStop_Calculator.mqh new file mode 100644 index 0000000..acf74f6 --- /dev/null +++ b/Include/MyIncludes/BandStop_Calculator.mqh @@ -0,0 +1,178 @@ +//+------------------------------------------------------------------+ +//| BandStop_Calculator.mqh | +//| Calculation engine for the John Ehlers' Band-Stop Filter. | +//| Implemented by subtracting BandPass from Price. | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+==================================================================+ +//| | +//| CLASS 1: CBandStopCalculator (Base Class) | +//| | +//+==================================================================+ +class CBandStopCalculator + { +protected: + double m_price[]; + + // Filter parameters + int m_period; + double m_bandwidth; + + virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + +public: + CBandStopCalculator(void) {}; + virtual ~CBandStopCalculator(void) {}; + + bool Init(int period, double bandwidth_delta); + void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &filter_buffer[]); + }; + +//+------------------------------------------------------------------+ +bool CBandStopCalculator::Init(int period, double bandwidth_delta) + { + m_period = (period < 2) ? 2 : period; + m_bandwidth = bandwidth_delta; + if(m_bandwidth <= 0 || m_bandwidth >= 0.5) + { + Print("BandStop Filter: Invalid bandwidth. Must be > 0 and < 0.5"); + return false; + } + return true; + } + +//+------------------------------------------------------------------+ +void CBandStopCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &filter_buffer[]) + { + if(rates_total < 3) + return; + if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) + return; + +// --- Calculate Band-Pass filter first --- + double bp_buffer[]; + ArrayResize(bp_buffer, rates_total); + +// Band-Pass coefficients + double beta = cos(2.0 * M_PI / m_period); + double gamma = 1.0 / cos(4.0 * M_PI * m_bandwidth / m_period); + double alpha = gamma - sqrt(gamma * gamma - 1.0); + double c0 = (1.0 - alpha) / 2.0; + double a1 = beta * (1.0 + alpha); + double a2 = -alpha; + +// State variables for Band-Pass recursion + double bp1=0, bp2=0; + + for(int i = 2; i < rates_total; i++) + { + // Band-Pass formula: BP = c0*(Price - Price[2]) + a1*BP[1] + a2*BP[2] + double current_bp = c0 * (m_price[i] - m_price[i-2]) + a1 * bp1 + a2 * bp2; + bp_buffer[i] = current_bp; + + // Update state + bp2 = bp1; + bp1 = current_bp; + + // --- Final Step: Calculate Band-Stop by subtraction --- + filter_buffer[i] = m_price[i] - bp_buffer[i]; + } + +// Initialize early values + filter_buffer[0] = m_price[0]; + filter_buffer[1] = m_price[1]; + } + +//+------------------------------------------------------------------+ +bool CBandStopCalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) + { + ArrayResize(m_price, rates_total); + switch(price_type) + { + case PRICE_CLOSE: + ArrayCopy(m_price, close, 0, 0, rates_total); + break; + case PRICE_OPEN: + ArrayCopy(m_price, open, 0, 0, rates_total); + break; + case PRICE_HIGH: + ArrayCopy(m_price, high, 0, 0, rates_total); + break; + case PRICE_LOW: + ArrayCopy(m_price, low, 0, 0, rates_total); + break; + case PRICE_MEDIAN: + for(int i=0; i