Spread_List

Author: Copyright 2018, MetaQuotes Software Corp.
Price Data Components
Series array that contains open time of each bar
0 Views
0 Downloads
0 Favorites
Spread_List
ÿþ//+------------------------------------------------------------------+

//|                                                  Spread_List.mq5 |

//|                        Copyright 2018, MetaQuotes Software Corp. |

//|                                                 https://mql5.com |

//+------------------------------------------------------------------+

#property copyright "Copyright 2018, MetaQuotes Software Corp."

#property link      "https://mql5.com"

#include <Canvas\Canvas.mqh>

#include <Arrays\ArrayObj.mqh>

#include <Arrays\ArrayString.mqh>

#include <Arrays\ArrayInt.mqh>

//+------------------------------------------------------------------+

//| ;0AA->:=>                                                       |

//+------------------------------------------------------------------+

enum ENUM_MOUSE_STATE

  {

   MOUSE_STATE_NOT_PRESSED,

   MOUSE_STATE_PRESSED_OUTSIDE_WINDOW,

   MOUSE_STATE_PRESSED_INSIDE_WINDOW,

   MOUSE_STATE_PRESSED_INSIDE_HEADER,

   MOUSE_STATE_OUTSIDE_WINDOW,

   MOUSE_STATE_INSIDE_WINDOW,

   MOUSE_STATE_INSIDE_HEADER

  };

//+------------------------------------------------------------------+

//|                                                                  |

//+------------------------------------------------------------------+

class CWnd

  {

protected:

   CCanvas           m_canvas;

   CCanvas           m_field;

   long              m_chart_id;

   int               m_chart_w;

   int               m_chart_h;

   int               m_sub_wnd;

   string            m_name;

   string            m_caption;

   string            m_caption_font;

   string            m_name_gv_x;

   string            m_name_gv_y;

   color             m_color_bg;

   color             m_color_border;

   color             m_color_bg_header;

   color             m_color_caption;

   color             m_color_texts;

   uchar             m_alpha_bg;

   uchar             m_alpha_head;

   int               m_x;

   int               m_y;

   int               m_w;

   int               m_h;

   int               m_y_act;

   int               m_caption_font_size;

   uint              m_caption_alignment;

   uint              m_x_caption;

   bool              m_is_visible;

   bool              m_header_on;

   bool              m_movable;

   bool              m_wider_wnd;

   bool              m_higher_wnd;

   ENUM_PROGRAM_TYPE m_program_type;

   ENUM_MOUSE_STATE  m_mouse_state;

   ENUM_MOUSE_STATE  MouseButtonState(const int x,const int y,bool pressed);

   void              Move(int x,int y);

   bool              CreateCanvas(CCanvas &canvas,const int wnd_id,const int x,const int y,const int w,const int h);

   void              DrawHeaderArea(const string caption);

   void              RedrawHeaderArea(const color clr_area,const color clr_caption);

   string            TimeframeToString(const ENUM_TIMEFRAMES timeframe);

   int               CoordX1(void)                             const { return this.m_x;                     }

   int               CoordX2(void)                             const { return this.m_x+this.m_w;            }

   int               CoordY1(void)                             const { return this.m_y;                     }

   int               CoordY2(void)                             const { return this.m_y+this.m_h;            }

   int               CoordYAct(void)                           const { return this.m_y+this.m_y_act;        }

   color             RGBToColor(const double r,const double g,const double b);

   void              ColorToRGB(const color clr,double &r,double &g,double &b);

   double            GetR(const color clr)                           { return clr&0xff;                     }

   double            GetG(const color clr)                           { return(clr>>8)&0xff;                 }

   double            GetB(const color clr)                           { return(clr>>16)&0xff;                }

   int               ChartWidth(void)                          const { return this.m_chart_w;               }

   int               ChartHeight(void)                         const { return this.m_chart_h;               }

   bool              HigherWnd(void)                           const { return(this.m_h+2>this.m_chart_h);   }

   bool              WiderWnd(void)                            const { return(this.m_w+2>this.m_chart_w);   }

public:

   bool              CreateWindow(const string caption_text,const int x,const int y,const int w,const int h,const bool header,bool movable);

   void              Resize(const int w,const int h);

   void              SetColors(const color clr_bg,const color clr_bd,const color clr_hd,const color clr_capt,const color clr_text,uchar alpha_bg=128,uchar alpha_hd=200);

   CCanvas          *GetFieldCanvas(void) { return &this.m_field;          }

   void              DrawSeparateVLine(const int x,const int y1,const int y2,const color clr1,const color clr2,const uchar w=1);

   void              DrawSeparateHLine(const int x,const int y1,const int y2,const color clr1,const color clr2,const uchar w=1);

   color             NewColor(color base_color,int shift_red,int shift_green,int shift_blue);

   string            Caption(void)                             const { return this.m_caption;         }

   string            NameCaptionFont(void)                     const { return this.m_caption_font;    }

   color             ColorCaption(void)                        const { return this.m_color_caption;   }

   color             ColorBackground(void)                     const { return this.m_color_bg;        }

   color             ColorHeaderBackground(void)               const { return this.m_color_bg_header; }

   color             ColorTexts(void)                          const { return this.m_color_texts;     }

   void              OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

                     CWnd(void);

                    ~CWnd(void);

  };

//+------------------------------------------------------------------+

//| CWnd :>=AB@C:B>@                                                 |

//+------------------------------------------------------------------+

