diff --git a/Include/MyIncludes/Polynomial_Regression_Object_Calculator.mqh b/Include/MyIncludes/Polynomial_Regression_Object_Calculator.mqh index e550629..fbc22cc 100644 --- a/Include/MyIncludes/Polynomial_Regression_Object_Calculator.mqh +++ b/Include/MyIncludes/Polynomial_Regression_Object_Calculator.mqh @@ -1,13 +1,13 @@ //+------------------------------------------------------------------+ //| Polynomial_Regression_Object_Calculator.mqh | -//| VERSION 1.10: Added customizable colors. | +//| VERSION 1.30: Restored full recalc logic for regression. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include -//+================================----------------==================+ +//+==================================================================+ class CPolynomialRegressionObjectCalculator { protected: @@ -15,6 +15,7 @@ protected: double m_deviation; string m_prefix; color m_mid_color, m_upper_color, m_lower_color; + double m_price[]; int m_last_rates_total; @@ -26,26 +27,11 @@ public: virtual ~CPolynomialRegressionObjectCalculator(void) {}; bool Init(int period, double deviation, string prefix, color mid_clr, color upper_clr, color lower_clr); + + //--- Reverted: No prev_calculated needed for regression void Calculate(int rates_total, const datetime &time[], ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -class CPolynomialRegressionObjectCalculator_HA : public CPolynomialRegressionObjectCalculator - { -private: - CHeikinAshi_Calculator m_ha_calculator; -protected: - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) override; - }; - -//+==================================================================+ -//| METHOD IMPLEMENTATIONS | -//+==================================================================+ - -//+------------------------------------------------------------------+ -//| | //+------------------------------------------------------------------+ bool CPolynomialRegressionObjectCalculator::Init(int period, double deviation, string prefix, color mid_clr, color upper_clr, color lower_clr) { @@ -58,32 +44,31 @@ bool CPolynomialRegressionObjectCalculator::Init(int period, double deviation, s return true; } -//+------------------------------------------------------------------+ -//| | //+------------------------------------------------------------------+ void CPolynomialRegressionObjectCalculator::Calculate(int rates_total, const datetime &time[], ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - if(rates_total <= m_last_rates_total && rates_total > 0) - return; - m_last_rates_total = rates_total; +// Optimization: Only recalculate if rates_total changed (new bar) OR on every tick? +// Regression changes on every tick. So we must run. +// But we can skip if no new tick (handled by OnCalculate return). if(rates_total < m_period) return; + +// Always prepare full series (fast copy) if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) return; DrawChannelObjects(rates_total, time); } -//+------------------------------------------------------------------+ -//| | //+------------------------------------------------------------------+ void CPolynomialRegressionObjectCalculator::DrawChannelObjects(int rates_total, const datetime &time[]) { - ObjectsDeleteAll(0, m_prefix); +// We do NOT delete all objects here. We update them. int start_index = rates_total - m_period; +// --- Polynomial Regression Calculation --- double sum_x=0, sum_y=0, sum_x2=0, sum_xy=0, sum_x3=0, sum_x4=0, sum_x2y=0; for(int j = 0; j < m_period; j++) { @@ -101,8 +86,10 @@ void CPolynomialRegressionObjectCalculator::DrawChannelObjects(int rates_total, double a=0, b=0, c=0; double n = m_period; double D = n * (sum_x2 * sum_x4 - sum_x3 * sum_x3) - sum_x * (sum_x * sum_x4 - sum_x2 * sum_x3) + sum_x2 * (sum_x * sum_x3 - sum_x2 * sum_x2); + if(MathAbs(D) < 1e-10) return; + a = (sum_y * (sum_x2 * sum_x4 - sum_x3 * sum_x3) - sum_xy * (sum_x * sum_x4 - sum_x2 * sum_x3) + sum_x2y * (sum_x * sum_x3 - sum_x2 * sum_x2)) / D; b = (n * (sum_xy * sum_x4 - sum_x2y * sum_x3) - sum_x * (sum_y * sum_x4 - sum_x2 * sum_x2y) + sum_x2 * (sum_y * sum_x3 - sum_x2 * sum_xy)) / D; c = (n * (sum_x2 * sum_x2y - sum_x3 * sum_xy) - sum_x * (sum_x * sum_x2y - sum_x2 * sum_xy) + sum_y * (sum_x * sum_x3 - sum_x2 * sum_x2)) / D; @@ -117,54 +104,84 @@ void CPolynomialRegressionObjectCalculator::DrawChannelObjects(int rates_total, } double std_dev = sqrt(sum_sq_err / n); - datetime points_time[]; - double points_mid[], points_upper[], points_lower[]; - ArrayResize(points_time, m_period); - ArrayResize(points_mid, m_period); - ArrayResize(points_upper, m_period); - ArrayResize(points_lower, m_period); - - for(int j = 0; j < m_period; j++) - { - points_time[j] = time[start_index + j]; - points_mid[j] = a + b * j + c * j * j; - points_upper[j] = points_mid[j] + m_deviation * std_dev; - points_lower[j] = points_mid[j] - m_deviation * std_dev; - } - +// --- Update Objects --- for(int j = 0; j < m_period - 1; j++) { + double x1 = j; + double x2 = j + 1; + + double y_mid1 = a + b * x1 + c * x1 * x1; + double y_mid2 = a + b * x2 + c * x2 * x2; + + double y_up1 = y_mid1 + m_deviation * std_dev; + double y_up2 = y_mid2 + m_deviation * std_dev; + + double y_dn1 = y_mid1 - m_deviation * std_dev; + double y_dn2 = y_mid2 - m_deviation * std_dev; + + datetime t1 = time[start_index + j]; + datetime t2 = time[start_index + j + 1]; + + // Midline string mid_name = m_prefix + "_mid_" + (string)j; - ObjectCreate(0, mid_name, OBJ_TREND, 0, points_time[j], points_mid[j], points_time[j+1], points_mid[j+1]); - ObjectSetInteger(0, mid_name, OBJPROP_COLOR, m_mid_color); - ObjectSetInteger(0, mid_name, OBJPROP_WIDTH, 2); - ObjectSetInteger(0, mid_name, OBJPROP_SELECTABLE, false); - ObjectSetInteger(0, mid_name, OBJPROP_BACK, true); + if(ObjectFind(0, mid_name) < 0) + { + ObjectCreate(0, mid_name, OBJ_TREND, 0, t1, y_mid1, t2, y_mid2); + ObjectSetInteger(0, mid_name, OBJPROP_COLOR, m_mid_color); + ObjectSetInteger(0, mid_name, OBJPROP_WIDTH, 2); + ObjectSetInteger(0, mid_name, OBJPROP_SELECTABLE, false); + ObjectSetInteger(0, mid_name, OBJPROP_BACK, true); + ObjectSetInteger(0, mid_name, OBJPROP_RAY, false); + } + else + { + ObjectMove(0, mid_name, 0, t1, y_mid1); + ObjectMove(0, mid_name, 1, t2, y_mid2); + } + // Upper string upper_name = m_prefix + "_upper_" + (string)j; - ObjectCreate(0, upper_name, OBJ_TREND, 0, points_time[j], points_upper[j], points_time[j+1], points_upper[j+1]); - ObjectSetInteger(0, upper_name, OBJPROP_COLOR, m_upper_color); - ObjectSetInteger(0, upper_name, OBJPROP_STYLE, STYLE_DOT); - ObjectSetInteger(0, upper_name, OBJPROP_SELECTABLE, false); - ObjectSetInteger(0, upper_name, OBJPROP_BACK, true); + if(ObjectFind(0, upper_name) < 0) + { + ObjectCreate(0, upper_name, OBJ_TREND, 0, t1, y_up1, t2, y_up2); + ObjectSetInteger(0, upper_name, OBJPROP_COLOR, m_upper_color); + ObjectSetInteger(0, upper_name, OBJPROP_STYLE, STYLE_DOT); + ObjectSetInteger(0, upper_name, OBJPROP_SELECTABLE, false); + ObjectSetInteger(0, upper_name, OBJPROP_BACK, true); + ObjectSetInteger(0, upper_name, OBJPROP_RAY, false); + } + else + { + ObjectMove(0, upper_name, 0, t1, y_up1); + ObjectMove(0, upper_name, 1, t2, y_up2); + } + // Lower string lower_name = m_prefix + "_lower_" + (string)j; - ObjectCreate(0, lower_name, OBJ_TREND, 0, points_time[j], points_lower[j], points_time[j+1], points_lower[j+1]); - ObjectSetInteger(0, lower_name, OBJPROP_COLOR, m_lower_color); - ObjectSetInteger(0, lower_name, OBJPROP_STYLE, STYLE_DOT); - ObjectSetInteger(0, lower_name, OBJPROP_SELECTABLE, false); - ObjectSetInteger(0, lower_name, OBJPROP_BACK, true); + if(ObjectFind(0, lower_name) < 0) + { + ObjectCreate(0, lower_name, OBJ_TREND, 0, t1, y_dn1, t2, y_dn2); + ObjectSetInteger(0, lower_name, OBJPROP_COLOR, m_lower_color); + ObjectSetInteger(0, lower_name, OBJPROP_STYLE, STYLE_DOT); + ObjectSetInteger(0, lower_name, OBJPROP_SELECTABLE, false); + ObjectSetInteger(0, lower_name, OBJPROP_BACK, true); + ObjectSetInteger(0, lower_name, OBJPROP_RAY, false); + } + else + { + ObjectMove(0, lower_name, 0, t1, y_dn1); + ObjectMove(0, lower_name, 1, t2, y_dn2); + } } + + ChartRedraw(); } -//+------------------------------------------------------------------+ -//| | //+------------------------------------------------------------------+ bool CPolynomialRegressionObjectCalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { if(ArraySize(m_price) != rates_total) - if(ArrayResize(m_price, rates_total) != rates_total) - return false; + ArrayResize(m_price, rates_total); switch(price_type) { @@ -190,60 +207,74 @@ bool CPolynomialRegressionObjectCalculator::PreparePriceSeries(int rates_total, break; case PRICE_WEIGHTED: for(int i=0; i