diff --git a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 b/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 index 14e1913..a1d8b5a 100644 --- a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 +++ b/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 @@ -1,15 +1,14 @@ //+------------------------------------------------------------------+ -//| KeltnerChannel_HeikinAshi.mq5 | +//| KeltnerChannel_HeikinAshi.mq5 | //| Copyright 2025, xxxxxxxx | //| | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Keltner Channels on Heikin Ashi data" +#property version "3.01" // Corrected OnCalculate signature and SMA logic +#property description "Keltner Channels with HA middle line and Standard ATR" #include -#include //--- Indicator Window and Plot Properties --- #property indicator_chart_window @@ -47,7 +46,7 @@ enum ENUM_HA_APPLIED_PRICE //--- Input Parameters --- input int InpMaPeriod = 20; input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; // HA price for the middle line +input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; input int InpAtrPeriod = 10; input double InpMultiplier = 2.0; @@ -57,17 +56,10 @@ double BufferLower[]; double BufferMiddle[]; double BufferATR[]; -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - //--- Global Objects and Variables --- int g_ExtMaPeriod, g_ExtAtrPeriod; double g_ExtMultiplier; -int g_handle_atr; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator +CHeikinAshi_Calculator *g_ha_calculator; //+------------------------------------------------------------------+ //| Custom indicator initialization function. | @@ -88,14 +80,6 @@ int OnInit() ArraySetAsSeries(BufferMiddle, false); ArraySetAsSeries(BufferATR, false); -// ATR is always calculated on standard candles for true volatility - g_handle_atr = iATR(_Symbol, _Period, g_ExtAtrPeriod); - if(g_handle_atr == INVALID_HANDLE) - { - Print("Error creating iATR handle."); - return(INIT_FAILED); - } - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); int draw_begin = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); @@ -103,7 +87,6 @@ int OnInit() PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, g_ExtMaPeriod - 1); IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_KC(%d,%d,%.1f)", g_ExtMaPeriod, g_ExtAtrPeriod, g_ExtMultiplier)); -//--- Create the calculator instance g_ha_calculator = new CHeikinAshi_Calculator(); if(CheckPointer(g_ha_calculator) == POINTER_INVALID) { @@ -119,19 +102,17 @@ int OnInit() //+------------------------------------------------------------------+ void OnDeinit(const int reason) { -//--- Free the calculator object if(CheckPointer(g_ha_calculator) != POINTER_INVALID) { delete g_ha_calculator; g_ha_calculator = NULL; } -//--- Release the indicator handle - IndicatorRelease(g_handle_atr); } //+------------------------------------------------------------------+ //| Keltner Channel on Heikin Ashi calculation function. | //+------------------------------------------------------------------+ +// --- FIX: Restored the full, correct function signature --- int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], @@ -147,69 +128,115 @@ int OnCalculate(const int rates_total, if(rates_total <= start_pos) return(0); -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); +//--- Intermediate Heikin Ashi Buffers + double ha_open[], ha_high[], ha_low[], ha_close[]; + ArrayResize(ha_open, rates_total); + ArrayResize(ha_high, rates_total); + ArrayResize(ha_low, rates_total); + ArrayResize(ha_close, rates_total); //--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); + g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); -//--- STEP 2: Get ATR values (from standard candles) - if(CopyBuffer(g_handle_atr, 0, 0, rates_total, BufferATR) < rates_total) +//--- STEP 2: Calculate Standard True Range manually + double tr[]; + ArrayResize(tr, rates_total); + for(int i = 1; i < rates_total; i++) { - Print("Error copying iATR buffer data."); - // We don't return here, calculation can proceed with partial data + tr[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); } -//--- STEP 3: Select the source Heikin Ashi price array for the middle line +//--- STEP 3: Prepare HA price source for the middle line double ha_price_source[]; + ArrayResize(ha_price_source, rates_total); switch(InpAppliedPrice) { case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ExtHaOpenBuffer); + ArrayCopy(ha_price_source, ha_open); break; case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ExtHaHighBuffer); + ArrayCopy(ha_price_source, ha_high); break; case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ExtHaLowBuffer); + ArrayCopy(ha_price_source, ha_low); break; default: - ArrayCopy(ha_price_source, ExtHaCloseBuffer); + ArrayCopy(ha_price_source, ha_close); break; } -//--- STEP 4: Calculate Middle, Upper, and Lower bands in a single loop +//--- STEP 4: Calculate ATR, Middle, Upper, and Lower bands + double sma_sum = 0; for(int i = 1; i < rates_total; i++) { + // --- Calculate Standard ATR (using Wilder's smoothing) --- + if(i == g_ExtAtrPeriod) // Initialization with manual SMA + { + double atr_sum = 0; + for(int j=1; j<=g_ExtAtrPeriod; j++) + atr_sum += tr[j]; + BufferATR[i] = atr_sum / g_ExtAtrPeriod; + } + else + if(i > g_ExtAtrPeriod) // Recursive calculation + { + BufferATR[i] = (BufferATR[i-1] * (g_ExtAtrPeriod - 1) + tr[i]) / g_ExtAtrPeriod; + } + // --- Calculate the middle line (MA on HA price) --- if(i >= g_ExtMaPeriod - 1) { switch(InpMaMethod) { case MODE_EMA: - if(i == g_ExtMaPeriod - 1) - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); - else - { - double pr = 2.0 / (g_ExtMaPeriod + 1.0); - BufferMiddle[i] = ha_price_source[i] * pr + BufferMiddle[i-1] * (1.0 - pr); - } - break; case MODE_SMMA: if(i == g_ExtMaPeriod - 1) - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); + { + double sum = 0; + for(int j=0; j 0) + BufferMiddle[i] = lwma_sum / weight_sum; + } + break; default: // MODE_SMA - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); + if(i == g_ExtMaPeriod - 1) // First calculation + { + sma_sum = 0; // Re-initialize sum for the first calculation point + for(int j=0; j= start_pos) { - double atr_value = BufferATR[i]; - double ma_value = BufferMiddle[i]; - - BufferUpper[i] = ma_value + (atr_value * g_ExtMultiplier); - BufferLower[i] = ma_value - (atr_value * g_ExtMultiplier); + BufferUpper[i] = BufferMiddle[i] + (BufferATR[i] * g_ExtMultiplier); + BufferLower[i] = BufferMiddle[i] - (BufferATR[i] * g_ExtMultiplier); } }