diff --git a/Include/MyIncludes/TDI_CMO_Calculator.mqh b/Include/MyIncludes/TDI_CMO_Calculator.mqh index 5264a48..9d284f2 100644 --- a/Include/MyIncludes/TDI_CMO_Calculator.mqh +++ b/Include/MyIncludes/TDI_CMO_Calculator.mqh @@ -1,209 +1,211 @@ //+------------------------------------------------------------------+ //| TDI_CMO_Calculator.mqh | //| Calculation engine for TDI based on CMO. | +//| VERSION 2.00: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" -#include +#include +#include +//+==================================================================+ +//| CLASS 1: CTDICMOCalculator (Base Class) | //+==================================================================+ class CTDICMOCalculator { protected: int m_cmo_period, m_price_period, m_signal_period, m_base_period; double m_std_dev; - double m_price[]; - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Engines + CCMOCalculator *m_cmo_calculator; + CMovingAverageCalculator m_price_line_engine; + CMovingAverageCalculator m_signal_line_engine; + CMovingAverageCalculator m_base_line_engine; + + //--- Persistent Buffers + double m_cmo_buffer[]; + double m_cmo_rescaled[]; + double m_price_line[]; + double m_base_line[]; + + virtual bool PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); public: - CTDICMOCalculator(void) {}; - virtual ~CTDICMOCalculator(void) {}; + CTDICMOCalculator(void); + virtual ~CTDICMOCalculator(void); - bool Init(int cmo_p, int price_p, int signal_p, int base_p, double dev); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], + //--- Init now takes MA types (optional, default to SMA for classic TDI) + bool Init(int cmo_p, int price_p, int signal_p, int base_p, double dev, ENUM_MA_TYPE ma_type = SMA); + + //--- Updated: Accepts prev_calculated + void Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &price_line_out[], double &signal_line_out[], double &base_line_out[], double &upper_band_out[], double &lower_band_out[]); }; //+------------------------------------------------------------------+ -bool CTDICMOCalculator::Init(int cmo_p, int price_p, int signal_p, int base_p, double dev) +//| Constructor | +//+------------------------------------------------------------------+ +CTDICMOCalculator::CTDICMOCalculator(void) + { + m_cmo_calculator = new CCMOCalculator(); + } + +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTDICMOCalculator::~CTDICMOCalculator(void) + { + if(CheckPointer(m_cmo_calculator) != POINTER_INVALID) + delete m_cmo_calculator; + } + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool CTDICMOCalculator::Init(int cmo_p, int price_p, int signal_p, int base_p, double dev, ENUM_MA_TYPE ma_type) { m_cmo_period = (cmo_p < 1) ? 1 : cmo_p; m_price_period = (price_p < 1) ? 1 : price_p; m_signal_period = (signal_p < 1) ? 1 : signal_p; m_base_period = (base_p < 1) ? 1 : base_p; m_std_dev = (dev <= 0) ? 1.618 : dev; + + if(CheckPointer(m_cmo_calculator) == POINTER_INVALID) + return false; + if(!m_cmo_calculator.Init(m_cmo_period)) + return false; + +// Initialize MA Engines (Classic TDI uses SMA, but we allow override) + if(!m_price_line_engine.Init(m_price_period, ma_type)) + return false; + if(!m_signal_line_engine.Init(m_signal_period, ma_type)) + return false; + if(!m_base_line_engine.Init(m_base_period, ma_type)) + return false; + return true; } //+------------------------------------------------------------------+ -void CTDICMOCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], +//| Main Calculation (Optimized) | +//+------------------------------------------------------------------+ +void CTDICMOCalculator::Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &price_line_out[], double &signal_line_out[], double &base_line_out[], double &upper_band_out[], double &lower_band_out[]) { +// Minimum bars check if(rates_total <= m_cmo_period + m_base_period) return; - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) + if(CheckPointer(m_cmo_calculator) == POINTER_INVALID) return; - double cmo_rescaled[]; - ArrayResize(cmo_rescaled, rates_total); + int start_index = (prev_calculated == 0) ? 0 : prev_calculated - 1; -//--- STEP 1: Calculate CMO and rescale it to 0-100 range - for(int i = m_cmo_period; i < rates_total; i++) +// Resize Buffers + if(ArraySize(m_cmo_buffer) != rates_total) { - double sum_up = 0.0, sum_down = 0.0; - for(int j = 0; j < m_cmo_period; j++) - { - double diff = m_price[i - j] - m_price[i - j - 1]; - if(diff > 0.0) - sum_up += diff; - else - sum_down += (-diff); - } - double total_sum = sum_up + sum_down; - double raw_cmo = (total_sum == 0.0) ? 0.0 : 100.0 * (sum_up - sum_down) / total_sum; - - //--- CRITICAL: Rescale CMO from [-100, 100] to [0, 100] - cmo_rescaled[i] = (raw_cmo + 100.0) / 2.0; + ArrayResize(m_cmo_buffer, rates_total); + ArrayResize(m_cmo_rescaled, rates_total); + ArrayResize(m_price_line, rates_total); + ArrayResize(m_base_line, rates_total); } -//--- STEP 2: Calculate Price Line (SMA on Rescaled CMO) - for(int i = m_cmo_period + m_price_period - 2; i < rates_total; i++) + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + +//--- 1. Calculate CMO (Incremental) + m_cmo_calculator.Calculate(rates_total, prev_calculated, price_type, open, high, low, close, m_cmo_buffer); + +//--- 2. Rescale CMO to 0-100 range + int loop_start_cmo = MathMax(m_cmo_period, start_index); + for(int i = loop_start_cmo; i < rates_total; i++) { - double sum=0; - for(int j=0; j