//+------------------------------------------------------------------+
//|                        Double_Bollinger_Bands_Dashboard_v3.1.mq4 |
//|                                         Copyright 2020, NickBixy |
//|             https://www.forexfactory.com/showthread.php?t=904734 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, NickBixy"
#property version   "3.10"  //Alert Bugfix - geemaster
#property strict
#property indicator_chart_window
#define HR2400 (PERIOD_D1 * 60)  // 86400 = 24 * 3600

enum symbolTypeChoice
{
   MarketWatch,//Market Watch
   SymbolList//Symbols In List
};

enum labelCornorAnchor
{
   LeftUpper,//Left Upper
   RightUpper//Right Upper
};

enum pipPointChoice
{
   Pips,//Pips
   Points,//Points
};

enum yesnoChoiceToggle
{
   No,
   Yes
};

extern string instanceHeader="-----------------Instance Settings---------------------------------------";//----- Instance Settings
extern string instanceID="1"; //Unique Instance ID (e.g., 1, 2, 3, etc.)

extern ENUM_TIMEFRAMES timeframe1=PERIOD_M5;//DBB1 timeframe
extern ENUM_TIMEFRAMES timeframe2=PERIOD_M15;//DBB2 timeframe
extern ENUM_TIMEFRAMES timeframe3=PERIOD_M30;//DBB3 timeframe
extern ENUM_TIMEFRAMES timeframe4=PERIOD_H1;//DBB4 timeframe
extern ENUM_TIMEFRAMES timeframe5=PERIOD_H4;//DBB5 timeframe
extern ENUM_TIMEFRAMES timeframe6=PERIOD_D1;//DBB6 timeframe

extern bool useTimeframe1=true;//Use DBB1 timeframe?
extern bool useTimeframe2=true;//Use DBB2 timeframe?
extern bool useTimeframe3=true;//Use DBB3 timeframe?
extern bool useTimeframe4=true;//Use DBB4 timeframe?
extern bool useTimeframe5=true;//Use DBB5 timeframe?
extern bool useTimeframe6=true;//Use DBB6 timeframe?

extern string symbolHeader="-----------------Symbol Settings------------------------------------------";//----- Symbol Settings
extern symbolTypeChoice symTypeChoice=MarketWatch;//Symbols To Scan- Market Watch/Symbol List Below?
extern string symbols="AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,CADCHF,CADJPY,CHFJPY,EURAUD,EURCAD,EURCHF,EURGBP,EURJPY,EURNZD,EURUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPUSD,NZDCAD,NZDCHF,NZDJPY,NZDUSD,USDCAD,USDCHF,USDJPY"; //Symbols To Scan?
extern string symbolPrefix=""; //Symbol Prefix?
extern string symbolSuffix=""; //Symbol Suffix?
extern string alertHeader="-----------------Alert Settings------------------------------------------";//----- Alert Settings
int alertIntervalTimeSeconds; //wait time between same alert message
extern int alertInternalMinutes=60;//BZ-SZ New State Color hold xx-Minutes?

extern string dashBoardHeader="-----------------Dashboard Settings--------------------------------------";//----- Dashboard Settings
extern labelCornorAnchor labelCornorAnchorChoice = RightUpper;//Label Corner Anchor left or right?
extern int dashX=0;//X Dashboard
extern int dashY=100;//Y Dashboard
extern int symXdbb1=100;  //X Between Columns Symbol-DBB1
extern int dbb1Xdbb2=40;   //X Between Columns DBB1-DBB2
extern int dbb2Xdbb3=40;   //X Between Columns DBB2-DBB3
extern int dbb3Xdbb4=40;   //X Between Columns DBB3-DBB4
extern int dbb4Xdbb5=40;   //X Between Columns DBB4-DBB5
extern int dbb5Xdbb6=40;   //X Between Columns DBB5-DBB6
extern string Font="Arial";//Label Font
extern int fontText=10;//Label Font Size
extern int textH=14;//Y Spacing Between labels Rows
extern color symbolColor=clrGold;//Color of Symbol Rows
extern color headerColor=clrGold;//Color of Header Row
extern color bzColor=clrLime;//Color of BZ Buy Zone
extern color szColor=clrRed;//Color of SZ Sell Zone
extern color naColor=clrGreen;//Color of NA Neutral Above Zone
extern color nbColor=clrMaroon;//Color of NB Neutral Below Zone
extern color BZNewStateColor=clrAqua;//Color of BZ NewState
extern color SZNewStateColor=clrMagenta;//Color of SZ NewState

