// version 1.01 10/22/21
// version 1.0 July 26th, 2020
// not for sale, rent, auction, nor lease
//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_chart_window
#property strict

extern string Symbols           = "GBPJPY;AUDJPY;NZDJPY;EURJPY;USDJPY;CHFJPY;";  // Symbols to use (separated by ";" in the list)
extern string TimeFrames        = "M5;M15;M30;H1;H4";        // Time frames to use (separated by ";" in the list)

//extern string TimeFrames        = "M1;M5;M15;M30;H1;H4;D1;W1;MN";        // Time frames to use (separated by ";" in the list)
extern int    CciPeriod         = 14;                                    // CCI period
extern ENUM_APPLIED_PRICE Price = PRICE_TYPICAL;                         // CCI price
extern double lStrongUp         =  200;                                  // Strong up level
extern double lStrongDown       = -200;                                  // Strong down level
extern int    BarToTest         = 0;                                     // Bar to test 
extern color  StrongUp          = clrLimeGreen;                          // Color for strong up
extern color  Neutral           = clrDarkGray;                           // Color for neutral
extern color  StrongDown        = clrOrangeRed;                          // Color for strong down
extern int    ColorSteps        = 41;                                    // Color steps for gradint colors
extern color  TextColor         = clrBlack;                              // Color for butons text
extern color  BorderColor       = clrBlack;                              // Color for butons border
extern color  FillColor         = clrSilver;                             // Color for butons background
extern int    Window            = 0;                                     // Window to use for display
extern ENUM_BASE_CORNER  Corner = CORNER_LEFT_LOWER;                     // Corner for display
extern int    XShift            = 0;                                     // Horizontal shift
extern int    YShift            = 0;                                     // Vertical shift
extern string UniqueID          = "CCIHeatmap2";                         // Indicator unique ID

extern string             button_note1          = "------------------------------";
extern int                btn_Subwindow         = 0;
extern ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER; // chart btn_corner for anchoring
extern string             btn_text              = "CCI";
extern string             btn_Font              = "Arial";
extern int                btn_FontSize          = 10;                                 //btn__font size
extern color              btn_text_ON_color     = clrLime;
extern color              btn_text_OFF_color    = clrRed;
extern color              btn_background_color  = clrDimGray;
extern color              btn_border_color      = clrBlack;
extern int                button_x              = 20;                                         //btn__x
extern int                button_y              = 13;                                         //btn__y
extern int                btn_Width             = 60;                                     //btn__width
extern int                btn_Height            = 20;                                    //btn__height
extern string             button_note2          = "------------------------------";

bool                      show_data             = true;
string IndicatorName, IndicatorObjPrefix;
//template code end1
int    cpairsLen,ctimesLen, aTimes[];
string cpairs[];
color  colors[];
//+------------------------------------------------------------------------------------------------------------------+
string GenerateIndicatorName(const string target) //don't change anything here
{
   string name = target;
   int try = 2;
   while (WindowFind(name) != -1)
   {
      name = target + " #" + IntegerToString(try++);
   }
   return name;
}
//+------------------------------------------------------------------------------------------------------------------+
string buttonId;

