//+------------------------------------------------------------------+
//|                                                 A! Sempoi BB.mq4 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 6  // Added one more buffer for EMA60
#property indicator_color1 Red    // Upper Band
#property indicator_color2 Gray   // Middle Band
#property indicator_color3 DodgerBlue   // Lower Band
#property indicator_color4 Red    // Upper Band Touch Points
#property indicator_color5 DodgerBlue   // Lower Band Touch Points
#property indicator_color6 Magenta // EMA 60
#property indicator_width1 3
#property indicator_width2 3
#property indicator_width3 3
#property indicator_width4 3
#property indicator_width5 3
#property indicator_width6 4

// Input Parameters
extern int    BandsPeriod = 20;         // Bollinger Bands Period
extern double BandsDeviation = 2;       // Standard Deviation
extern int    BarsToCalculate = 1000;    // Calculation Limit
extern int    LineWidth = 1;            // Line Width
extern bool   EnableDotOperation = true; // Control dot operation
extern int    EMA_Period = 60;          // EMA Period

// Indicator Buffers
double UpperBuffer[];
double MiddleBuffer[];
double LowerBuffer[];
double UpperTouchBuffer[];
double LowerTouchBuffer[];
double EMABuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                           |
//+------------------------------------------------------------------+
int OnInit()
{
    // Set Indicator Buffers
    SetIndexBuffer(0, UpperBuffer);
    SetIndexBuffer(1, MiddleBuffer);
    SetIndexBuffer(2, LowerBuffer);
    SetIndexBuffer(3, UpperTouchBuffer);
    SetIndexBuffer(4, LowerTouchBuffer);
    SetIndexBuffer(5, EMABuffer);
    
    // Set Indicator Labels
    SetIndexLabel(0, "Upper Band");
    SetIndexLabel(1, "Middle Band");
    SetIndexLabel(2, "Lower Band");
    SetIndexLabel(3, "Upper Touch");
    SetIndexLabel(4, "Lower Touch");
    SetIndexLabel(5, "EMA " + IntegerToString(EMA_Period));
    
    // Set Drawing Styles
    SetIndexStyle(0, DRAW_LINE, STYLE_DASH, LineWidth);
    SetIndexStyle(1, DRAW_LINE, STYLE_DOT, LineWidth);
    SetIndexStyle(2, DRAW_LINE, STYLE_DASH, LineWidth);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_ARROW);
    SetIndexStyle(5, DRAW_LINE, STYLE_SOLID, LineWidth);
    
    // Set Arrow Codes
    SetIndexArrow(3, 159);
    SetIndexArrow(4, 159);
    
    // Prevent repainting
    SetIndexShift(3, 1);
    SetIndexShift(4, 1);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                                |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    int limit = rates_total - prev_calculated;
    if(limit > BarsToCalculate) limit = BarsToCalculate;
    
    // Calculate EMA first
    for(int i = limit; i >= 0; i--)
    {
        EMABuffer[i] = iMA(NULL, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);
    }
    
    // Calculate Bollinger Bands and signals
    for(int i = limit; i >= 1; i--)
    {
        MiddleBuffer[i] = iMA(NULL, 0, BandsPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
        double stdDev = iStdDev(NULL, 0, BandsPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
        
        UpperBuffer[i] = MiddleBuffer[i] + (BandsDeviation * stdDev);
        LowerBuffer[i] = MiddleBuffer[i] - (BandsDeviation * stdDev);
        
        if (EnableDotOperation && i < rates_total - 1)
        {
            bool upTrend = close[i] > EMABuffer[i] && close[i+1] > EMABuffer[i+1];
            bool downTrend = close[i] < EMABuffer[i] && close[i+1] < EMABuffer[i+1];
            
            // Upper touch signal only in downtrend
            if(high[i] >= UpperBuffer[i] && downTrend)
                UpperTouchBuffer[i] = high[i];
            else
                UpperTouchBuffer[i] = EMPTY_VALUE;
                
            // Lower touch signal only in uptrend
            if(low[i] <= LowerBuffer[i] && upTrend)
                LowerTouchBuffer[i] = low[i];
            else
                LowerTouchBuffer[i] = EMPTY_VALUE;
        }
    }
    
    // Calculate current candle's values
    if(rates_total > 0)
    {
        int current = 0;
        MiddleBuffer[current] = iMA(NULL, 0, BandsPeriod, 0, MODE_SMA, PRICE_CLOSE, current);
        double currentStdDev = iStdDev(NULL, 0, BandsPeriod, 0, MODE_SMA, PRICE_CLOSE, current);
        
        UpperBuffer[current] = MiddleBuffer[current] + (BandsDeviation * currentStdDev);
        LowerBuffer[current] = MiddleBuffer[current] - (BandsDeviation * currentStdDev);
        EMABuffer[current] = iMA(NULL, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, current);
        
        if (!EnableDotOperation)
        {
            UpperTouchBuffer[current] = EMPTY_VALUE;
            LowerTouchBuffer[current] = EMPTY_VALUE;
        }
    }
    
    return(rates_total);
}