CWnd::CWnd(void) : m_chart_id(::ChartID()),

                   m_program_type((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)),

                   m_name(::MQLInfoString(MQL_PROGRAM_NAME)),

                   m_name_gv_x(m_name+"_GVX"),

                   m_name_gv_y(m_name+"_GVY"),

                   m_sub_wnd(m_program_type==PROGRAM_EXPERT || m_program_type==PROGRAM_SCRIPT ? 0 : ::ChartWindowFind()),

                   m_chart_w((int)::ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS,m_sub_wnd)),

                   m_chart_h((int)::ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,m_sub_wnd)),

                   m_caption("Panel"),

                   m_caption_font("Calibri"),

                   m_caption_font_size(-100),

                   m_alpha_bg(128),

                   m_alpha_head(200),

                   m_color_bg(C'200,200,200'),

                   m_color_bg_header(clrDarkGray),

                   m_color_border(clrDarkGray),

                   m_color_caption(clrYellow),

                   m_color_texts(clrSlateGray),

                   m_h(100),

                   m_w(160),

                   m_x(3),

                   m_y(::ChartGetInteger(m_chart_id,CHART_SHOW_ONE_CLICK) ? 79 : 20),

                   m_y_act(10),

                   m_is_visible(false),

                   m_movable(true),

                   m_header_on(true),

                   m_x_caption(4),

                   m_caption_alignment(TA_LEFT|TA_VCENTER),

                   m_mouse_state(MOUSE_STATE_NOT_PRESSED)

  {

   ::ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);

   if(!::GlobalVariableCheck(this.m_name_gv_x))

      ::GlobalVariableSet(this.m_name_gv_x,this.m_x);

   else

      this.m_x=(int)::GlobalVariableGet(this.m_name_gv_x);

   if(!::GlobalVariableCheck(this.m_name_gv_y))

      ::GlobalVariableSet(this.m_name_gv_y,this.m_y);

   else

      this.m_y=(int)::GlobalVariableGet(this.m_name_gv_y);

   this.m_higher_wnd=this.HigherWnd();

   this.m_wider_wnd=this.WiderWnd();

  }

//+------------------------------------------------------------------+

//| CWnd 45AB@C:B>@                                                  |

//+------------------------------------------------------------------+

CWnd::~CWnd(void)

  {

   ::ObjectsDeleteAll(this.m_chart_id,m_name);

   ::GlobalVariableSet(this.m_name_gv_x,this.m_x);

   ::GlobalVariableSet(this.m_name_gv_y,this.m_y);

  }

//+------------------------------------------------------------------+

//| CWnd Chart event function                                        |

//+------------------------------------------------------------------+

void CWnd::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)

  {

   if(id==CHARTEVENT_CHART_CHANGE)

     {

      this.m_sub_wnd=(this.m_program_type==PROGRAM_EXPERT || this.m_program_type==PROGRAM_SCRIPT ? 0 : ::ChartWindowFind());

      int w=(int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS,this.m_sub_wnd);

      int h=(int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.m_sub_wnd);

      this.m_higher_wnd=this.HigherWnd();

      this.m_wider_wnd=this.WiderWnd();

      if(this.m_chart_h!=h)

        {

         this.m_chart_h=h;

         int y=this.CoordY1();

         if(this.CoordY1()+this.m_h>h-1) y=h-this.m_h-1;

         if(y<1) y=1;

         this.Move(this.CoordX1(),y);

        }

      if(this.m_chart_w!=w)

        {

         this.m_chart_w=w;

         int x=this.CoordX1();

         if(this.CoordX1()+this.m_w>w-1) x=w-this.m_w-1;

         if(x<1) x=1;

         this.Move(x,this.CoordY1());

        }

     }

   if(!this.m_movable)

      return;

   static int diff_x=0;

   static int diff_y=0;

   bool pressed=(sparam=="1" || sparam=="" ? true : false);

   int  mouse_x=(int)lparam;

   int  mouse_y=(int)dparam-(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_sub_wnd);

   ENUM_MOUSE_STATE state=this.MouseButtonState(mouse_x,mouse_y,pressed);

   if(id==CHARTEVENT_MOUSE_MOVE)

     {

      if(state==MOUSE_STATE_PRESSED_INSIDE_WINDOW)

        {

         ::ChartSetInteger(0,CHART_MOUSE_SCROLL,false);

         ::ChartRedraw(this.m_chart_id);

         return;

        }

      else if(state==MOUSE_STATE_PRESSED_INSIDE_HEADER)

        {

         ::ChartSetInteger(0,CHART_MOUSE_SCROLL,false);

         this.Move(mouse_x-diff_x,mouse_y-diff_y);

         return;

        }

      else

        {

         ::ChartSetInteger(0,CHART_MOUSE_SCROLL,true);

         diff_x=mouse_x-this.CoordX1();

         diff_y=mouse_y-this.CoordY1();

        }

     }

  }

//+------------------------------------------------------------------+

//| >72@0I05B A>AB>O=85 :=>?:8 <KH8                                 |

//+------------------------------------------------------------------+

ENUM_MOUSE_STATE CWnd::MouseButtonState(const int x,const int y,bool pressed)

  {

//--- A;8 :=>?:0 =060B0

   if(pressed)

     {

      //--- A;8 C65 70D8:A8@>20=> A>AB>O=85 - 2KE>4

      if(this.m_mouse_state!=MOUSE_STATE_NOT_PRESSED)

         return this.m_mouse_state;

      //--- A;8 =060B0 :=>?:0 2=CB@8 >:=0

      if(x>this.CoordX1() && x<this.CoordX2() && y>this.CoordY1() && y<this.CoordY2())

        {

         //--- A;8 =060B0 :=>?:0 2=CB@8 703>;>2:0

         if(y>this.CoordY1() && y<this.CoordYAct())

           {

            this.RedrawHeaderArea(this.NewColor(this.m_color_bg_header,30,30,30),this.m_color_caption);

            this.m_mouse_state=MOUSE_STATE_PRESSED_INSIDE_HEADER;

            return this.m_mouse_state;

           }

         //--- A;8 =060B0 :=>?:0 2=CB@8 >:=0

         else if(y>this.CoordY1() && y<this.CoordY2())

           {

            this.m_mouse_state=(this.m_header_on ? MOUSE_STATE_PRESSED_INSIDE_WINDOW : MOUSE_STATE_PRESSED_INSIDE_HEADER);

            return this.m_mouse_state;

           }

        }

      //--- =>?:0 =060B0 2=5 ?@545;>2 >:=0

      else

        {

         this.m_mouse_state=MOUSE_STATE_PRESSED_OUTSIDE_WINDOW;

         return this.m_mouse_state;

        }

     }

//--- =>?:0 =5 =060B0

   else

     {

      this.m_mouse_state=MOUSE_STATE_NOT_PRESSED;

      //--- C@A>@ 2=CB@8 >:=0

      if(x>this.CoordX1() && x<this.CoordX2() && y>this.CoordY1() && y<this.CoordY2())

        {

         //--- C@A>@ 2=CB@8 703>;>2:0

         if(y>this.CoordY1() && y<this.CoordYAct())

           {

            this.RedrawHeaderArea(this.NewColor(this.m_color_bg_header,20,20,20),this.m_color_caption);

            return MOUSE_STATE_INSIDE_HEADER;

           }

         //--- C@A>@ 2=CB@8 >:=0

         else

           {

            this.RedrawHeaderArea(this.m_color_bg_header,this.m_color_caption);

            return MOUSE_STATE_INSIDE_WINDOW;

           }

        }

     }

   this.RedrawHeaderArea(this.m_color_bg_header,this.m_color_caption);

   return MOUSE_STATE_NOT_PRESSED;

  }