extern string alert_section = "---- Alerts ----";
extern bool alertsOn = false;
extern bool alertsMessage = true;
extern bool alertsNotify = false;             
extern bool alertsSound = true;
extern bool alertsEmail = false;

string indiName="DBB_DB_"; // Base name, will append instanceID
string symbolList[];
string symbolListFinal[];
int numSymbols=0;
int signcount=0;
int signgoal=0;

int      arrSymbolDBB1State[][1];
datetime arrDBB1WaitTill[][1];
int      arrSymbolDBB2State[][1];
datetime arrDBB2WaitTill[][1];
int      arrSymbolDBB3State[][1];
datetime arrDBB3WaitTill[][1];
int      arrSymbolDBB4State[][1];
datetime arrDBB4WaitTill[][1];
int      arrSymbolDBB5State[][1];
datetime arrDBB5WaitTill[][1];
int      arrSymbolDBB6State[][1];
datetime arrDBB6WaitTill[][1];

// Add structure and array for tracking last alert times
struct AlertRecord {
   string symbol;
   string doWhat;
   datetime lastAlertTime;
};

AlertRecord lastAlerts[];
int numAlertRecords = 0;

//+------------------------------------------------------------------+
int OnInit()
{
   // Append instanceID to indiName to make it unique for this instance
   indiName = "DBB_DB_" + instanceID;
   IndicatorSetString(INDICATOR_SHORTNAME, indiName);
   alertIntervalTimeSeconds = alertInternalMinutes * 60;

   bool eventBool = EventSetTimer(5);
   if(eventBool == false) Alert("EventSetTimer Error Code " + (string)GetLastError());

   // Initialize the lastAlerts array
   ArrayResize(lastAlerts, 0);
   numAlertRecords = 0;

   if(symTypeChoice == MarketWatch) {
      int numSymbolsMarketWatch = SymbolsTotal(true);
      numSymbols = numSymbolsMarketWatch;
      ArrayResize(symbolListFinal, numSymbolsMarketWatch);
      for(int i = 0; i < numSymbolsMarketWatch; i++) {
         symbolListFinal[i] = SymbolName(i, true);
      }
   } else if(symTypeChoice == SymbolList) {
      getSymbols();
      testSymbols();
   }

   // Conditionally resize DBB1 arrays based on useTimeframe1
   if(useTimeframe1) {
      if(ArrayResize(arrSymbolDBB1State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB1State");
      if(ArrayResize(arrDBB1WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB1WaitTill");
   }

   signgoal = 0; // Start at 0 instead of 1 since DBB1 is now optional
   if(useTimeframe1) {
      signgoal = 1;
   }
   if(useTimeframe2) {
      signgoal++;
      if(ArrayResize(arrSymbolDBB2State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB2State");
      if(ArrayResize(arrDBB2WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB2WaitTill");
   }
   if(useTimeframe3) {
      signgoal++;
      if(ArrayResize(arrSymbolDBB3State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB3State");
      if(ArrayResize(arrDBB3WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB3WaitTill");
   }
   if(useTimeframe4) {
      signgoal++;
      if(ArrayResize(arrSymbolDBB4State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB4State");
      if(ArrayResize(arrDBB4WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB4WaitTill");
   }
   if(useTimeframe5) {
      signgoal++;
      if(ArrayResize(arrSymbolDBB5State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB5State");
      if(ArrayResize(arrDBB5WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB5WaitTill");
   }
   if(useTimeframe6) {
      signgoal++;
      if(ArrayResize(arrSymbolDBB6State, numSymbols) < 0) Alert("ArrayResize Error arrSymbolDBB6State");
      if(ArrayResize(arrDBB6WaitTill, numSymbols) < 0) Alert("ArrayResize Error arrDBB6WaitTill");
   }

   for(int i = 0; i < numSymbols; i++) {
      if(useTimeframe1) {
         if(GlobalVariableCheck(indiName + " " + "DBB1" + " " + symbolListFinal[i]))
            arrSymbolDBB1State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB1" + " " + symbolListFinal[i]);
         else arrSymbolDBB1State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB1WAITTILL" + " " + symbolListFinal[i]))
            arrDBB1WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB1WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB1WaitTill[i][0] = NULL;
      }

      if(useTimeframe2) {
         if(GlobalVariableCheck(indiName + " " + "DBB2" + " " + symbolListFinal[i]))
            arrSymbolDBB2State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB2" + " " + symbolListFinal[i]);
         else arrSymbolDBB2State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB2WAITTILL" + " " + symbolListFinal[i]))
            arrDBB2WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB2WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB2WaitTill[i][0] = NULL;
      }

      if(useTimeframe3) {
         if(GlobalVariableCheck(indiName + " " + "DBB3" + " " + symbolListFinal[i]))
            arrSymbolDBB3State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB3" + " " + symbolListFinal[i]);
         else arrSymbolDBB3State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB3WAITTILL" + " " + symbolListFinal[i]))
            arrDBB3WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB3WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB3WaitTill[i][0] = NULL;
      }

      if(useTimeframe4) {
         if(GlobalVariableCheck(indiName + " " + "DBB4" + " " + symbolListFinal[i]))
            arrSymbolDBB4State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB4" + " " + symbolListFinal[i]);
         else arrSymbolDBB4State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB4WAITTILL" + " " + symbolListFinal[i]))
            arrDBB4WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB4WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB4WaitTill[i][0] = NULL;
      }

      if(useTimeframe5) {
         if(GlobalVariableCheck(indiName + " " + "DBB5" + " " + symbolListFinal[i]))
            arrSymbolDBB5State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB5" + " " + symbolListFinal[i]);
         else arrSymbolDBB5State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB5WAITTILL" + " " + symbolListFinal[i]))
            arrDBB5WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB5WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB5WaitTill[i][0] = NULL;
      }

      if(useTimeframe6) {
         if(GlobalVariableCheck(indiName + " " + "DBB6" + " " + symbolListFinal[i]))
            arrSymbolDBB6State[i][0] = (int)GlobalVariableGet(indiName + " " + "DBB6" + " " + symbolListFinal[i]);
         else arrSymbolDBB6State[i][0] = -5;

         if(GlobalVariableCheck(indiName + " " + "DBB6WAITTILL" + " " + symbolListFinal[i]))
            arrDBB6WaitTill[i][0] = (datetime)GlobalVariableGet(indiName + " " + "DBB6WAITTILL" + " " + symbolListFinal[i]);
         else arrDBB6WaitTill[i][0] = NULL;
      }
   }
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(reason == 1 || reason == 2 || reason == 4 || reason == 5 || reason == 7 || reason == 9) {
      ObjectsDeleteAll(0, indiName, 0, OBJ_LABEL);
      GlobalVariablesDeleteAll(indiName);
      // Clean up lastAlerts array
      ArrayResize(lastAlerts, 0);
      numAlertRecords = 0;
   } else if(reason == 3) {
      for(int symbolIndex = 0; symbolIndex < numSymbols; symbolIndex++) {
         if(useTimeframe1) {
            GlobalVariableSet(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex], arrSymbolDBB1State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB1WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB1WaitTill[symbolIndex][0]);
         }

         if(useTimeframe2) {
            GlobalVariableSet(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex], arrSymbolDBB2State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB2WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB2WaitTill[symbolIndex][0]);
         }

         if(useTimeframe3) {
            GlobalVariableSet(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex], arrSymbolDBB3State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB3WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB3WaitTill[symbolIndex][0]);
         }

         if(useTimeframe4) {
            GlobalVariableSet(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex], arrSymbolDBB4State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB4WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB4WaitTill[symbolIndex][0]);
         }

         if(useTimeframe5) {
            GlobalVariableSet(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex], arrSymbolDBB5State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB5WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB5WaitTill[symbolIndex][0]);
         }

         if(useTimeframe6) {
            GlobalVariableSet(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex], arrSymbolDBB6State[symbolIndex][0]);
            GlobalVariableSet(indiName + " " + "DBB6WAITTILL" + " " + symbolListFinal[symbolIndex], arrDBB6WaitTill[symbolIndex][0]);
         }
      }
   }
}

//+------------------------------------------------------------------+
void getSymbols()
{
   string sep=",";
   ushort u_sep=StringGetCharacter(sep,0);
   StringSplit(symbols,u_sep,symbolList);
   numSymbols=ArraySize(symbolList);
   ArrayResize(symbolListFinal,numSymbols);
   for(int i=0; i<numSymbols; i++) {
      symbolListFinal[i]=symbolPrefix+symbolList[i]+symbolSuffix;
   }
}

//+------------------------------------------------------------------+
bool testSymbols()
{
   bool result=true;
   for(int i=0; i<numSymbols; i++) {
      double bid=MarketInfo(symbolListFinal[i],MODE_BID);
      if(GetLastError()==4106) {
         result=false;
         Alert("Can't find this symbol: "+symbolListFinal[i]+",\nPut symbols in Market Watch,\nDouble Check Prefix Or Suffix Settings,\nREMOVING INDICATOR FROM CHART.");
         ChartIndicatorDelete(0,0,indiName);
         break;
      }
   }
   return result;
}

//+------------------------------------------------------------------+
void OnTimer()
{
   CreateLabels();
   static datetime time1 = 0;
   static string mess1 = "";
   static string symb1 = "";
   
   string symb_listBZ = "";
   string symb_listSZ = "";
   for(int symbolIndex = 0; symbolIndex < numSymbols; symbolIndex++) {
      signcount = 0;
      if(useTimeframe1) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe1)) continue;
         else setLabelDBB1(symbolIndex);
      }

      if(useTimeframe2) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe2)) continue;
         else setLabelDBB2(symbolIndex);
      }

      if(useTimeframe3) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe3)) continue;
         else setLabelDBB3(symbolIndex);
      }

      if(useTimeframe4) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe4)) continue;
         else setLabelDBB4(symbolIndex);
      }

      if(useTimeframe5) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe5)) continue;
         else setLabelDBB5(symbolIndex);
      }

      if(useTimeframe6) {
         if(!download_history(symbolListFinal[symbolIndex], timeframe6)) continue;
         else setLabelDBB6(symbolIndex);
      }

      if(signcount == signgoal) {
         if(symb_listBZ == "") symb_listBZ = symbolListFinal[symbolIndex];
         else symb_listBZ = symb_listBZ + ", " + symbolListFinal[symbolIndex];
      }
      if(signcount == -signgoal) {
         if(symb_listSZ == "") symb_listSZ = symbolListFinal[symbolIndex];
         else symb_listSZ = symb_listSZ + ", " + symbolListFinal[symbolIndex];
      }
   }
   if(symb_listBZ != "") doAlert(symb_listBZ, time1, mess1, symb1, 0, "all TF at BZ");
   if(symb_listSZ != "") doAlert(symb_listSZ, time1, mess1, symb1, 0, "all TF at SZ");
}