int OnInit()
{
   IndicatorName = GenerateIndicatorName(btn_text);
   IndicatorObjPrefix = "__" + IndicatorName + "__";
   IndicatorShortName(IndicatorName);
   IndicatorDigits(Digits);
   
   double val;
   if (GlobalVariableGet(IndicatorName + "_visibility", val))
      show_data = val != 0;

// put init() here
   Symbols = StringTrimLeft(StringTrimRight(Symbols)); 
   if (StringSubstr(Symbols,StringLen(Symbols)-1,1) != ";")
                    Symbols = StringConcatenate(Symbols,";");

   TimeFrames = StringTrimLeft(StringTrimRight(TimeFrames));
   if (StringSubstr(TimeFrames,StringLen(TimeFrames)-1,1) != ";")
                    TimeFrames = StringConcatenate(TimeFrames,";");

      //
      //
      //
      //
      //
   
      int s = 0, i = StringFind(Symbols,";",s);
         while (i > 0)
         {
            string current = StringSubstr(Symbols,s,i-s);
            ArrayResize(cpairs,ArraySize(cpairs)+1);
                        cpairs[ArraySize(cpairs)-1] = current;
                        s = i + 1;
                        i = StringFind(Symbols,";",s);
         }
      if (Corner==CORNER_LEFT_LOWER  || Corner==CORNER_RIGHT_LOWER) invertArray(cpairs);  cpairsLen = ArraySize(cpairs);
      s = 0; i = StringFind(TimeFrames,";",s);
         while (i > 0)
         {
            string current = StringSubstr(TimeFrames,s,i-s);
            int time = stringToTimeFrame(current);
            if (time > 0) {
                  ArrayResize(aTimes,ArraySize(aTimes)+1);
                              aTimes[ArraySize(aTimes)-1] = time; }
                              s = i + 1;
                                  i = StringFind(TimeFrames,";",s);
         }
      if (Corner==CORNER_RIGHT_UPPER || Corner==CORNER_RIGHT_LOWER) invertiArray(aTimes); ctimesLen = ArraySize(aTimes);

      //
      //
      //
      //
      //
               
      if (ColorSteps%2==0) ColorSteps++;
         ArrayResize(colors,ColorSteps);
         int half = ColorSteps/2;
            for (i=0; i<half; i++)
               {
                  colors[i             ] = gradientColor(i+1,half,StrongUp  ,Neutral);
                  colors[ColorSteps-i-1] = gradientColor(i+1,half,StrongDown,Neutral);
               }      
               colors[i] = Neutral;            

   ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_MOVE, 1);
   buttonId = IndicatorObjPrefix + UniqueID;
   createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(ChartID(), buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(ChartID(), buttonId, OBJPROP_XDISTANCE, button_x);
   
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------------------------------------------------------+
//don't change anything here
void createButton(string buttonID,string buttonText,int width,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor)
{
      ObjectDelete    (ChartID(),buttonID);
      ObjectCreate    (ChartID(),buttonID,OBJ_BUTTON,btn_Subwindow,0,0);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_COLOR,txtColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_BGCOLOR,bgColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_BORDER_COLOR,borderColor);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_XSIZE,width);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_YSIZE,height);
      ObjectSetString (ChartID(),buttonID,OBJPROP_FONT,font);
      ObjectSetString (ChartID(),buttonID,OBJPROP_TEXT,buttonText);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_FONTSIZE,fontSize);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_SELECTABLE,0);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_CORNER,btn_corner);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_HIDDEN,1);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_XDISTANCE,9999);
      ObjectSetInteger(ChartID(),buttonID,OBJPROP_YDISTANCE,9999);
}
//+------------------------------------------------------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll(ChartID(), IndicatorObjPrefix);

//put deinit() here
   int idLength = StringLen(UniqueID);
   for (int i = ObjectsTotal(); i>=0; i--)
         { string name = ObjectName(i); if (StringSubstr(name,0,idLength) == UniqueID) ObjectDelete(name); }         

	return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
//don't change anything here
bool recalc = true;

void handleButtonClicks()
{
   if (ObjectGetInteger(ChartID(), buttonId, OBJPROP_STATE))
   {
      ObjectSetInteger(ChartID(), buttonId, OBJPROP_STATE, false);
      show_data = !show_data;
      GlobalVariableSet(IndicatorName + "_visibility", show_data ? 1.0 : 0.0);
      recalc = true;
      start();
   }
}
//+------------------------------------------------------------------------------------------------------------------+
void OnChartEvent(const int id, //don't change anything here
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if (id==CHARTEVENT_OBJECT_CLICK && ObjectGet(sparam,OBJPROP_TYPE)==OBJ_BUTTON)
   {   
      if (StringFind(sparam,UniqueID+"t",0)==0)          
            ChartSetSymbolPeriod(0,ObjectGetString(0,sparam,OBJPROP_TEXT),_Period);
      if (StringFind(sparam,UniqueID+"h",0)==0)          
            ChartSetSymbolPeriod (0,_Symbol,stringToTimeFrame(ObjectGetString(0,sparam,OBJPROP_TEXT)));
   }
   handleButtonClicks();
}
//+------------------------------------------------------------------------------------------------------------------+
string GetButtonState(string whichbutton)
{
      bool selected = ObjectGetInteger(ChartID(),whichbutton,OBJPROP_STATE);
      if (selected)
           { return ("on"); } 
      else { return ("off");}
}
//+------------------------------------------------------------------------------------------------------------------+
int start()
{
   handleButtonClicks();
   recalc = false;
   int xshift=0, nxshift=0; if (Corner==CORNER_RIGHT_LOWER || Corner==CORNER_RIGHT_UPPER) { xshift=49; nxshift=66; }
   for (int i = 0; i < cpairsLen; i++ ) ButtonCreate2(ChartID(),UniqueID+"t"+(string)i,Window,XShift+nxshift+2,YShift+30+i*15,66,14,Corner,cpairs[i]                   ,"Arial",9,TextColor,BorderColor,FillColor);
   for (int i = 0; i < ctimesLen; i++ ) ButtonCreate2(ChartID(),UniqueID+"h"+(string)i,Window,XShift+xshift+i*50+69,YShift+15,49,14,Corner,timeFrameToString(aTimes[i]),"Arial",9,TextColor,BorderColor,FillColor);
   for (int i = 0; i < cpairsLen; i++)
      if (iClose(cpairs[i],0,0)!=0) for (int t = 0; t < ctimesLen; t++)
      {
         double value    = iCCI(cpairs[i],aTimes[t],CciPeriod,Price,BarToTest);
         int    step     = (int)((ColorSteps-1)*(MathMax(MathMin(value,lStrongUp),lStrongDown)-lStrongDown)/(lStrongUp-lStrongDown));
         color  theColor = colors[ColorSteps-step-1];
            ButtonCreate2(ChartID(),UniqueID+(string)t+(string)i,Window,XShift+xshift+t*50+69,YShift+30+i*15,49,14,Corner," ","arial",10,theColor,BorderColor,theColor);
      }
   if (Corner==CORNER_RIGHT_UPPER || Corner==CORNER_RIGHT_LOWER)
         ButtonCreate2(ChartID(),UniqueID+"title",Window,XShift+xshift+ctimesLen*50+19,YShift+30+cpairsLen*15,ctimesLen*50-1,14,Corner," CCI ("+(string)CciPeriod+")","arial",10,TextColor,BorderColor,FillColor);
   else  ButtonCreate2(ChartID(),UniqueID+"title",Window,XShift+xshift+69             ,YShift+30+cpairsLen*15,ctimesLen*50-1,14,Corner," CCI ("+(string)CciPeriod+")","arial",10,TextColor,BorderColor,FillColor);

      if (!show_data)
       {
       ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_OFF_color);
       int idLength = StringLen(UniqueID);
       for (int i = ObjectsTotal(); i>=0; i--)
         { string name = ObjectName(i); if (StringSubstr(name,0,idLength) == UniqueID) ObjectDelete(name); }         
       }
      else       ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_ON_color);

   return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