//+------------------------------------------------------------------+

//| CWnd ?5@5<5I5=85 >:=0                                            |

//+------------------------------------------------------------------+

void CWnd::Move(int x,int y)

  {

   if(!this.m_wider_wnd)

     {

      if(x+this.m_w>this.m_chart_w-1) x=this.m_chart_w-this.m_w-1;

      if(x<1) x=1;

     }

   else

     {

      if(x>1) x=1;

      if(x<this.m_chart_w-this.m_w-1) x=this.m_chart_w-this.m_w-1;

     }

   if(!this.m_higher_wnd)

     {

      if(y+this.m_h>this.m_chart_h-2) y=this.m_chart_h-this.m_h-2;

      if(y<1) y=1;

     }

   else

     {

      if(y>1) y=1;

      if(y<this.m_chart_h-this.m_h-2) y=this.m_chart_h-this.m_h-2;

     }



   this.m_x=x;

   this.m_y=y;

   ::ObjectSetInteger(this.m_chart_id,this.m_name+"0",OBJPROP_XDISTANCE,this.m_x);

   ::ObjectSetInteger(this.m_chart_id,this.m_name+"0",OBJPROP_YDISTANCE,this.m_y);

   ::ObjectSetInteger(this.m_chart_id,this.m_name+"1",OBJPROP_XDISTANCE,this.m_x+1);

   ::ObjectSetInteger(this.m_chart_id,this.m_name+"1",OBJPROP_YDISTANCE,this.m_y+this.m_y_act+1);

   this.m_canvas.Update(true);

  }

//+------------------------------------------------------------------+

//| CWnd !>740QB E>;AB                                               |

//+------------------------------------------------------------------+

bool CWnd::CreateCanvas(CCanvas &canvas,const int wnd_id,const int x,const int y,const int w,const int h)

  {

   if(!canvas.CreateBitmapLabel(this.m_chart_id,this.m_sub_wnd,this.m_name+(string)wnd_id,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE))

      return false;

   if(wnd_id==0)

     {

      this.m_x=x;

      this.m_y=y;

      this.m_w=w;

      this.m_h=h;

     }

   ::ObjectSetInteger(this.m_chart_id,this.m_name+(string)wnd_id,OBJPROP_SELECTABLE,false);

   ::ObjectSetInteger(this.m_chart_id,this.m_name+(string)wnd_id,OBJPROP_SELECTED,false);

   ::ObjectSetInteger(this.m_chart_id,this.m_name+(string)wnd_id,OBJPROP_HIDDEN,true);

   return true;

  }

//+------------------------------------------------------------------+

//| CWnd !>740QB >:=>                                                |

//+------------------------------------------------------------------+

bool CWnd::CreateWindow(const string caption_text,const int x,const int y,const int w,const int h,const bool header,bool movable)

  {

   this.m_header_on=header;

   if(!header)

      this.m_y_act=0;

   if(!this.CreateCanvas(this.m_canvas,0,x,y,w,h))

      return false;

   this.m_movable=movable;

   this.m_caption=caption_text;

   this.m_canvas.Erase(::ColorToARGB(this.m_color_bg,this.m_alpha_bg));

   this.m_canvas.Rectangle(0,0,this.m_w-1,this.m_h-1,::ColorToARGB(this.m_color_border));

   this.DrawHeaderArea(this.m_caption);

   this.m_canvas.Update(true);



   if(!this.CreateCanvas(this.m_field,1,this.m_x+1,this.m_y+this.m_y_act+1,this.m_w-2,this.m_h-this.m_y_act-2))

      return false;

   return true;

  }

//+------------------------------------------------------------------+

//| 7<5=O5B @07<5@K >:=0                                            |

//+------------------------------------------------------------------+

void CWnd::Resize(const int w,const int h)

  {

   this.m_w=w;

   this.m_h=h;

   this.m_canvas.Resize(this.m_w,this.m_h);

   this.m_field.Resize(this.m_w-2,this.m_h-this.m_y_act-2);

   this.m_canvas.Erase(::ColorToARGB(this.m_color_bg,this.m_alpha_bg));

   this.m_canvas.Rectangle(0,0,this.m_w-1,this.m_h-1,::ColorToARGB(this.m_color_border));

   this.DrawHeaderArea(this.m_caption);

   this.m_canvas.Update(false);

   this.m_field.Update(true);

  }

//+------------------------------------------------------------------+

//| CWnd  8AC5B 703>;>2>:                                            |

//+------------------------------------------------------------------+

void CWnd::DrawHeaderArea(const string caption)

  {

   if(!this.m_header_on) return;

   this.m_canvas.FillRectangle(0,0,this.m_w,this.m_y_act,::ColorToARGB(this.m_color_bg_header,this.m_alpha_head));

   this.m_canvas.FontSet(this.m_caption_font,this.m_caption_font_size,FW_NORMAL);

   this.m_canvas.TextOut(this.m_x_caption,this.m_y_act/2,caption,::ColorToARGB(this.m_color_caption),this.m_caption_alignment);

  }

