//+------------------------------------------------------------------+
//|                                              Balls Dashboard.mq4 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright ""
#property link      ""
#property indicator_chart_window
#property indicator_buffers 0

extern int X_Position = 2;
extern int Y_Position = 5;
extern color Font_Color = Black;
extern color Border_Color = Black;
extern color Empty_Box_Color = White;

extern string _alerts = "--- Alerts ---";
extern bool OnlySound = false;
extern bool M5_Alerts = true;
extern bool H1_Alerts = true;
extern bool H4_Alerts = true;
extern bool D1_Alerts = true;
extern bool W1_Alerts = true;

extern string _sem_colors = "--- Semaphore Colors ---";
extern color Up_Ball_2 = Green;
extern color Down_Ball_2 = Red;
extern color Up_Ball_3 = Green;
extern color Down_Ball_3 = Red;

extern string _nld_colors = "--- NLD Trend Colors ---";
extern color NLD_Trend_Up = Green;
extern color NLD_Trend_Down = Red;

extern string _nld_column_colors = "--- NLD Above/Below Colors ---";
extern color Price_Below_NLD = Green;
extern color Price_Above_NLD = Red;
extern color Price_Equal_NLD = Yellow;

extern string _sem_m5 = "--- Semaphore M5 settings ---";
extern int M5_eintDepth1 = 5;
extern int M5_eintDepth2 = 13;
extern int M5_eintDepth3 = 34;
extern string _nonlagdot_m5 = "--- NonLagDot M5 settings ---";
extern int M5_Length = 20;

extern string _sem_h1 = "--- Semaphore H1 settings ---";
extern int H1_eintDepth1 = 5;
extern int H1_eintDepth2 = 13;
extern int H1_eintDepth3 = 34;
extern string _nonlagdot_h1 = "--- NonLagDot H1 settings ---";
extern int H1_Length = 20;

extern string _sem_h4 = "--- Semaphore H4 settings ---";
extern int H4_eintDepth1 = 5;
extern int H4_eintDepth2 = 13;
extern int H4_eintDepth3 = 34;
extern string _nonlagdot_h4 = "--- NonLagDot H4 settings ---";
extern int H4_Length = 20;

extern string _sem_d1 = "--- Semaphore Daily settings ---";
extern int D1_eintDepth1 = 5;
extern int D1_eintDepth2 = 13;
extern int D1_eintDepth3 = 34;
extern string _nonlagdot_d1 = "--- NonLagDot Daily settings ---";
extern int D1_Length = 20;

extern string _sem_w1 = "--- Semaphore Weekly settings ---";
extern int W1_eintDepth1 = 5;
extern int W1_eintDepth2 = 13;
extern int W1_eintDepth3 = 34;
extern string _nonlagdot_w1 = "--- NonLagDot Weekly settings ---";
extern int W1_Length = 20;


string objPrefix = "";
int window = -1;
bool starting = true;

string pairs[28] = {"USDJPY", "EURJPY", "GBPJPY", "CHFJPY", "CADJPY", "AUDJPY", "EURUSD", "GBPUSD", "AUDUSD", "NZDUSD", 
   "USDCAD", "AUDCAD", "EURCAD", "USDCHF", "GBPCHF", "EURCHF", "EURGBP", "EURAUD", "AUDNZD", "NZDCAD", "NZDJPY", "NZDCHF", 
   "EURNZD", "GBPNZD", "CADCHF", "AUDCHF", "GBPCAD", "GBPAUD"};

datetime alertTimes[32][10];
int periods[5] = { PERIOD_M5, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1 };


int init() {
   string sufix = StringSubstr(Symbol(), 6);

   for(int i=ArraySize(pairs)-1; i>=0; i--){      
      pairs[i] = pairs[i] + sufix;
   }
   
   for(i=ArraySize(pairs)-1; i>=0; i--)
      for(int j=ArraySize(periods)-1; j>=0; j--)
         alertTimes[i][j] = 0;
   
   return (0);
}

int deinit() {
   DelObjects();
   return (0);
}