//+------------------------------------------------------------------+
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[])
{
   return(rates_total);
}

//+------------------------------------------------------------------+
bool download_history(string symbol, ENUM_TIMEFRAMES period=PERIOD_CURRENT)
{
   if(period == PERIOD_CURRENT) period = (ENUM_TIMEFRAMES)_Period;
   ResetLastError();
   datetime other = iTime(symbol, period, 0);
   if(_LastError == 0 && other != 0) return true;
   if(_LastError != ERR_HISTORY_WILL_UPDATED && _LastError != ERR_NO_HISTORY_DATA)
      PrintFormat("iTime(%s,%i) Failed: %i", symbol, period, _LastError);
   return false;
}

//+------------------------------------------------------------------+
bool LabelCreate(const long chart_ID=0,
                 const string name="Label",
                 const int sub_window=0,
                 const int x=0,
                 const int y=0,
                 const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER,
                 const string text="Label",
                 const string font="Arial",
                 const int font_size=10,
                 const color clr=clrRed,
                 const double angle=0.0,
                 const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER,
                 const bool back=false,
                 const bool selection=false,
                 const bool hidden=true,
                 const long z_order=0)
{
   ResetLastError();
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) {
      Print(__FUNCTION__, ": failed to create text label! Error code = ",GetLastError());
      return(false);
   }
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); // Fixed: Removed stray '-' and added ';'
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
   return(true);
}