//+------------------------------------------------------------------+

//| CWnd 5@5@8A>2K205B 703>;>2>:                                    |

//+------------------------------------------------------------------+

void CWnd::RedrawHeaderArea(const color clr_area,const color clr_caption)

  {

   if(!this.m_header_on) return;

   this.m_canvas.FillRectangle(0,0,this.m_w,this.m_y_act,::ColorToARGB(clr_area,this.m_alpha_head));

   this.m_canvas.FontSet(this.m_caption_font,this.m_caption_font_size,FW_NORMAL);

   this.m_canvas.TextOut(this.m_x_caption,this.m_y_act/2,this.m_caption,::ColorToARGB(clr_caption),this.m_caption_alignment);

   this.m_canvas.Update();

  }

//+------------------------------------------------------------------+

//|  8AC5B 25@B8:0;L=CN @0745;8B5;L=CN ;8=8N                         |

//+------------------------------------------------------------------+

void CWnd::DrawSeparateVLine(const int x,const int y1,const int y2,const color clr1,const color clr2,const uchar w=1)

  {

   this.m_field.LineVertical(x,y1,y2,::ColorToARGB(clr1,this.m_alpha_bg));

   this.m_field.LineVertical(x+w,y1,y2,::ColorToARGB(clr2,this.m_alpha_bg));

  }

//+------------------------------------------------------------------+

//|  8AC5B 3>@87>=B0;L=CN @0745;8B5;L=CN ;8=8N                       |

//+------------------------------------------------------------------+

void CWnd::DrawSeparateHLine(const int x1,const int x2,const int y,const color clr1,const color clr2,const uchar w=1)

  {

   this.m_field.LineHorizontal(x1,x2,y,::ColorToARGB(clr1,this.m_alpha_bg));

   this.m_field.LineHorizontal(x1,x2,y+w,::ColorToARGB(clr2,this.m_alpha_bg));

  }

//+------------------------------------------------------------------+

//| >72@0I05B F25B A =>2>9 F25B>2>9 A>AB02;ONI59                    |

//+------------------------------------------------------------------+

color CWnd::NewColor(color base_color,int shift_red,int shift_green,int shift_blue)

  {

   double clR=0,clG=0,clB=0;

   this.ColorToRGB(base_color,clR,clG,clB);

   double clRn=(clR+shift_red  < 0 ? 0 : clR+shift_red  > 255 ? 255 : clR+shift_red);

   double clGn=(clG+shift_green< 0 ? 0 : clG+shift_green> 255 ? 255 : clG+shift_green);

   double clBn=(clB+shift_blue < 0 ? 0 : clB+shift_blue > 255 ? 255 : clB+shift_blue);

   return this.RGBToColor(clRn,clGn,clBn);

  }

//+------------------------------------------------------------------+

//| @5>1@07>20=85 RGB 2 const color                                 |

//+------------------------------------------------------------------+

color CWnd::RGBToColor(const double r,const double g,const double b)

  {

   int int_r=(int)::round(r);

   int int_g=(int)::round(g);

   int int_b=(int)::round(b);

   int clr=0;

//---

   clr=int_b;

   clr<<=8;

   clr|=int_g;

   clr<<=8;

   clr|=int_r;

//---

   return (color)clr;

  }

//+------------------------------------------------------------------+

//| >;CG5=85 7=0G5=89 :><?>=5=B>2 RGB                               |

//+------------------------------------------------------------------+

void CWnd::ColorToRGB(const color clr,double &r,double &g,double &b)

  {

   r=GetR(clr);

   g=GetG(clr);

   b=GetB(clr);

  }

//+------------------------------------------------------------------+

//| >72@0I05B =08<5=>20=85 B09<D@59<0                               |

//+------------------------------------------------------------------+

string CWnd::TimeframeToString(const ENUM_TIMEFRAMES timeframe)

  {

   return ::StringSubstr(::EnumToString(timeframe==PERIOD_CURRENT ? Period() : timeframe),7);

  }

//+------------------------------------------------------------------+

//| #AB0=02;8205B F25B0 ?0=5;8                                       |

//+------------------------------------------------------------------+

void CWnd::SetColors(const color clr_bg,const color clr_bd,const color clr_hd,const color clr_capt,const color clr_text,uchar alpha_bg=128,uchar alpha_hd=200)

  {

   this.m_color_bg=clr_bg;

   this.m_color_border=clr_bd;

   this.m_color_bg_header=clr_hd;

   this.m_color_caption=clr_capt;

   this.m_color_texts=clr_text;

   this.m_alpha_bg=alpha_bg;

   this.m_alpha_head=alpha_hd;

  }

//+------------------------------------------------------------------+



//+------------------------------------------------------------------+

//| ;0AA B09<D@59<                                                  |

//+------------------------------------------------------------------+

class CTimeframe : public CObject

  {

private:

   ENUM_TIMEFRAMES   m_timeframe;

   string            m_symbol;

   datetime          m_last_alert_time;

   int               m_status;

   int               m_index_x;

public:

   ENUM_TIMEFRAMES   Timeframe(void)                                 const { return this.m_timeframe;       }

   string            Symbol(void)                                    const { return this.m_symbol;          }

   int               Status(void)                                    const { return this.m_status;          }

   int               IndexX(void)                                    const { return this.m_index_x;         }

   void              SetAlertTime(const datetime time)                     { this.m_last_alert_time=time;   }

   void              SetIndexX(const int index)                            { this.m_index_x=index;          }

   void              SetStatus(const int status)                           { this.m_status=status;          }

   datetime          LastAlertTime(void)                             const { return this.m_last_alert_time; }

   string            TimeframeDescription(void) const { return ::StringSubstr(::EnumToString(this.m_timeframe==PERIOD_CURRENT ? ::Period() : this.m_timeframe),7);   }

                     CTimeframe(const string symbol,const ENUM_TIMEFRAMES timeframe);

                    ~CTimeframe(void){;}

  };

//+------------------------------------------------------------------+