int start() {
   /*if(window < 0)
      window = WindowOnDropped();   
   
   if(window >= WindowsTotal())
      window = WindowsTotal() - 1;
  */
   window = 0;   
   
   if(starting){
      objPrefix = "BlDshb#" + X_Position + "#" + Y_Position + "#" + window + "#";      
      Draw();    
      starting = false;  
   }
   
   int nSymbols = ArraySize(pairs);        
   
   for(int y=0; y<nSymbols; y++){
      string symbol = pairs[y];
      
      if(!SymbolExists(symbol)) continue;
            
      UpdateCell(0, y, symbol, PERIOD_M5, 2);
      UpdateCell(1, y, symbol, PERIOD_M5, 3);
      
      UpdateCell(2, y, symbol, PERIOD_H1, 2);
      UpdateCell(3, y, symbol, PERIOD_H1, 3);
      
      UpdateCell(4, y, symbol, PERIOD_H4, 2);
      UpdateCell(5, y, symbol, PERIOD_H4, 3);
      
      UpdateCell(6, y, symbol, PERIOD_D1, 2);
      UpdateCell(7, y, symbol, PERIOD_D1, 3);
      
      UpdateCell(8, y, symbol, PERIOD_W1, 2);
      UpdateCell(9, y, symbol, PERIOD_W1, 3); 
      
      if(M5_Alerts) CheckAlerts(y, 0);
      if(H1_Alerts) CheckAlerts(y, 1);
      if(H4_Alerts) CheckAlerts(y, 2);
      if(D1_Alerts) CheckAlerts(y, 3);
      if(W1_Alerts) CheckAlerts(y, 4);
   }
   
   WindowRedraw();
   return (0);
}

void CheckAlerts(int symIndex, int perIndex){
   string symbol = pairs[symIndex];
   int tf = periods[perIndex];
   datetime curTime = iTime(symbol, tf, 1);
   datetime lastTime = alertTimes[symIndex][perIndex];
   alertTimes[symIndex][perIndex] = curTime;
   
   if(curTime <= lastTime) return;
   
   bool b2Up = BallUp(symbol, tf, 2);
   bool b3Up = BallUp(symbol, tf, 3);
   bool b2Dw = BallDown(symbol, tf, 2);
   bool b3Dw = BallDown(symbol, tf, 3);
   
   int nld = NonLagDir(symbol, tf);
   int aboveBelow = AboveBelowNLD(symbol, tf);
   
   if(b2Up && nld > 0){
      if(aboveBelow > 0)
         SendAlert("Green-Green-Green Ball 2", symbol, tf);
      else
         SendAlert("Green-Green Ball 2", symbol, tf);
   }
   
   if(b3Up && nld > 0){
      if(aboveBelow > 0)
         SendAlert("Green-Green-Green Ball 3", symbol, tf);
      else
         SendAlert("Green-Green Ball 3", symbol, tf);
   }   
      
   if(b2Dw && nld < 0){
      if(aboveBelow < 0)
         SendAlert("Red-Red-Red Ball 2", symbol, tf);
      else
         SendAlert("Red-Red Ball 2", symbol, tf);
   }
   
   if(b3Dw && nld < 0){
      if(aboveBelow < 0)
         SendAlert("Red-Red-Red Ball 3", symbol, tf);
      else
         SendAlert("Red-Red Ball 3", symbol, tf);
   }
}

void SendAlert(string txt, string symbol, int tf){
   if(OnlySound)
      PlaySound("Alert.wav");
   else
      Alert(txt + " on " + symbol + " " + PeriodToStr(tf));
}

