diff --git a/Include/MyIncludes/PivotPoint_Calculator.mqh b/Include/MyIncludes/PivotPoint_Calculator.mqh index e1922ff..de05401 100644 --- a/Include/MyIncludes/PivotPoint_Calculator.mqh +++ b/Include/MyIncludes/PivotPoint_Calculator.mqh @@ -1,9 +1,10 @@ //+------------------------------------------------------------------+ //| PivotPoint_Calculator.mqh | //| Engine for calculating various Pivot Point types. | -//| Copyright 2026, xxxxxxxx | +//| Copyright 2026, xxxxxxxx| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" +#property version "3.10" enum ENUM_PIVOT_TYPE { @@ -25,6 +26,7 @@ struct PivotLevels double PP; double R1, R2, R3; double S1, S2, S3; + datetime period_start; }; //+==================================================================+ @@ -36,7 +38,7 @@ protected: ENUM_PIVOT_TYPE m_type; ENUM_PIVOT_SOURCE m_source; - // Cache for optimization + // Cache for O(1) performance datetime m_last_calc_time; PivotLevels m_last_levels; @@ -55,6 +57,7 @@ bool CPivotPointCalculator::Init(ENUM_PIVOT_TYPE type, ENUM_PIVOT_SOURCE source) { m_type = type; m_source = source; + m_last_calc_time = 0; return true; } @@ -63,66 +66,69 @@ bool CPivotPointCalculator::Init(ENUM_PIVOT_TYPE type, ENUM_PIVOT_SOURCE source) //+------------------------------------------------------------------+ bool CPivotPointCalculator::CalculateLevels(datetime current_time, ENUM_TIMEFRAMES tf, PivotLevels &out_levels) { -// 1. Identify the start time of the HTF bar containing current_time - datetime htf_time = iTime(_Symbol, tf, iBarShift(_Symbol, tf, current_time)); + int current_bar_shift = iBarShift(_Symbol, tf, current_time, false); + if(current_bar_shift < 0) + return false; -// Optimization: If we already calculated for this HTF bar, return cached + datetime htf_time = iTime(_Symbol, tf, current_bar_shift); + if(htf_time == 0) + return false; + +// Optimization: Return cached result if same HTF bar if(htf_time == m_last_calc_time && m_last_calc_time != 0) { out_levels = m_last_levels; return true; } -// 2. We need the PREVIOUS completed HTF bar data - int htf_index = iBarShift(_Symbol, tf, current_time) + 1; - - double O, H, L, C; +// Fetch completed previous HTF bar data + int htf_index = current_bar_shift + 1; double o_arr[1], h_arr[1], l_arr[1], c_arr[1]; - if(CopyOpen(_Symbol, tf, htf_index, 1, o_arr)<=0 || - CopyHigh(_Symbol, tf, htf_index, 1, h_arr)<=0 || - CopyLow(_Symbol, tf, htf_index, 1, l_arr)<=0 || - CopyClose(_Symbol, tf, htf_index, 1, c_arr)<=0) + if(CopyOpen(_Symbol, tf, htf_index, 1, o_arr) <= 0 || + CopyHigh(_Symbol, tf, htf_index, 1, h_arr) <= 0 || + CopyLow(_Symbol, tf, htf_index, 1, l_arr) <= 0 || + CopyClose(_Symbol, tf, htf_index, 1, c_arr) <= 0) return false; - O = o_arr[0]; - H = h_arr[0]; - L = l_arr[0]; - C = c_arr[0]; + double O = o_arr[0]; + double H = h_arr[0]; + double L = l_arr[0]; + double C = c_arr[0]; -// Heikin Ashi Transformation if requested +// Heikin Ashi Transformation if(m_source == PIVOT_SRC_HEIKIN_ASHI) { double ha_close = (O + H + L + C) / 4.0; double po_arr[1], pc_arr[1]; - CopyOpen(_Symbol, tf, htf_index+1, 1, po_arr); - CopyClose(_Symbol, tf, htf_index+1, 1, pc_arr); - double ha_open = (po_arr[0] + pc_arr[0]) / 2.0; + if(CopyOpen(_Symbol, tf, htf_index + 1, 1, po_arr) > 0 && + CopyClose(_Symbol, tf, htf_index + 1, 1, pc_arr) > 0) + { + double ha_open = (po_arr[0] + pc_arr[0]) / 2.0; + double ha_high = MathMax(H, MathMax(ha_open, ha_close)); + double ha_low = MathMin(L, MathMin(ha_open, ha_close)); - double ha_high = MathMax(H, MathMax(ha_open, ha_close)); - double ha_low = MathMin(L, MathMin(ha_open, ha_close)); - - O = ha_open; - H = ha_high; - L = ha_low; - C = ha_close; + O = ha_open; + H = ha_high; + L = ha_low; + C = ha_close; + } } -// 3. Calculate Formulas double range = H - L; switch(m_type) { case PIVOT_CLASSIC: out_levels.PP = (H + L + C) / 3.0; - out_levels.R1 = 2 * out_levels.PP - L; - out_levels.S1 = 2 * out_levels.PP - H; + out_levels.R1 = 2.0 * out_levels.PP - L; + out_levels.S1 = 2.0 * out_levels.PP - H; out_levels.R2 = out_levels.PP + range; out_levels.S2 = out_levels.PP - range; - out_levels.R3 = H + 2 * (out_levels.PP - L); - out_levels.S3 = L - 2 * (H - out_levels.PP); + out_levels.R3 = H + 2.0 * (out_levels.PP - L); + out_levels.S3 = L - 2.0 * (H - out_levels.PP); break; case PIVOT_FIBONACCI: @@ -136,13 +142,13 @@ bool CPivotPointCalculator::CalculateLevels(datetime current_time, ENUM_TIMEFRAM break; case PIVOT_WOODIE: - out_levels.PP = (H + L + 2 * C) / 4.0; - out_levels.R1 = 2 * out_levels.PP - L; - out_levels.S1 = 2 * out_levels.PP - H; + out_levels.PP = (H + L + 2.0 * C) / 4.0; + out_levels.R1 = 2.0 * out_levels.PP - L; + out_levels.S1 = 2.0 * out_levels.PP - H; out_levels.R2 = out_levels.PP + range; out_levels.S2 = out_levels.PP - range; - out_levels.R3 = H + 2 * (out_levels.PP - L); - out_levels.S3 = L - 2 * (H - out_levels.PP); + out_levels.R3 = H + 2.0 * (out_levels.PP - L); + out_levels.S3 = L - 2.0 * (H - out_levels.PP); break; case PIVOT_CAMARILLA: @@ -159,29 +165,30 @@ bool CPivotPointCalculator::CalculateLevels(datetime current_time, ENUM_TIMEFRAM { double X; if(C < O) - X = H + 2 * L + C; + X = H + 2.0 * L + C; else if(C > O) - X = 2 * H + L + C; + X = 2.0 * H + L + C; else - X = H + L + 2 * C; + X = H + L + 2.0 * C; out_levels.PP = X / 4.0; out_levels.R1 = X / 2.0 - L; out_levels.S1 = X / 2.0 - H; - out_levels.R2 = 0; - out_levels.S2 = 0; - out_levels.R3 = 0; - out_levels.S3 = 0; + out_levels.R2 = EMPTY_VALUE; + out_levels.S2 = EMPTY_VALUE; + out_levels.R3 = EMPTY_VALUE; + out_levels.S3 = EMPTY_VALUE; break; } } -// Update Cache + out_levels.period_start = htf_time; + +// Store Cache m_last_calc_time = htf_time; - m_last_levels = out_levels; + m_last_levels = out_levels; return true; } //+------------------------------------------------------------------+ -//+------------------------------------------------------------------+