//| CTimeframe :>=AB@C:B>@                                           |

//+------------------------------------------------------------------+

CTimeframe::CTimeframe(const string symbol,const ENUM_TIMEFRAMES timeframe) : m_status(0),m_last_alert_time(0)

  {

   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);

   this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);

  }

//+------------------------------------------------------------------+

  

//+------------------------------------------------------------------+

//| ;0AA A8<2>;                                                     |

//+------------------------------------------------------------------+

class CSymbol : public CObject

  {

private:

   CArrayObj         m_list_timeframe;

   MqlTick           m_tick[2];

   string            m_symbol;

   double            m_tick_value;

   double            m_tick_value_loss;

   int               m_digits;

   int               m_index_x;

   int               m_index_y;

   datetime          m_last_alert_time;

   double            m_point;

   bool              m_actual;

   bool              CheckTimeframe(const ENUM_TIMEFRAMES timeframe);

public:

   CTimeframe*       GetPointerTF(const ENUM_TIMEFRAMES timeframe);

   CArrayObj*        GetListTimeframes(void)                               { return &this.m_list_timeframe; }

   void              SetActualData(const bool flag)                        { this.m_actual=flag;            }

   void              SetIndexX(const int index)                            { this.m_index_x=index;          }

   void              SetIndexY(const int index)                            { this.m_index_y=index;          }

   void              SetAlertTime(const datetime time)                     { this.m_last_alert_time=time;   }

   int               IndexX(void)                                    const { return this.m_index_x;         }

   int               IndexY(void)                                    const { return this.m_index_y;         }

   string            Symbol(void)                                    const { return this.m_symbol;          }

   datetime          LastAlertTime(void)                             const { return this.m_last_alert_time; }

   bool              CheckSyncTFsByValue(const int value);

   int               CheckSyncAllTFs(int &value);

   int               CheckSigOneTF(const ENUM_TIMEFRAMES timeframe);

   bool              AddTimeframe(const ENUM_TIMEFRAMES timeframe);

   void              SetStatusTF(const ENUM_TIMEFRAMES timeframe,const int status);

   int               Spread(const int shift,const ENUM_TIMEFRAMES timeframe) const;

   double            Ask(void)                                    const { return this.m_tick[1].ask;                                   }

   double            Bid(void)                                    const { return this.m_tick[1].bid;                                   }

   double            Spread(void)                                 const { return (this.m_tick[1].ask-this.m_tick[1].bid)/this.m_point; }

   double            SpreadPrev(void)                             const { return (this.m_tick[0].ask-this.m_tick[0].bid)/this.m_point; }

   datetime          Time(void)                                   const { return this.m_tick[1].time;                                  }

   long              TimeMsc(void)                                const { return this.m_tick[1].time_msc;                              }

   double            AskPrev(void)                                const { return this.m_tick[0].ask;                                   }

   double            BidPrev(void)                                const { return this.m_tick[0].bid;                                   }

   datetime          TimePrev(void)                               const { return this.m_tick[0].time;                                  }

   long              TimeMscPrev(void)                            const { return this.m_tick[0].time_msc;                              }

   int               Digits(void)                                 const { return this.m_digits;                                        }

   double            Point(void)                                  const { return this.m_point;                                         }

   double            TickValue(void)                              const { return this.m_tick_value;                                    }

   double            TickValueLoss(void)                          const { return this.m_tick_value_loss;                               }

   bool              Refresh(void);

                     CSymbol(const string symbol);

                    ~CSymbol(void){;}

  };

//+------------------------------------------------------------------+

//| CSymbol :>=AB@C:B>@                                              |

//+------------------------------------------------------------------+

CSymbol::CSymbol(const string symbol) : m_last_alert_time(0),m_actual(false),m_tick_value(0),m_tick_value_loss(0)

  {

   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);

   this.m_list_timeframe.Clear();

   this.m_point=::SymbolInfoDouble(this.m_symbol,SYMBOL_POINT);

   this.m_digits=(int)::SymbolInfoInteger(this.m_symbol,SYMBOL_DIGITS);

   ::ZeroMemory(this.m_tick);

  }

//+------------------------------------------------------------------+

//| 1=>2;5=85 0:BC0;L=KE 40==KE                                     |

//+------------------------------------------------------------------+

bool CSymbol::Refresh(void)

  {

   if(!this.m_actual)

      return false;

   bool res=false;

   this.m_tick_value=::SymbolInfoDouble(this.m_symbol,SYMBOL_TRADE_TICK_VALUE);

   this.m_tick_value_loss=::SymbolInfoDouble(this.m_symbol,SYMBOL_TRADE_TICK_VALUE_LOSS);

   if(::CopyTicks(this.m_symbol,this.m_tick,COPY_TICKS_ALL,0,2)==2)

     {

      uint flag=this.m_tick[1].flags;

      if(flag==TICK_FLAG_ASK || flag==TICK_FLAG_BID)

         res=true;

     }

   return res;

  }

//+------------------------------------------------------------------+

//| >72@0I05B A?@54 10@0                                            |

//+------------------------------------------------------------------+

int CSymbol::Spread(const int shift,const ENUM_TIMEFRAMES timeframe) const

  {

   int array[];

   return(::CopySpread(this.m_symbol,timeframe,shift,1,array)==1 ? array[0] : INT_MIN);

  }

//+------------------------------------------------------------------+

//| >72@0I05B D0:B A8=E@>=870F88 2A5E B09<D@59<>2 ?> 7=0G5=8N       |

//+------------------------------------------------------------------+

bool CSymbol::CheckSyncTFsByValue(const int value)

  {

   int total=this.m_list_timeframe.Total();

   if(total<2)

      return false;

   this.m_list_timeframe.Sort();

   CTimeframe* first=this.m_list_timeframe.At(0);

   if(first==NULL || first.Status()!=value)

      return false;

   int tfs=1;

   for(int i=1;i<total;i++)

     {

      CTimeframe* obj=this.m_list_timeframe.At(i);

      if(obj==NULL || obj.Status()!=first.Status())

         return false;

      tfs++;

     }

   return(tfs==total ? true : false);

  }