void UpdateCell(int x, int y, string symbol, int tf, int ball){  
   if(Loaded(symbol, tf)){
         int nld = 0;
         int aboveBelow = 0;
         color col = Empty_Box_Color;
         color col2 = Empty_Box_Color;
         color col3 = Empty_Box_Color;
         
         bool bUp = BallUp(symbol, tf, ball);
         bool bDw = BallDown(symbol, tf, ball);         
                
         if(bUp || bDw){
            nld = NonLagDir(symbol, tf);
            aboveBelow = AboveBelowNLD(symbol, tf);
            
            if(bUp){
               if(ball == 2) col = Up_Ball_2;
               if(ball == 3) col = Up_Ball_3;
            }else if(bDw){
               if(ball == 2) col = Down_Ball_2;
               if(ball == 3) col = Down_Ball_3;
            }
            
            if(nld > 0) col2 = NLD_Trend_Up;
            else if(nld < 0) col2 = NLD_Trend_Down;
            
            if(aboveBelow > 0) col3 = Price_Below_NLD;
            else if(aboveBelow < 0) col3 = Price_Above_NLD;
            else col3 = Price_Equal_NLD;                                              
         }                  
               
         UpdateBox(BoxX(x), BoxY(y), col);
         UpdateLabel(LabelX(x), LabelY(y), CharToStr(32));
         
         UpdateBox(BoxX(x, 0.34), BoxY(y), col2);
         UpdateLabel(LabelX(x, 0.34), LabelY(y), CharToStr(32));
         
         UpdateBox(BoxX(x, 0.66), BoxY(y), col3);
         UpdateLabel(LabelX(x, 0.66), LabelY(y), CharToStr(32));
   }
}

bool Loaded(string pair, int tf){
   return(iBars(pair, tf) > 50);
}

bool SymbolExists(string symbol){
   return(MarketInfo(symbol, MODE_BID) > 0);
}

int NonLagDir(string pair, int tf){
   double up = NonLagDot(pair, tf, 1, 1);
   
   if(up != EMPTY_VALUE && up > 0) return(1);
   
   double down = NonLagDot(pair, tf, 2, 1);
   
   if(down != EMPTY_VALUE && down > 0) return(-1);
   
   return(0);
}

int AboveBelowNLD(string pair, int tf){   
   double val = NonLagDot(pair, tf, 0, 1);
   double close = iClose(pair, tf, 1);
   
   if(val != EMPTY_VALUE && val > 0){
      val = NormalizeDouble(val, MarketInfo(pair, MODE_DIGITS));
      
      if(val > close) return(1);
      if(val < close) return(-1);
   }
   
   return(0);
}

double NonLagDot(string pair, int tf, int buf, int bar){
   int len;
   
   switch(tf){
      case PERIOD_M5:
         len = M5_Length;        
         break;
      case PERIOD_H1:
         len = H1_Length;        
         break;
      case PERIOD_H4:
         len = H4_Length;         
         break;
      case PERIOD_D1:
         len = D1_Length;        
         break;
      case PERIOD_W1:
         len = W1_Length;        
         break;
   }
   
   return(iCustom(pair, tf, "_nonlagdot", 
         0, len, 0, 0, 1, 0, 0, 10,
         buf, bar));
}

bool BallUp(string pair, int tf, int ball){
   return(Indicator(pair, tf, ball-1, 1) > 0.0);
}

bool BallDown(string pair, int tf, int ball){
   return(Indicator(pair, tf, ball+2, 1) > 0.0);
}

double Indicator(string pair, int tf, int buf, int bar){
   int depth1, depth2, depth3;
   
   switch(tf){
      case PERIOD_M5:
         depth1 = M5_eintDepth1;
         depth2 = M5_eintDepth2;
         depth3 = M5_eintDepth3;
         break;
      case PERIOD_H1:
         depth1 = H1_eintDepth1;
         depth2 = H1_eintDepth2;
         depth3 = H1_eintDepth3;
         break;
      case PERIOD_H4:
         depth1 = H4_eintDepth1;
         depth2 = H4_eintDepth2;
         depth3 = H4_eintDepth3;
         break;
      case PERIOD_D1:
         depth1 = D1_eintDepth1;
         depth2 = D1_eintDepth2;
         depth3 = D1_eintDepth3;
         break;
      case PERIOD_W1:
         depth1 = W1_eintDepth1;
         depth2 = W1_eintDepth2;
         depth3 = W1_eintDepth3;
         break;
   }

   return(iCustom(pair, tf, "SemaphorTrue2", 
         depth1, depth2, depth3, 50.0, 10, 
         buf, bar));
}