bool ButtonCreate2(const long              chart_ID=0,               // chart's ID 
                  const string            name="Button",            // button name 
                  const int               sub_window=0,             // subwindow index 
                  const int               x=0,                      // X coordinate 
                  const int               y=0,                      // Y coordinate 
                  const int               width=50,                 // button width 
                  const int               height=18,                // button height 
                  const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // chart corner for anchoring 
                  const string            text="Button",            // text 
                  const string            font="Arial",             // font 
                  const int               font_size=10,             // font size 
                  const color             clr=clrBlack,             // text color 
                  const color             clrBorder=clrBlack,       // border color 
                  const color             back_clr=clrGray,         // background color 
                  const bool              state=true,              // pressed/released 
                  const bool              back=false,               // in the background 
                  const bool              selection=false,          // highlight to move 
                  const bool              hidden=true,              // hidden in the object list 
                  const long              z_order=0)                // priority for mouse click 
{ 
      ObjectCreate    (chart_ID,name,OBJ_BUTTON,sub_window,0,0);
      ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
      ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
      ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width); 
      ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height); 
      ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); 
      ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size); 
      ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
      ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr); 
      ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_COLOR,clrBorder); 
      ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,BORDER_FLAT); 
      ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
      ObjectSetInteger(chart_ID,name,OBJPROP_STATE,state); 
      ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); 
      ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); 
      ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); 
      ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); 
      ObjectSetString (chart_ID,name,OBJPROP_TEXT,text); 
      ObjectSetString (chart_ID,name,OBJPROP_FONT,font); 
      return(true); 
} 
//+------------------------------------------------------------------------------------------------------------------+
string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

int stringToTimeFrame(string tfs)
{
   StringToUpper(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+(string)iTfTable[i]) return(iTfTable[i]);
                                                              return(_Period);
}
//+------------------------------------------------------------------------------------------------------------------+
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}
//+------------------------------------------------------------------------------------------------------------------+
void invertArray(string& array[])
{
   string temp[]; ArrayCopy(temp,array); for (int i=0, s=ArraySize(array); i<s; i++) array[i] = temp[s-i-1];
}
void invertiArray(int& array[])
{
   int temp[]; ArrayCopy(temp,array); for (int i=0, s=ArraySize(array); i<s; i++) array[i] = temp[s-i-1];
}
//+------------------------------------------------------------------------------------------------------------------+
color gradientColor(int step, int totalSteps, color from, color to)
{
   color newBlue  = getColor(step,totalSteps,(from & 0XFF0000)>>16,(to & 0XFF0000)>>16)<<16;
   color newGreen = getColor(step,totalSteps,(from & 0X00FF00)>> 8,(to & 0X00FF00)>> 8) <<8;
   color newRed   = getColor(step,totalSteps,(from & 0X0000FF)    ,(to & 0X0000FF)    )    ;
   return(newBlue+newGreen+newRed);
}
color getColor(int stepNo, int totalSteps, color from, color to)
{
   double step = (from-to)/(totalSteps-1.0);
   return((color)MathRound(from-step*stepNo));
}
//+------------------------------------------------------------------------------------------------------------------+