//+------------------------------------------------------------------+

//| >72@0I05B 7=0G5=85 A8=E@>=870F88 2A5E B09<D@59<>2               |

//+------------------------------------------------------------------+

int CSymbol::CheckSyncAllTFs(int &value)

  {

   int total=this.m_list_timeframe.Total();

   if(total<2)

      return 0;

   this.m_list_timeframe.Sort();

   CTimeframe* first=this.m_list_timeframe.At(0);

   if(first==NULL || first.Status()==0)

      return 0;

   int tfs=1;

   for(int i=1;i<total;i++)

     {

      CTimeframe* obj=this.m_list_timeframe.At(i);

      if(obj==NULL || obj.Status()!=first.Status())

         return 0;

      tfs++;

     }

   if(tfs==total)

     {

      value=first.Status();

      return tfs;

     }

   return 0;

  }

//+------------------------------------------------------------------+

//| >72@0I05B 7=0G5=85 A83=0;0 =0 B09<D@59<5                        |

//+------------------------------------------------------------------+

int CSymbol::CheckSigOneTF(const ENUM_TIMEFRAMES timeframe)

  {

   if(this.m_list_timeframe.Total()<1)

      return 0;

   CTimeframe* obj=this.GetPointerTF(timeframe);

   return(obj!=NULL ? obj.Status() : 0);

  }

//+------------------------------------------------------------------+

//| #AB0=02;8205B AB0BCA B09<D@59<0                                  |

//+------------------------------------------------------------------+

void CSymbol::SetStatusTF(const ENUM_TIMEFRAMES timeframe,const int status)

  {

   CTimeframe* tf=this.GetPointerTF(timeframe);

   if(tf==NULL)

      return;

   tf.SetStatus(status);

  }

//+------------------------------------------------------------------+

//| >72@0I05B C:070B5;L =0 >1J5:B-B09<D@59<                         |

//+------------------------------------------------------------------+

CTimeframe* CSymbol::GetPointerTF(const ENUM_TIMEFRAMES timeframe)

  {

   int total=this.m_list_timeframe.Total();

   for(int i=0;i<total;i++)

     {

      CTimeframe* obj=this.m_list_timeframe.At(i);

      if(obj==NULL)

         continue;

      if(obj.Timeframe()==timeframe)

         return obj;

     }

   return NULL;

  }

//+------------------------------------------------------------------+

//| CSymbol 2>72@0I05B =0;8G85 B09<D@59<0 2 A?8A:5                   |

//+------------------------------------------------------------------+

bool CSymbol::CheckTimeframe(const ENUM_TIMEFRAMES timeframe)

  {

   int total=this.m_list_timeframe.Total();

   for(int i=0;i<total;i++)

     {

      CTimeframe* obj=this.m_list_timeframe.At(i);

      if(obj==NULL)

         continue;

      if(obj.Timeframe()==timeframe)

         return true;

     }

   return false;

  }

//+------------------------------------------------------------------+

//| CSymbol 4>102;O5B B09<D@59<                                      |

//+------------------------------------------------------------------+

bool CSymbol::AddTimeframe(const ENUM_TIMEFRAMES timeframe)

  {

   if(!this.CheckTimeframe(timeframe))

     {

      CTimeframe* tf=new CTimeframe(this.m_symbol,timeframe);

      if(tf==NULL)

         return false;

      if(this.m_list_timeframe.Add(tf))

         return true;

     }

   return false;

  }

//+------------------------------------------------------------------+



//+------------------------------------------------------------------+

//| =48:0B>@                                                        |

//+------------------------------------------------------------------+

#property description "Multi Currency Pair Spread List Dashboard"

#property version   "1.00"

#include <Arrays\ArrayObj.mqh>

#include <Arrays\ArrayString.mqh>

#include <Arrays\ArrayInt.mqh>

#property indicator_chart_window

#property indicator_buffers 0

#property indicator_plots   0

//--- defines

#define   IND_ID_MACD      IND_CUSTOM+1

#define   SIG_STATUS_NL    0

#define   SIG_STATUS_UP    1

#define   SIG_STATUS_DN   -1

#define   SIG_STATUS_FL    2

//--- enums

enum ENUM_INPUT_YES_NO

  {

   INPUT_YES   =  1,       // Yes

   INPUT_NO    =  0        // No

  };

//--- 

enum ENUM_COST_MODE

  {

   COST_MODE_TICK,      // Tick

   COST_MODE_SPREAD     // Spread

  };

//--- input parameters

input ENUM_COST_MODE    InpShowCost       =  COST_MODE_TICK;   // Show cost

input string            InpSymbols="EURUSD,EURJPY,USDJPY,GBPUSD,GBPJPY,EURGBP,AUDUSD,NZDUSD";  // Symbols list (Comma Separated Pairs, empty - current symbol)

input uint              InpCoordX         =  1;                // Panel: X-coordinate

input uint              InpCoordY         =  1;                // Panel: Y-coordinate

input color             InpColorPanel     =  C'240,240,240';   // Panel: Background color

input color             InpColorBorder    =  C'200,200,200';   // Panel: Border color

input color             InpColorLabels    =  clrSlateGray;     // Panel: Texts color

input color             InpColorUP        =  clrRed;           // Panel: Color of increase the spread value

input color             InpColorDN        =  clrBlue;          // Panel: Color  of decrease the spread value

input color             InpColorNL        =  clrGray;          // Panel: Color of unchanged spread value

input uchar             InpAlphaBackgrnd  =  128;              // Panel: Background opacity

//--- global variables

CArrayString   list_symbols;

CArrayObj      list_work;

CWnd           panel;

//---

string         custom_ind_name;

string         array_symbols[];

string         gv_name;

//+------------------------------------------------------------------+

//| Custom indicator initialization function                         |

//+------------------------------------------------------------------+