void DelObjects(){
   int total = ObjectsTotal();
   
   for(int i=total-1; i>=0; i--){
      string name = ObjectName(i);
      
      if(StringFind(name, objPrefix) == 0)
         ObjectDelete(name);
   }
}

int Font_Size = 10;
int Row_Height = 20;
int Column_Width = 120;
int First_Col_Width = 76;
int offy = 3;
int offx = 10;
int dy2 = 10;

int BoxX(int x, double plus = 0.0){   
   return(X_Position+First_Col_Width+(x+plus)*Column_Width+5);
}

int BoxY(int y){
   return(Y_Position+(y+2)*Row_Height+9);
}

void Draw(){
   int columns = 11;
   int nSymbols = ArraySize(pairs);   
   
   // boxes
   for(int x=0; x<columns-1; x++)
      for(int y=0; y<nSymbols; y++){
         DrawBox(BoxX(x), BoxY(y), 16, 3, Empty_Box_Color);
         DrawBox(BoxX(x, 0.34), BoxY(y), 16, 3, Empty_Box_Color);
         DrawBox(BoxX(x, 0.66), BoxY(y), 16, 3, Empty_Box_Color);
      }
   
   // vertical bold lines 
   for(int i=0; i<columns; i++)
      for(int j=0; j<=nSymbols+1; j++)
         if(j > 0 || i % 2 == 0)
            DrawLine(X_Position+First_Col_Width+i*Column_Width+18, Y_Position+j*Row_Height+10, 10, 6, true, true);
      
   // vertical bold lines for first column (symbols)
   for(j=0; j<=nSymbols+1; j++)
         DrawLine(X_Position+18, Y_Position+j*Row_Height+10, 10, 6, true, true);
      
   // vertical dashed lines dividing each first column
   for(i=0; i<columns-1; i++)
      for(j=1; j<=nSymbols+1; j++)
         DrawLine(X_Position+First_Col_Width+(i+0.34)*Column_Width+15, Y_Position+j*Row_Height+10, 10, 6, true, false);
         
   // vertical dashed lines dividing each NLD column
   for(i=0; i<columns-1; i++)
      for(j=1; j<=nSymbols+1; j++)
         DrawLine(X_Position+First_Col_Width+(i+0.66)*Column_Width+15, Y_Position+j*Row_Height+10, 10, 6, true, false);
      
   // horizontal bold lines 
   for(i=0; i<columns-1; i++)
      for(j=0; j<=nSymbols+2; j++)   
         DrawLine(X_Position+First_Col_Width+i*Column_Width+6, Y_Position+j*Row_Height, 10, 31, false, true);
      
   // horizontal bold lines for first column (pairs)
   for(j=0; j<=nSymbols+2; j++)   
         DrawLine(X_Position+6, Y_Position+j*Row_Height, 10, 25, false, true);
      
   DrawLabel(X_Position+offx, LabelY(-1), "Pairs");
   
   // symbols labels
   for(i=1; i<=nSymbols; i++)
      DrawLabel(X_Position+offx, LabelY(i-1), StringSubstr(pairs[i-1], 0, 6));
      
   DrawLabel(LabelX(0, 0.8), LabelY(-2), "5 Min");
   DrawLabel(LabelX(2, 0.8), LabelY(-2), "1 Hour");
   DrawLabel(LabelX(4, 0.8), LabelY(-2), "4 Hour");
   DrawLabel(LabelX(6, 0.8), LabelY(-2), "1 Day");
   DrawLabel(LabelX(8, 0.77), LabelY(-2), "1 Week");
      
   DrawLabel(LabelX(0), LabelY(-1), "2Ball");
   DrawLabel(LabelX(0, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(0, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(1), LabelY(-1), "3Ball");
   DrawLabel(LabelX(1, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(1, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(2), LabelY(-1), "2Ball");
   DrawLabel(LabelX(2, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(2, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(3), LabelY(-1), "3Ball");
   DrawLabel(LabelX(3, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(3, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(4), LabelY(-1), "2Ball");
   DrawLabel(LabelX(4, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(4, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(5), LabelY(-1), "3Ball");
   DrawLabel(LabelX(5, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(5, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(6), LabelY(-1), "2Ball");
   DrawLabel(LabelX(6, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(6, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(7), LabelY(-1), "3Ball");
   DrawLabel(LabelX(7, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(7, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(8), LabelY(-1), "2Ball");
   DrawLabel(LabelX(8, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(8, 0.66), LabelY(-1), "Pullb.");
   DrawLabel(LabelX(9), LabelY(-1), "3Ball");
   DrawLabel(LabelX(9, 0.34), LabelY(-1), "Trend");
   DrawLabel(LabelX(9, 0.66), LabelY(-1), "Pullb.");
   
   for(x=0; x<columns-1; x++)
      for(y=0; y<nSymbols; y++){
         string txt = "Wait";
         
         if(!SymbolExists(pairs[y]))
            txt = "  ---";
         
         DrawLabel(LabelX(x), LabelY(y), txt);
         DrawLabel(LabelX(x, 0.34), LabelY(y), txt);
         DrawLabel(LabelX(x, 0.66), LabelY(y), txt);
      }
}         

int LabelX(int x, double plus = 0.0){  
   return(X_Position+First_Col_Width+(x+plus)*Column_Width+offx);
}

int LabelY(int y){
   return(Y_Position+(y+2)*Row_Height+dy2+offy);
}

void DrawLabel(int x, int y, string text, string font = "Arial", color col = 0){
   string name = objPrefix + "txt#" + x + "#" + y;
   
   if(col == 0) col = Font_Color;
   
   ObjectCreate(name, OBJ_LABEL, window, 0, 0);
   ObjectSet(name, OBJPROP_CORNER, 0);
   ObjectSet(name, OBJPROP_XDISTANCE, x);
   ObjectSet(name, OBJPROP_YDISTANCE, y);
   ObjectSetText(name, text, Font_Size, font, col);
}

void DrawLine(int x, int y, int size, int len, bool vertical, bool bold){
   string name = objPrefix + "ln#" + x + "#" + y + "#" + vertical;
   string txt = "-";
   string font = "Arial";
   
   for(int i=2; i<len; i++)
      txt = StringConcatenate(txt, "-");
   
   if(ObjectCreate(name, OBJ_LABEL, window, 0, 0)){      
      ObjectSet(name, OBJPROP_XDISTANCE, x);
      ObjectSet(name, OBJPROP_YDISTANCE, y);
      ObjectSet(name, OBJPROP_CORNER, 0);
      
      if(vertical)
         ObjectSet(name, OBJPROP_ANGLE, -90);
      else
         ObjectSet(name, OBJPROP_ANGLE, 0);
   }
   
   if(bold)
      font = "Arial Black";
   
   ObjectSetText(name, txt, size, font, Border_Color);
}

void UpdateLabel(int x, int y, string text){
   string name = objPrefix + "txt#" + x + "#" + y;
   
   ObjectSetText(name, text, Font_Size);
}

void UpdateBox(int x, int y, color col){
   string name = objPrefix + "box#" + x + "#" + y;
   
   ObjectSet(name, OBJPROP_COLOR, col);
   ObjectSetText(name, ObjectDescription(name), ObjectGet(name, OBJPROP_FONTSIZE), "Webdings", col);
}

void DrawBox(int x, int y, int size, int len, color col){
   string name = objPrefix + "box#" + x + "#" + y;
   string txt = "g";
   
   for(int i=2; i<len; i++)
      txt = StringConcatenate(txt, "g");
   
   if(ObjectCreate(name, OBJ_LABEL, window, 0, 0)){      
      ObjectSet(name, OBJPROP_XDISTANCE, x);
      ObjectSet(name, OBJPROP_YDISTANCE, y);
      ObjectSet(name, OBJPROP_CORNER, 0);
      ObjectSet(name, OBJPROP_BACK, true);
      ObjectSet(name, OBJPROP_COLOR, col);
   }
   
   ObjectSetText(name, txt, size, "Webdings", col);
}

string PeriodToStr(int p){
   switch(p){
      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("Daily");
      case PERIOD_W1: return("Weekly");
      case PERIOD_MN1: return("Monthly");
      default: return("" + Period());
   }
}