//+------------------------------------------------------------------+
string TimeframeToString(ENUM_TIMEFRAMES tf)
{
   switch(tf)
   {
      case PERIOD_M1:  return "M1";
      case PERIOD_M5:  return "M5";
      case PERIOD_M15: return "M15";
      case PERIOD_M30: return "M30";
      case PERIOD_H1:  return "H1";
      case PERIOD_H4:  return "H4";
      case PERIOD_D1:  return "D1";
      case PERIOD_W1:  return "W1";
      case PERIOD_MN1: return "MN";
      default: return "Unknown";
   }
}

//+------------------------------------------------------------------+
void CreateLabels()
{
   int textSpaceing = textH; // Initialize spacing
   ENUM_BASE_CORNER labelCornor = CORNER_LEFT_UPPER;
   ENUM_ANCHOR_POINT labelAnchor = ANCHOR_LEFT_UPPER;

   if(labelCornorAnchorChoice == LeftUpper) {
      labelCornor = CORNER_LEFT_UPPER;
      labelAnchor = ANCHOR_LEFT_UPPER;
   } else if(labelCornorAnchorChoice == RightUpper) {
      labelCornor = CORNER_RIGHT_UPPER;
      labelAnchor = ANCHOR_RIGHT_UPPER;
   }

   // Create header row
   if(ObjectFind(indiName + " " + "HEADER_SYM") != 0) {
      LabelCreate(0, indiName + " " + "HEADER_SYM", 0,
                 dashX, dashY, labelCornor, "",
                 Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
   }

   // Dynamically calculate X positions based on which timeframes are enabled
   int currentX = dashX + symXdbb1; // Starting X position after the symbol column

   if(useTimeframe1) {
      if(ObjectFind(indiName + " " + "HEADER_DBB1") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB1", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe1),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
      currentX += dbb1Xdbb2; // Increment X for the next column
   }

   if(useTimeframe2) {
      if(ObjectFind(indiName + " " + "HEADER_DBB2") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB2", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe2),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
      currentX += dbb2Xdbb3;
   }

   if(useTimeframe3) {
      if(ObjectFind(indiName + " " + "HEADER_DBB3") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB3", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe3),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
      currentX += dbb3Xdbb4;
   }

   if(useTimeframe4) {
      if(ObjectFind(indiName + " " + "HEADER_DBB4") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB4", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe4),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
      currentX += dbb4Xdbb5;
   }

   if(useTimeframe5) {
      if(ObjectFind(indiName + " " + "HEADER_DBB5") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB5", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe5),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
      currentX += dbb5Xdbb6;
   }

   if(useTimeframe6) {
      if(ObjectFind(indiName + " " + "HEADER_DBB6") != 0) {
         LabelCreate(0, indiName + " " + "HEADER_DBB6", 0,
                    currentX, dashY, labelCornor, TimeframeToString(timeframe6),
                    Font, fontText, headerColor, 0.0, labelAnchor, false, false, true, 0);
      }
   }

   // Start symbol rows immediately below the header (dashY + textH)
   int symbolStartY = dashY + textH; // Position for the first symbol row

   for(int i = 0; i < ArraySize(symbolListFinal); i++) {
      int currentY = symbolStartY + (i * textH); // Calculate Y position for each symbol row

      if(ObjectFind(indiName + " " + "SYM" + " " + symbolListFinal[i]) != 0) {
         LabelCreate(0, indiName + " " + "SYM" + " " + symbolListFinal[i], 0,
                    dashX, currentY, labelCornor, symbolListFinal[i],
                    Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
      }

      // Reset currentX for the data columns
      currentX = dashX + symXdbb1;

      if(useTimeframe1) {
         if(ObjectFind(indiName + " " + "DBB1" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB1" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
         currentX += dbb1Xdbb2;
      }

      if(useTimeframe2) {
         if(ObjectFind(indiName + " " + "DBB2" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB2" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
         currentX += dbb2Xdbb3;
      }

      if(useTimeframe3) {
         if(ObjectFind(indiName + " " + "DBB3" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB3" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
         currentX += dbb3Xdbb4;
      }

      if(useTimeframe4) {
         if(ObjectFind(indiName + " " + "DBB4" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB4" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
         currentX += dbb4Xdbb5;
      }

      if(useTimeframe5) {
         if(ObjectFind(indiName + " " + "DBB5" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB5" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
         currentX += dbb5Xdbb6;
      }

      if(useTimeframe6) {
         if(ObjectFind(indiName + " " + "DBB6" + " " + symbolListFinal[i]) != 0) {
            LabelCreate(0, indiName + " " + "DBB6" + " " + symbolListFinal[i], 0,
                       currentX, currentY, labelCornor, "POOP",
                       Font, fontText, symbolColor, 0.0, labelAnchor, false, false, true, 0);
         }
      }
   }
}
//+------------------------------------------------------------------+
int bollingerBandsState(int symbolIndex, ENUM_TIMEFRAMES timeframe)
{
   int result=0;
   double bidPrice=MarketInfo(symbolListFinal[symbolIndex],MODE_BID);

   double B1=iBands(symbolListFinal[symbolIndex],timeframe,20,1,0,PRICE_CLOSE,1,0);
   double C=iBands(symbolListFinal[symbolIndex],timeframe,20,1,0,PRICE_CLOSE,0,0);
   double B2=iBands(symbolListFinal[symbolIndex],timeframe,20,1,0,PRICE_CLOSE,2,0);
   double A1=iBands(symbolListFinal[symbolIndex],timeframe,20,2,0,PRICE_CLOSE,1,0);
   double A2=iBands(symbolListFinal[symbolIndex],timeframe,20,2,0,PRICE_CLOSE,2,0);

   if((bidPrice<=A1 && bidPrice>=B1) || (bidPrice>=A1)) result=1;  //Buy Zone
   else if(bidPrice<=B1 && bidPrice>=C) result=2;                   //Neutral Zone 1
   else if(bidPrice<=C && bidPrice>=B2) result=3;                   //Neutral Zone 2
   else if((bidPrice<=B2 && bidPrice>=A2) || (bidPrice<=A2)) result=4; //Sell Zone

   return result;
}

//+------------------------------------------------------------------+
void setLabelDBB1(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe1);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB1State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB1State[symbolIndex][0]=value;
      arrDBB1WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB1State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB1WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB1State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB1WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB1State[symbolIndex][0]=value;
         arrDBB1WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB1WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB1WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB1" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void setLabelDBB2(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe2);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB2State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB2State[symbolIndex][0]=value;
      arrDBB2WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB2State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB2WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB2State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB2WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB2State[symbolIndex][0]=value;
         arrDBB2WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB2WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB2WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB2" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void setLabelDBB3(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe3);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB3State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB3State[symbolIndex][0]=value;
      arrDBB3WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB3State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB3WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB3State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB3WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB3State[symbolIndex][0]=value;
         arrDBB3WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB3WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB3WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB3" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void setLabelDBB4(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe4);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB4State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB4State[symbolIndex][0]=value;
      arrDBB4WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB4State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB4WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB4State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB4WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB4State[symbolIndex][0]=value;
         arrDBB4WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB4WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB4WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB4" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void setLabelDBB5(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe5);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB5State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB5State[symbolIndex][0]=value;
      arrDBB5WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB5State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB5WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB5State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB5WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB5State[symbolIndex][0]=value;
         arrDBB5WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB5WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB5WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB5" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void setLabelDBB6(int symbolIndex)
{
   int value=bollingerBandsState(symbolIndex,timeframe6);
   color labelColor=clrWhite;
   string labelText="POOP";

   double prevSig=arrSymbolDBB6State[symbolIndex][0];
   if(prevSig==-5) {
      arrSymbolDBB6State[symbolIndex][0]=value;
      arrDBB6WaitTill[symbolIndex][0]=NULL;
   } else {
      if(value==1) {
         arrSymbolDBB6State[symbolIndex][0]=value;
         if(prevSig!=1) arrDBB6WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else if(value==4) {
         arrSymbolDBB6State[symbolIndex][0]=value;
         if(prevSig!=4) arrDBB6WaitTill[symbolIndex][0]=(TimeCurrent()+alertIntervalTimeSeconds);
      } else {
         arrSymbolDBB6State[symbolIndex][0]=value;
         arrDBB6WaitTill[symbolIndex][0]=NULL;
      }
   }

   if(arrDBB6WaitTill[symbolIndex][0]>TimeCurrent() && value==1) {
      if(ObjectFind(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex],"BZ",fontText,Font,BZNewStateColor);
   } else if(arrDBB6WaitTill[symbolIndex][0]>TimeCurrent() && value==4) {
      if(ObjectFind(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex],"SZ",fontText,Font,SZNewStateColor);
   } else {
      if(value==1) { labelColor=bzColor; labelText="BZ"; signcount++; }
      else if(value==2) { labelColor=naColor; labelText="NA"; }
      else if(value==3) { labelColor=nbColor; labelText="NB"; }
      else if(value==4) { labelColor=szColor; labelText="SZ"; signcount--; }
      else { labelColor=clrWhite; labelText="POOP"; }

      if(ObjectFind(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex]) == 0)
         ObjectSetText(indiName + " " + "DBB6" + " " + symbolListFinal[symbolIndex],labelText,fontText,Font,labelColor);
   }
}

//+------------------------------------------------------------------+
void doAlert(string& symbol, datetime& previousTime, string& previousAlert, string& previousSymbol, int forBar, string doWhat)
{
   string message;
   
   // Check if this combination of symbol and doWhat has been alerted recently
   bool canAlert = true;
   int recordIndex = -1;
   for(int i = 0; i < numAlertRecords; i++) {
      if(lastAlerts[i].symbol == symbol && lastAlerts[i].doWhat == doWhat) {
         recordIndex = i;
         if(TimeCurrent() < lastAlerts[i].lastAlertTime + alertIntervalTimeSeconds) {
            canAlert = false; // Too soon to alert again
         }
         break;
      }
   }

   if(canAlert) {
      // Update or add the alert record
      if(recordIndex == -1) {
         // New record
         ArrayResize(lastAlerts, numAlertRecords + 1);
         lastAlerts[numAlertRecords].symbol = symbol;
         lastAlerts[numAlertRecords].doWhat = doWhat;
         lastAlerts[numAlertRecords].lastAlertTime = TimeCurrent();
         numAlertRecords++;
      } else {
         // Update existing record
         lastAlerts[recordIndex].lastAlertTime = TimeCurrent();
      }

      // Generate the alert message
      message = StringConcatenate(symbol, " at ", TimeToStr(TimeLocal(), TIME_SECONDS), " DBB (", instanceID, ") - ", doWhat);
      
      if(alertsMessage) Alert(message);
      if(alertsNotify) SendNotification(message);
      if(alertsEmail) SendMail(StringConcatenate(symbol, " DBB (", instanceID, ") - "), message);
      if(alertsSound) PlaySound("alert2.wav");
   }
}