//+------------------------------------------------------------------+
//| MTF CANDLEZ HA.mq4                                               |
//+------------------------------------------------------------------+
#property strict

#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

extern string UniqueCandlesIdentifier = "MTF Heiken Ashi";
input color Color_Bullish             = clrLime;         // Bullish Color
input color Color_Bearish             = clrRed;          // Bearish Color
input ENUM_TIMEFRAMES HigherTimeframe = PERIOD_H4;       // TimeFrame
extern int DrawingWidth               = 2;               // Line Width
input string  LineOnlySettings=" For Line Only set Both To False ";
extern bool DisplayasBackground       = false;           // Draw As BackGround
extern bool FilledCandles             = false;           // Filled Candles

int timeframeRatio = 1;
datetime lastCalculatedBarTime = 0;

string IndicatorName;
string IndicatorObjPrefix;
bool show_data = true;

//+------------------------------------------------------------------+
//| Generate unique indicator name                                   |
//+------------------------------------------------------------------+
string GenerateIndicatorName(const string target) {
   string name = target;
   int try = 2;
   while (WindowFind(name) != -1) {
      name = target + " #" + IntegerToString(try++);
   }
   return name;
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
    timeframeRatio = HigherTimeframe / Period();
    if(timeframeRatio < 1) timeframeRatio = 1;
    
    IndicatorName = GenerateIndicatorName("MTF Heiken Ashi Rectangles");
    IndicatorObjPrefix = "__" + IndicatorName + "__";
    IndicatorShortName("MTF HEIKEN ASHI Rect (" + EnumToString(HigherTimeframe) + ")");

    double val;
    if(GlobalVariableGet(IndicatorName + "_visibility", val))
        show_data = val != 0;
    
    return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {
    deleteCandles();
    ObjectsDeleteAll(ChartID(), IndicatorObjPrefix);
    return(0);
}

//+------------------------------------------------------------------+
//| Delete all candles with our identifier                           |
//+------------------------------------------------------------------+
void deleteCandles() {
   int searchLength = StringLen(UniqueCandlesIdentifier);
   for (int i=ObjectsTotal()-1; i>=0; i--) {
      string name = ObjectName(i);
      if (StringSubstr(name,0,searchLength) == UniqueCandlesIdentifier) {
         ObjectDelete(name);
      }
   }
}

//+------------------------------------------------------------------+
//| Update current candle wick                                       |
//+------------------------------------------------------------------+
void UpdateCurrentCandleWick(datetime higherTFStart, datetime higherTFEnd, 
                            double d_High, double d_Low, double d_Open, double d_Close, color candleColor) {
    string name = UniqueCandlesIdentifier+":"+IntegerToString(higherTFStart);
    datetime wickTime = higherTFStart + (higherTFEnd - higherTFStart) / 2;
    
    // Update upper wick - only extend higher, never lower
    string wname = name+":+";
    if (ObjectFind(wname) >= 0) {
        double currentHigh = ObjectGet(wname, OBJPROP_PRICE1);
        if (d_High > currentHigh) {
            ObjectSet(wname, OBJPROP_PRICE1, d_High);
        }
        // Keep the bottom of wick fixed at body top
        ObjectSet(wname, OBJPROP_PRICE2, MathMax(d_Open, d_Close));
    }
    
    // Update lower wick - only extend lower, never higher
    wname = name+":-";
    if (ObjectFind(wname) >= 0) {
        double currentLow = ObjectGet(wname, OBJPROP_PRICE2);
        if (d_Low < currentLow) {
            ObjectSet(wname, OBJPROP_PRICE2, d_Low);
        }
        // Keep the top of wick fixed at body bottom
        ObjectSet(wname, OBJPROP_PRICE1, MathMin(d_Open, d_Close));
    }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start() {
    if (!show_data) {
        deleteCandles();
        return(0);
    }
    
    int counted_bars = IndicatorCounted();
    if(counted_bars < 0) return(-1);
    
    // Delete old candles before redrawing if it's a full recalculation
    if (counted_bars == 0) {
        deleteCandles();
    }
    
    // Get the number of higher timeframe bars we need to process
    int higherTFBars = MathMin(Bars, iBars(NULL, HigherTimeframe));
    int limit = Bars - counted_bars;
    if(limit <= 0) limit = 1;
    
    // Process historical candles (from oldest to newest)
    for(int i = limit-1; i > 0; i--) {
        datetime currentTime = iTime(NULL, 0, i);
        int higherTFIndex = iBarShift(NULL, HigherTimeframe, currentTime, true);
        
        if(higherTFIndex < 0) continue;
        
        // Get the start and end time of the higher timeframe bar
        datetime higherTFStart = iTime(NULL, HigherTimeframe, higherTFIndex);
        datetime higherTFEnd = higherTFStart + HigherTimeframe*60 - 1;
        
        // Only process if this is the first current timeframe bar in the higher timeframe bar
        if(i < Bars-1 && iTime(NULL, 0, i+1) >= higherTFStart) continue;
        
        // Get higher timeframe data
        double haOpen = iOpen(NULL, HigherTimeframe, higherTFIndex);
        double haClose = iClose(NULL, HigherTimeframe, higherTFIndex);
        double haHigh = iHigh(NULL, HigherTimeframe, higherTFIndex);
        double haLow = iLow(NULL, HigherTimeframe, higherTFIndex);
        
        // Calculate Heiken Ashi values
        static double prevHAOpen = 0, prevHAClose = 0;
        
        double d_Open, d_Close, d_High, d_Low;
        
        if(higherTFIndex == iBars(NULL, HigherTimeframe)-1) {
            // First bar calculation
            d_Open = (haOpen + haClose) / 2;
            d_Close = (haOpen + haHigh + haLow + haClose) / 4;
        }
        else {
            // Subsequent bars
            d_Open = (prevHAOpen + prevHAClose) / 2;
            d_Close = (haOpen + haHigh + haLow + haClose) / 4;
        }
        
        d_High = MathMax(haHigh, MathMax(d_Open, d_Close));
        d_Low = MathMin(haLow, MathMin(d_Open, d_Close));
        
        // Store values for next calculation
        prevHAOpen = d_Open;
        prevHAClose = d_Close;
        
        // Determine candle color
        color candleColor = (d_Close > d_Open) ? Color_Bullish : Color_Bearish;
        
        // Draw the rectangle (candle body)
        string name = UniqueCandlesIdentifier+":"+IntegerToString(higherTFStart);
        if (ObjectFind(name) < 0) {
            ObjectCreate(name, OBJ_RECTANGLE, 0, higherTFStart, d_Open, higherTFEnd, d_Close);
            ObjectSet(name, OBJPROP_COLOR, candleColor);
            ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSet(name, OBJPROP_WIDTH, DrawingWidth);
            ObjectSetInteger(0,name,OBJPROP_BACK,DisplayasBackground);
            ObjectSetInteger(0,name,OBJPROP_FILL,FilledCandles);
            
            // Draw the wicks - centered in time
            datetime wickTime = higherTFStart + (higherTFEnd - higherTFStart) / 2;
            
            // Upper wick - from high to top of body
            string wname = name+":+";
            ObjectCreate(wname, OBJ_TREND, 0, wickTime, d_High, wickTime, MathMax(d_Open, d_Close));
            ObjectSet(wname, OBJPROP_COLOR, candleColor);
            ObjectSet(wname, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSet(wname, OBJPROP_RAY, false);
            ObjectSet(wname, OBJPROP_WIDTH, DrawingWidth);
            ObjectSet(wname, OBJPROP_BACK, DisplayasBackground);
            
            // Lower wick - from bottom of body to low
            wname = name+":-";
            ObjectCreate(wname, OBJ_TREND, 0, wickTime, MathMin(d_Open, d_Close), wickTime, d_Low);
            ObjectSet(wname, OBJPROP_COLOR, candleColor);
            ObjectSet(wname, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSet(wname, OBJPROP_RAY, false);
            ObjectSet(wname, OBJPROP_WIDTH, DrawingWidth);
            ObjectSet(wname, OBJPROP_BACK, DisplayasBackground);
        }
    }
    
    // Handle the current (incomplete) candle separately
    if (Bars > 0) {
        datetime currentTime = Time[0];
        int higherTFIndex = iBarShift(NULL, HigherTimeframe, currentTime, true);
        
        if(higherTFIndex >= 0) {
            // Get the start and end time of the higher timeframe bar
            datetime higherTFStart = iTime(NULL, HigherTimeframe, higherTFIndex);
            datetime higherTFEnd = higherTFStart + HigherTimeframe*60 - 1;
            
            // Get higher timeframe data
            double haOpen = iOpen(NULL, HigherTimeframe, higherTFIndex);
            double haClose = iClose(NULL, HigherTimeframe, higherTFIndex);
            double haHigh = iHigh(NULL, HigherTimeframe, higherTFIndex);
            double haLow = iLow(NULL, HigherTimeframe, higherTFIndex);
            
            // Calculate Heiken Ashi values
            static double prevHAOpen = 0, prevHAClose = 0;
            
            double d_Open, d_Close, d_High, d_Low;
            
            if(higherTFIndex == iBars(NULL, HigherTimeframe)-1) {
                // First bar calculation
                d_Open = (haOpen + haClose) / 2;
                d_Close = (haOpen + haHigh + haLow + haClose) / 4;
            }
            else {
                // Subsequent bars
                d_Open = (prevHAOpen + prevHAClose) / 2;
                d_Close = (haOpen + haHigh + haLow + haClose) / 4;
            }
            
            d_High = MathMax(haHigh, MathMax(d_Open, d_Close));
            d_Low = MathMin(haLow, MathMin(d_Open, d_Close));
            
            // Determine candle color
            color candleColor = (d_Close > d_Open) ? Color_Bullish : Color_Bearish;
            
            // Create or update the current candle
            string name = UniqueCandlesIdentifier+":"+IntegerToString(higherTFStart);
            if (ObjectFind(name) < 0) {
                // Create the candle if it doesn't exist
                ObjectCreate(name, OBJ_RECTANGLE, 0, higherTFStart, d_Open, higherTFEnd, d_Close);
                ObjectSet(name, OBJPROP_COLOR, candleColor);
                ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
                ObjectSet(name, OBJPROP_WIDTH, DrawingWidth);
                ObjectSetInteger(0,name,OBJPROP_BACK,DisplayasBackground);
                ObjectSetInteger(0,name,OBJPROP_FILL,FilledCandles);
                
                // Create the wicks - centered in time
                datetime wickTime = higherTFStart + (higherTFEnd - higherTFStart) / 2;
                
                // Upper wick - from high to top of body
                string wname = name+":+";
                ObjectCreate(wname, OBJ_TREND, 0, wickTime, d_High, wickTime, MathMax(d_Open, d_Close));
                ObjectSet(wname, OBJPROP_COLOR, candleColor);
                ObjectSet(wname, OBJPROP_STYLE, STYLE_SOLID);
                ObjectSet(wname, OBJPROP_RAY, false);
                ObjectSet(wname, OBJPROP_WIDTH, DrawingWidth);
                ObjectSet(wname, OBJPROP_BACK, DisplayasBackground);
                
                // Lower wick - from bottom of body to low
                wname = name+":-";
                ObjectCreate(wname, OBJ_TREND, 0, wickTime, MathMin(d_Open, d_Close), wickTime, d_Low);
                ObjectSet(wname, OBJPROP_COLOR, candleColor);
                ObjectSet(wname, OBJPROP_STYLE, STYLE_SOLID);
                ObjectSet(wname, OBJPROP_RAY, false);
                ObjectSet(wname, OBJPROP_WIDTH, DrawingWidth);
                ObjectSet(wname, OBJPROP_BACK, DisplayasBackground);
            } else {
                // Only update the wicks for the current candle
                UpdateCurrentCandleWick(higherTFStart, higherTFEnd, d_High, d_Low, d_Open, d_Close, candleColor);
            }
        }
    }
    
    return(0);
}