int OnInit()

  {

//--- timer

   EventSetMillisecondTimer(16);

//--- setting indicator parameters

   gv_name="Spread_List";

   custom_ind_name="";

//--- Preparing of arrays

   if(!ArraysPreparing())

     {

      Print("Error. Failed to prepare working arrays.");

      return INIT_FAILED;

     }

//---

   int total_sym=list_symbols.Total();

   for(int s=0;s<total_sym;s++)

     {

      for(int t=0;t<2;t++)

        {

         string sy=list_symbols.At(s);

         CSymbol* symbol=new CSymbol(sy);

         if(symbol==NULL)

            continue;

         //--- Set coordinates

         symbol.SetIndexX(t);

         symbol.SetIndexY(s);

         symbol.SetActualData(true);

         //--- Add collection to the indicators list

         list_work.Add(symbol);

        }

     }

   

//--- 0=5;L

   int w=180,h=74;

   int x=int(!GlobalVariableCheck(gv_name+"_GVX") ? int(ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)-w-InpCoordX) : GlobalVariableGet(gv_name+"_GVX"));

   int y=int(!GlobalVariableCheck(gv_name+"_GVY") ? (int)InpCoordY : GlobalVariableGet(gv_name+"_GVY"));

   panel.SetColors(InpColorPanel,InpColorBorder,clrNONE,clrNONE,InpColorLabels,InpAlphaBackgrnd,255);

   string name=gv_name;

   StringReplace(name,"_"," ");

   if(!panel.CreateWindow(name,x,y,w,h,false,true))

     {

      Print("Failed to create panel. Please restart the indicator");

      return INIT_FAILED;

     }

   RedrawField();

//---

   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[])

  {

//---



//--- return value of prev_calculated for next call

   return(rates_total);

  }

//+------------------------------------------------------------------+

//| Custom indicator timer function                                  |

//+------------------------------------------------------------------+

void OnTimer()

  {

   bool refresh=false;

   int total=list_work.Total();

   for(int i=0;i<total;i++)

     {

      CSymbol* symbol=list_work.At(i);

      if(symbol==NULL)

         continue;

      if(symbol.Refresh())

         refresh=true;

     }

   if(refresh)

      RedrawField();

  }

//+------------------------------------------------------------------+

//| Cart event function                                              |

//+------------------------------------------------------------------+

void OnChartEvent(const int id,

                  const long &lparam,

                  const double &dparam,

                  const string &sparam)

  {

   panel.OnChartEvent(id,lparam,dparam,sparam);

  }

//+------------------------------------------------------------------+

//| 1=>2;O5B 40==K5 ?0=5;8                                          |

//+------------------------------------------------------------------+

void RedrawField(void)

  {

   int row=list_symbols.Total();

   int col=2;

   CCanvas *canvas=panel.GetFieldCanvas();

   if(canvas==NULL)

     {

      Print(__FUNCTION__,": Error: Canvas not available.");

      return;

     }

   int shiftV=14,shiftH=48,startH=54,startV=15;

   panel.Resize(startH+col*shiftH,shiftV+row*shiftV+3);

   canvas.Erase(ColorToARGB(panel.ColorBackground(),0));

   panel.DrawSeparateHLine(1,canvas.Width()-2,13,panel.NewColor(panel.ColorBackground(),-5,-5,-5),panel.NewColor(panel.ColorBackground(),45,45,45));

   panel.DrawSeparateVLine(50,14,canvas.Height()-2,panel.NewColor(panel.ColorBackground(),-5,-5,-5),panel.NewColor(panel.ColorBackground(),45,45,45));



//---

   int total=list_work.Total();

   for(int i=0;i<total;i++)

     {

      CSymbol* symbol=list_work.At(i);

      if(symbol==NULL)

         continue;

      symbol.Refresh();

      int x=symbol.IndexX();

      int y=symbol.IndexY();

      if(y==0)

        {

         string header=(symbol.IndexX()==0 ? "Spread" : InpShowCost==COST_MODE_TICK ? "Tick cost" : "Cost");

         canvas.FontSet(panel.NameCaptionFont(),-80,FW_BLACK);

         canvas.TextOut(startH+(shiftH/2)-4+x*shiftH,0,header,ColorToARGB(panel.ColorTexts()),TA_CENTER);

         if(x==0)

            canvas.TextOut(22,0,"Pairs",ColorToARGB(panel.ColorTexts()),TA_CENTER);

        }

      int gx=startH+(shiftH/2)-4+x*shiftH;

      int gy=startV+6+y*shiftV;

      panel.DrawSeparateVLine(gx+shiftH-shiftH/2,14,canvas.Height()-2,panel.NewColor(panel.ColorBackground(),-5,-5,-5),panel.NewColor(panel.ColorBackground(),45,45,45));



   //--- Spread

      if(x==0)

        {

         canvas.FontSet(panel.NameCaptionFont(),-80,FW_BLACK);

         canvas.TextOut(4,startV+y*shiftV,symbol.Symbol(),ColorToARGB(panel.ColorTexts()));

         

         double sp0=symbol.Spread();

         double sp1=symbol.SpreadPrev();

         color clr_sp=(sp0>sp1 ? InpColorUP : sp0<sp1 ? InpColorDN : InpColorNL);

         string text=DoubleToString(sp0,0);

         canvas.FontSet(panel.NameCaptionFont(),-80,FW_NORMAL);

         canvas.TextOut(startH+(shiftH/2)-4+x*shiftH,startV+y*shiftV,text,ColorToARGB(clr_sp),TA_CENTER|TA_CENTER);

        }

   //--- Cost

      if(x==1)

        {

         string text=DoubleToString(symbol.TickValue()*(InpShowCost==COST_MODE_SPREAD ? symbol.Spread() : 1),2);

         canvas.FontSet(panel.NameCaptionFont(),-80,FW_NORMAL);

         canvas.TextOut(startH+(shiftH/2)-4+x*shiftH,startV+y*shiftV,text,ColorToARGB(InpColorNL),TA_CENTER|TA_CENTER);

        }

     }

   canvas.Update(true);

  }

//+------------------------------------------------------------------+

//|  8AC5B B@5C3>;L=8: 225@E                                         |

//+------------------------------------------------------------------+

void TriangleUp(CCanvas *canvas,const int x,const int y,const color clr_bd,const color clr_bg,const uchar alpha=255)

  {

   if(canvas==NULL)

      return;

   int x1=x-4;

   int y1=y+2;

   int x2=x;

   int y2=y-2;

   int x3=x+4;

   int y3=y1;

   canvas.FillTriangle(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bg,alpha));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd,alpha),STYLE_SOLID);

  }

//+------------------------------------------------------------------+

//|  8AC5B B@5C3>;L=8: 2=87                                          |

//+------------------------------------------------------------------+

void TriangleDown(CCanvas *canvas,const int x,const int y,const color clr_bd,const color clr_bg,const uchar alpha=255)

  {

   if(canvas==NULL)

      return;

   int x1=x-4;

   int y1=y-2;

   int x2=x;

   int y2=y+2;

   int x3=x+4;

   int y3=y1;

   canvas.FillTriangle(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bg,alpha));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd,alpha),STYLE_SOLID);

  }

//+------------------------------------------------------------------+

//|  8AC5B B@5C3>;L=8: 2?@02>                                        |

//+------------------------------------------------------------------+

void TriangleRight(CCanvas* canvas,const int x,const int y,const color clr_bd,const color clr_bg,const uchar alpha=255)

  {

   if(canvas==NULL)

      return;

   int x1=x-2;

   int y1=y-3;

   int x2=x+3;

   int y2=y;

   int x3=x-2;

   int y3=y+3;

   canvas.FillTriangle(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bg,alpha));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd,alpha),STYLE_SOLID);

  }

//+------------------------------------------------------------------+

//|  8AC5B :@C3                                                      |

//+------------------------------------------------------------------+

void Circle(CCanvas *canvas,const int x,const int y,const double r,const color clr_bd,const color clr_bg,const uchar alpha=255)

  {

   if(canvas==NULL)

      return;

   canvas.FillCircle(x,y,(int)r,ColorToARGB(clr_bg,alpha));

   canvas.CircleWu(x,y,r,ColorToARGB(clr_bd,alpha),STYLE_SOLID);

  }

//+------------------------------------------------------------------+

//|  8AC5B ?@O<>C3>;L=8:                                             |

//+------------------------------------------------------------------+

void Rectangle(CCanvas* canvas,const int x,const int y,const int h,const int w,const color clr_bd,const color clr_bg,const uchar alpha=255)

  {

   if(canvas==NULL)

      return;

   int h2=(int)ceil(h/2);

   int w2=(int)ceil(w/2);

   int x1=x-w2;

   int y1=y-h2;

   int x2=x+w2;

   int y2=y+h2;

   canvas.FillRectangle(x1,y1,x2,y2,ColorToARGB(clr_bg,alpha));

   canvas.Rectangle(x1,y1,x2,y2,ColorToARGB(clr_bd,alpha));

  }

//+------------------------------------------------------------------+

//| @>25@:0 A8<2>;0                                                 |

//+------------------------------------------------------------------+

bool SymbolCheck(const string symbol_name)

  {

   long select=0;

   ResetLastError();

   if(!SymbolInfoInteger(symbol_name,SYMBOL_SELECT,select))

     {

      int err=GetLastError();

      Print("Error: ",err," Symbol ",symbol_name," does not exist");

      return false;

     }

   else

     {

      if(select) return true;

      ResetLastError();

      if(!SymbolSelect(symbol_name,true))

        {

         int err=GetLastError();

         Print("Error selected ",symbol_name,": ",err);

        }

     }

   return false;

  }

//+------------------------------------------------------------------+

//| >72@0I05B D0:B =0;8G8O A8<2>;0 2 A?8A:5                         |

//+------------------------------------------------------------------+

bool IsPresentSymbol(const string symbol)

  {

   list_symbols.Sort();

   return(list_symbols.Search(symbol)>WRONG_VALUE);

  }

//+------------------------------------------------------------------+

//| >72@0I05B 8=45:A A8<2>;0 2 A?8A:5                               |

//+------------------------------------------------------------------+

int IndexSymbol(const string symbol_name)

  {

   int total=list_symbols.Total();

   for(int i=0;i<total;i++)

      if(list_symbols.At(i)==symbol_name)

         return i;

   return WRONG_VALUE;

  }

//+------------------------------------------------------------------+

//| >43>B>2:0 <0AA82>2 2E>4=KE ?0@0<5B@>2                           |

//+------------------------------------------------------------------+

bool ArraysPreparing(void)

  {

   if(InpSymbols=="" || InpSymbols==NULL)

     {

      ArrayResize(array_symbols,1);

      array_symbols[0]=Symbol();

     }

   else

     {

      string value=","+InpSymbols;

      int total=StringSplit(InpSymbols,StringGetCharacter(value,0),array_symbols);

      ResetLastError();

      if(total<=0)

        {

         string end=(total==0 ? "Symbols string is empty." : "Error: "+(string)GetLastError());

         Print("Failed to get the array of symbols. ",end);

         return false;

        }

      for(int i=0;i<total;i++)

         SymbolCheck(array_symbols[i]);

     }

   int total=ArraySize(array_symbols);

   list_symbols.Clear();

   for(int i=0;i<total;i++)

     {

      if(!IsPresentSymbol(array_symbols[i]))

         if(SymbolCheck(array_symbols[i]))

            list_symbols.Add(array_symbols[i]);

     }

   if(list_symbols.Total()==0)

     {

      Print("There is no valid symbol in the list. The ",Symbol()," will be used.");

      list_symbols.Add(Symbol());

     }

//---

   return true;

  }

//+------------------------------------------------------------------+

//| >72@0I05B AB@>:C 2@5<5=8 A <8;8A5:C=40<8                        |

//+------------------------------------------------------------------+

string TimeMSCtoString(const long time_msc)

  {

   return TimeToString(time_msc/1000,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"."+IntegerToString(time_msc%1000,3,'0');

  }

//+------------------------------------------------------------------+

Comments