MTF_MCP_Percentage_price_follower

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

//|                            MTF_MCP_Percentage_price_follower.mq5 |

//|                        Copyright 2018, MetaQuotes Software Corp. |

//|                                                 https://mql5.com |

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

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

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

//--- includes

#include <Canvas\Canvas.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(""),

                   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)

  {

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

      return false;

   this.m_header_on=header;

   if(!header)

      this.m_y_act=0;

   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 AGQBG8: B09<5@0                                            |

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

class CTimerCounter

  {

private:  

   ulong             m_timer_counter;

   ulong             m_timer_step;

   ulong             m_timer_pause;

public:

   void              SetParams(const ulong step,const ulong pause)   { this.m_timer_step=step; this.m_timer_pause=pause;   }

   bool              IsTimeDone(void);

                     CTimerCounter(void) : m_timer_counter(0),m_timer_step(16),m_timer_pause(250){;}

                    ~CTimerCounter(void){;}

  };

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

//| CTimerCounter ?@>25@O5B >:>=G0=85 ?0C7K                          |

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

bool CTimerCounter::IsTimeDone(void)

  {

   if(this.m_timer_counter>ULONG_MAX)

      this.m_timer_counter=0;

   if(this.m_timer_counter<this.m_timer_pause)

     {

      this.m_timer_counter+=this.m_timer_step;

      return false;

     }

   this.m_timer_counter=0;

   return true;

  }

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



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

//| ;0AA =48:0B>@0                                                 |

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

#include <Indicators\Indicator.mqh>

class CIndicatorsBase : public CIndicator

  {

protected:

   CTimerCounter     m_counter_time;

   CTimerCounter     m_counter_refresh;

   MqlParam          m_params[];

   string            m_name_indicator;

   bool              m_counter_refresh_done;

   bool              m_counter_time_done;

   int               m_type;

   int               m_num_params;

   int               m_prev_calculated;

   bool              m_handle_success;

   int               m_refresh_flags;

   datetime          Time(const int shift) const { datetime array[]; return(::CopyTime(this.Symbol(),this.Period(),1,1,array)==1 ? array[0]: 0);   }

   string            SetName(const ENUM_INDICATOR type)  const { return ::StringSubstr(::EnumToString(type),4);            }

   virtual bool      Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[]);

public:

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

   string            Name(void)                 const { return this.m_name_indicator;        }

   int               PrevCalculated(void)       const { return this.m_prev_calculated;       }

   bool              IsCounterRefreshDone(void)       { return this.m_counter_refresh_done;  }

   bool              IsCounterTimeDone(void)          { return this.m_counter_time_done;     }

   void              SetType(const int type)          { this.m_type=type;                    }

   void              SetCounterTime(const uint step,const uint pause);

   void              SetCounterRefresh(const uint step,const uint pause);

   void              SetRefreshFlags(const bool refresh_current,const int refresh_periods=OBJ_ALL_PERIODS);

   bool              CheckLoadHistory(void)                 { return CSeries::CheckLoadHistory(this.BufferSize());   }

   bool              Create(const string indicator_name,const int buffers_num);

   bool              Create(const ENUM_INDICATOR indicator_type,const int buffers_num);

   void              Refresh(void);

   template<typename T>

   void              SetParameter(const T value);

   void              OnTimer(void);

   virtual int       Type(void)                       const { return this.m_type;                  }

                     CIndicatorsBase(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const int type);

                    ~CIndicatorsBase(void);

  };

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

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

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

CIndicatorsBase::CIndicatorsBase(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const int type) : m_refresh_flags(OBJ_ALL_PERIODS),

                                                                                                            m_prev_calculated(WRONG_VALUE),

                                                                                                            m_handle_success(false),

                                                                                                            m_num_params(0),

                                                                                                            m_counter_refresh_done(false),

                                                                                                            m_counter_time_done(false),

                                                                                                            m_type(type)

  {

   this.SetSymbolPeriod(symbol_name,timeframe);

   this.m_refresh_current=false;

   this.SetCounterRefresh(16,250);

   this.SetCounterTime(16,90000);

  }

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

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

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

CIndicatorsBase::~CIndicatorsBase(void)

  {

   this.m_handle_success=false;

   this.m_handle=INVALID_HANDLE;

   this.m_buffers_total=0;

   this.m_prev_calculated=0;

   this.m_num_params=0;

   this.m_counter_time_done=false;

   this.m_counter_refresh_done=false;

  }

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

//| CIndicatorsBase "09<5@                                           |

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

void CIndicatorsBase::OnTimer(void)

  {

   this.m_counter_time_done=this.m_counter_time.IsTimeDone();

   if(this.m_counter_time_done)

      this.Time(1);

   this.m_counter_refresh_done=this.m_counter_refresh.IsTimeDone();

  }

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

//| CIndicatorsBase #AB0=>2:0 AGQBG8:0 B09<5@0 2@5<5=8               |

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

void CIndicatorsBase::SetCounterTime(const uint step,const uint pause)

  {

   this.m_counter_time.SetParams(step,pause);

  }

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

//| CIndicatorsBase #AB0=>2:0 AGQBG8:0 B09<5@0 >1=>2;5=8O            |

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

void CIndicatorsBase::SetCounterRefresh(const uint step,const uint pause)

  {

   this.m_counter_refresh.SetParams(step,pause);

  }

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

//| CIndicatorsBase !>740QB 8=48:0B>@ ?> 8<5=8                       |

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

bool CIndicatorsBase::Create(const string indicator_name,const int buffers_num)

  {

   if(this.m_num_params==0)

     {

      Print(__FUNCSIG__,": Error. First, you need to set the indicator parameters");

      this.m_handle_success=false;

      this.m_handle=INVALID_HANDLE;

      this.m_buffers_total=0;

      this.m_num_params=0;

      return false;

     }

   //---

   this.m_name_indicator=indicator_name;

   this.m_buffers_total=(buffers_num<1 ? 1 : buffers_num>512 ? 512 : buffers_num);

   int size=ArraySize(this.m_params);

   ArrayResize(this.m_params,size+1);

   for(int i=size;i>0;i--)

     {

      this.m_params[i].type=this.m_params[i-1].type;

      this.m_params[i].double_value=this.m_params[i-1].double_value;

      this.m_params[i].integer_value=this.m_params[i-1].integer_value;

      this.m_params[i].string_value=this.m_params[i-1].string_value;

     }

   this.m_params[0].type=TYPE_STRING;

   this.m_params[0].string_value=this.m_name_indicator;

   this.m_num_params++;

   //---

   ::ResetLastError();

   this.m_handle_success=CIndicator::Create(this.m_symbol,this.m_period,IND_CUSTOM,this.m_num_params,this.m_params);

   if(!this.m_handle_success)

     {

      Print(__FUNCSIG__,": Error creating indicator ",::GetLastError());

      this.m_handle_success=false;

      this.m_handle=INVALID_HANDLE;

      this.m_buffers_total=0;

      this.m_num_params=0;

      return false;

     }

   return this.m_handle_success;

  }

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

//| CIndicatorsBase !>740QB 8=48:0B>@ ?> B8?C                        |

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

bool CIndicatorsBase::Create(const ENUM_INDICATOR indicator_type,const int buffers_num)

  {

   if(this.m_num_params==0)

     {

      Print(__FUNCSIG__,": Error. First, you need to set the indicator parameters");

      this.m_handle_success=false;

      this.m_handle=INVALID_HANDLE;

      this.m_buffers_total=0;

      this.m_num_params=0;

      return false;

     }

   if(indicator_type==IND_CUSTOM)

     {

      Print(__FUNCSIG__,": Error. To create a custom indicator, use the CIndicatorsBase::Create(const string indicator_name,const int buffers_num) method.");

      this.m_handle_success=false;

      this.m_handle=INVALID_HANDLE;

      this.m_buffers_total=0;

      this.m_num_params=0;

      return false;

     }

   //---

   this.m_name_indicator=this.SetName(indicator_type);

   CSeries::m_buffers_total=(buffers_num<1 ? 1 : buffers_num>512 ? 512 : buffers_num);

   //---

   ::ResetLastError();

   this.m_handle_success=CIndicator::Create(this.m_symbol,this.m_period,indicator_type,this.m_num_params,this.m_params);

   if(!this.m_handle_success)

     {

      Print(__FUNCSIG__,": Error creating indicator ",this.Name()," ",::GetLastError(),", m_num_params=",m_num_params);

      this.m_handle_success=false;

      this.m_handle=INVALID_HANDLE;

      this.m_buffers_total=0;

      this.m_num_params=0;

      return false;

     }

   return this.m_handle_success;

  }

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

//| CIndicatorsBase 8=8F80;870F8O                                    |

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

bool CIndicatorsBase::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])

  {

   if(CIndicator::CreateBuffers(symbol,period,m_buffers_total))

     {

      //--- string of status of drawing

      CSeries::m_name=this.m_name_indicator+" "+symbol+" "+this.TimeframeDescription()+" "+params[0].string_value;

      CIndicator::m_status="("+this.m_name_indicator+" "+symbol+" "+this.TimeframeDescription();

      for(int i=(this.m_type==IND_CUSTOM ? 1 : 0);i<num_params;i++)

        {

         switch(params[i].type)

           {

            case TYPE_BOOL    : CIndicator::m_status+=","+((params[i].integer_value) ? "true" : "false");  break;

            case TYPE_CHAR    : case TYPE_UCHAR: case TYPE_SHORT: case TYPE_USHORT: 

            case TYPE_INT     : case TYPE_UINT:  case TYPE_LONG:

            case TYPE_ULONG   : CIndicator::m_status+=","+IntegerToString(params[i].integer_value);         break;

            case TYPE_COLOR   : CIndicator::m_status+=","+ColorToString((color)params[i].integer_value);    break;

            case TYPE_DATETIME: CIndicator::m_status+=","+TimeToString(params[i].integer_value);            break;

            case TYPE_FLOAT   :

            case TYPE_DOUBLE  : CIndicator::m_status+=","+DoubleToString(params[i].double_value,2);         break;

            case TYPE_STRING  : CIndicator::m_status+=",'"+params[i].string_value+"'";                      break;

            default           : break;

           }

        }

      CIndicator::m_status+=") Handle="+IntegerToString(CIndicator::m_handle);

      //--- create buffers

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

         ((CIndicatorBuffer*)At(i)).Name("LINE "+IntegerToString(i));

      //--- ok

      return true;

     }

//--- error

   return false;

  }

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

//| CIndicatorsBase 1=>2;O5B 8=48:0B>@                              |

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

void CIndicatorsBase::Refresh(void)

  {

   this.SetRefreshFlags(CIndicator::BarsCalculated()==this.m_prev_calculated,this.m_refresh_flags);

   if(this.m_prev_calculated!=CIndicator::BarsCalculated())

     {

      this.m_prev_calculated=CIndicator::BarsCalculated();

     }

   CIndicator::Refresh(this.m_refresh_flags);

  }

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

//| CIndicatorsBase CAB0=>2:0 D;03>2 >1=>2;5=8O                      |

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

void CIndicatorsBase::SetRefreshFlags(const bool refresh_current,const int refresh_periods=OBJ_ALL_PERIODS)

  {

   CSeries::RefreshCurrent(refresh_current);

   this.m_refresh_flags=refresh_periods;

  }

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

//| CIndicatorsBase #AB0=>2:0 >4=>3> ?0@0<5B@0                       |

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

template<typename T>

void CIndicatorsBase::SetParameter(const T value)

  {

   string type=typename(value);

   this.m_num_params++;

   if(::ArraySize(this.m_params)<this.m_num_params)

      ::ArrayResize(this.m_params,this.m_num_params);

   if(type=="string")

     {

      this.m_params[this.m_num_params-1].type=TYPE_STRING;

      this.m_params[this.m_num_params-1].string_value=(string)value;

     }

   else if(type=="bool")

     {

      this.m_params[this.m_num_params-1].type=TYPE_BOOL;

      this.m_params[this.m_num_params-1].integer_value=(bool)value;

     }

   else if(type=="char")

     {

      this.m_params[this.m_num_params-1].type=TYPE_CHAR;

      this.m_params[this.m_num_params-1].integer_value=(char)value;

     }

   else if(type=="uchar")

     {

      this.m_params[this.m_num_params-1].type=TYPE_UCHAR;

      this.m_params[this.m_num_params-1].integer_value=(uchar)value;

     }

   else if(type=="short")

     {

      this.m_params[this.m_num_params-1].type=TYPE_SHORT;

      this.m_params[this.m_num_params-1].integer_value=(short)value;

     }

   else if(type=="ushort")

     {

      this.m_params[this.m_num_params-1].type=TYPE_USHORT;

      this.m_params[this.m_num_params-1].integer_value=(ushort)value;

     }

   else if(type=="color")

     {

      this.m_params[this.m_num_params-1].type=TYPE_COLOR;

      this.m_params[this.m_num_params-1].integer_value=(color)value;

     }

   else if(type=="int")

     {

      this.m_params[this.m_num_params-1].type=TYPE_INT;

      this.m_params[this.m_num_params-1].integer_value=(int)value;

     }

   else if(type=="uint")

     {

      this.m_params[this.m_num_params-1].type=TYPE_UINT;

      this.m_params[this.m_num_params-1].integer_value=(uint)value;

     }

   else if(type=="datetime")

     {

      this.m_params[this.m_num_params-1].type=TYPE_DATETIME;

      this.m_params[this.m_num_params-1].integer_value=(datetime)value;

     }

   else if(type=="long")

     {

      this.m_params[this.m_num_params-1].type=TYPE_LONG;

      this.m_params[this.m_num_params-1].integer_value=(long)value;

     }

   else if(type=="ulong")

     {

      this.m_params[this.m_num_params-1].type=TYPE_ULONG;

      this.m_params[this.m_num_params-1].integer_value=(long)value;

     }

   else if(type=="float")

     {

      this.m_params[this.m_num_params-1].type=TYPE_FLOAT;

      this.m_params[this.m_num_params-1].double_value=(float)value;

     }

   else if(type=="double")

     {

      this.m_params[this.m_num_params-1].type=TYPE_DOUBLE;

      this.m_params[this.m_num_params-1].double_value=(double)value;

     }

  }

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

//| ;0AA-:>;;5:F8O 8=48:0B>@>2                                      |

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

class CIndCollection : public CObject

  {

protected:

   CTimerCounter     m_counter_time;

   CTimerCounter     m_counter_refresh;

   CArrayObj         m_list_ind;

   string            m_symbol;

   ENUM_TIMEFRAMES   m_timeframe;

   bool              m_counter_refresh_done;

   bool              m_counter_time_done;

   int               m_index_x;

   int               m_index_y;

   int               m_digits;

   double            m_point;

   datetime          Time(const int shift) const { datetime array[]; return(::CopyTime(this.m_symbol,this.m_timeframe,1,1,array)==1 ? array[0]: 0);   }

public:

   CIndicatorsBase*  GetIndByID(const int ind_id);

   CArrayObj*        GetList(void)                    { return &m_list_ind;                  }

   bool              Add(CIndicatorsBase* ind)        { return this.m_list_ind.Add(ind);     }

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

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

   bool              IsCounterRefreshDone(void)       { return this.m_counter_refresh_done;  }

   bool              IsCounterTimeDone(void)          { return this.m_counter_time_done;     }

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

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

   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;                }

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

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

   void              SetCounterTime(const uint step,const uint pause);

   void              SetCounterRefresh(const uint step,const uint pause);

   void              OnTimer(void);

   void              Refresh(void);

                     CIndCollection(const string symbol_name,const ENUM_TIMEFRAMES timeframe);

                    ~CIndCollection(void);

  };

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

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

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

CIndCollection::CIndCollection(const string symbol_name,const ENUM_TIMEFRAMES timeframe) : m_index_x(0),

                                                                                           m_index_y(0),

                                                                                           m_counter_refresh_done(false),

                                                                                           m_counter_time_done(false)

  {

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

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

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

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

   this.SetCounterRefresh(16,250);

   this.SetCounterTime(16,90000);

  }

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

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

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

CIndCollection::~CIndCollection(void)

  {

   this.m_counter_time_done=false;

   this.m_counter_refresh_done=false;

  }

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

//| CIndCollection 1=>2;O5B :>;;5:F8N 8=48:0B>@>2                   |

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

void CIndCollection::Refresh(void)

  {

   int total=this.m_list_ind.Total();

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

     {

      CIndicatorsBase* ind=this.m_list_ind.At(i);

      if(ind==NULL)

         continue;

      ind.Refresh();

     }

  }

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

//| CIndCollection "09<5@                                            |

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

void CIndCollection::OnTimer(void)

  {

   this.m_counter_time_done=this.m_counter_time.IsTimeDone();

   if(this.m_counter_time_done)

     {

      this.Time(1);

     }

   this.m_counter_refresh_done=this.m_counter_refresh.IsTimeDone();

  }

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

//| CIndCollection #AB0=>2:0 AGQBG8:0 B09<5@0 2@5<5=8                |

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

void CIndCollection::SetCounterTime(const uint step,const uint pause)

  {

   this.m_counter_time.SetParams(step,pause);

  }

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

//| CIndCollection #AB0=>2:0 AGQBG8:0 B09<5@0 >1=>2;5=8O             |

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

void CIndCollection::SetCounterRefresh(const uint step,const uint pause)

  {

   this.m_counter_refresh.SetParams(step,pause);

  }

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

//| CIndCollection 2>72@0I05B C:070B5;L =0 8=48:0B>@ ?> B8?C         |

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

CIndicatorsBase* CIndCollection::GetIndByID(const int ind_id)

  {

   int total=this.m_list_ind.Total();

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

     {

      CIndicatorsBase* ind=this.m_list_ind.At(i);

      if(ind.Type()==ind_id)

         return ind;

     }

   return NULL;

  }

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



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

//| =48:0B>@                                                        |

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

#property description "Multitimeframe Multi Currency Pair Percentage Price Follower Dashboard"

#property description "Percentage Price Follower: https://www.mql5.com/ru/code/23800"

#property version   "1.00"

#include <Arrays\ArrayObj.mqh>

#include <Arrays\ArrayString.mqh>

#include <Arrays\ArrayInt.mqh>

#property indicator_separate_window

#property indicator_buffers 0

#property indicator_plots   0

//--- enums

enum ENUM_INPUT_YES_NO

  {

   INPUT_YES   =  1,       // Yes

   INPUT_NO    =  0        // No

  };

//---

enum ENUM_FOLLOW_TYPE

  {

   TYPE_FOLLOW_PRICE,      // Follows the price 

   TYPE_FOLLOW_DAY_CHANGE  // Follows the daily changes

  };

//--- input parameters

input ENUM_FOLLOW_TYPE  InpTypeFollow           =  TYPE_FOLLOW_PRICE;// Type of following

input uint              InpPercentRange1        =  10;               // High-Low Range (Follows the price)

input int               InpPercentRange2        =  90;               // Open-Close Range (Follows the daily changes)

//---

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

input ENUM_INPUT_YES_NO InpUseM1                =  INPUT_YES;        // Use 1 minute timeframe

input ENUM_INPUT_YES_NO InpUseM2                =  INPUT_NO;         // Use 2 minute timeframe

input ENUM_INPUT_YES_NO InpUseM3                =  INPUT_NO;         // Use 3 minute timeframe

input ENUM_INPUT_YES_NO InpUseM4                =  INPUT_NO;         // Use 4 minute timeframe

input ENUM_INPUT_YES_NO InpUseM5                =  INPUT_YES;        // Use 5 minute timeframe

input ENUM_INPUT_YES_NO InpUseM6                =  INPUT_NO;         // Use 6 minute timeframe

input ENUM_INPUT_YES_NO InpUseM10               =  INPUT_NO;         // Use 10 minute timeframe

input ENUM_INPUT_YES_NO InpUseM12               =  INPUT_NO;         // Use 12 minute timeframe

input ENUM_INPUT_YES_NO InpUseM15               =  INPUT_YES;        // Use 15 minute timeframe

input ENUM_INPUT_YES_NO InpUseM20               =  INPUT_NO;         // Use 20 minute timeframe

input ENUM_INPUT_YES_NO InpUseM30               =  INPUT_YES;        // Use 30 minute timeframe

input ENUM_INPUT_YES_NO InpUseH1                =  INPUT_YES;        // Use 1 hour timeframe

input ENUM_INPUT_YES_NO InpUseH2                =  INPUT_NO;         // Use 2 hour timeframe

input ENUM_INPUT_YES_NO InpUseH3                =  INPUT_NO;         // Use 3 hour timeframe

input ENUM_INPUT_YES_NO InpUseH4                =  INPUT_YES;        // Use 4 hour timeframe

input ENUM_INPUT_YES_NO InpUseH6                =  INPUT_NO;         // Use 6 hour timeframe

input ENUM_INPUT_YES_NO InpUseH8                =  INPUT_NO;         // Use 8 hour timeframe

input ENUM_INPUT_YES_NO InpUseH12               =  INPUT_NO;         // Use 12 hour timeframe

input ENUM_INPUT_YES_NO InpUseD1                =  INPUT_YES;        // Use 1 Day timeframe

input ENUM_INPUT_YES_NO InpUseW1                =  INPUT_NO;         // Use 1 Week timeframe

input ENUM_INPUT_YES_NO InpUseMN1               =  INPUT_NO;         // Use 1 Month timeframe

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              =  clrGreen;         // Panel: PPF up direction color

input color             InpColorDN              =  clrRed;           // Panel: PPF Entry down direction color

input color             InpColorNL              =  clrLightGray;     // Panel: PPF Neutral direction color

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

//--- global variables

CArrayString   list_symbols;

CArrayInt      list_timeframes;

CArrayObj      list_ind;

CWnd           panel;

//--- PPF

int            range1;

int            range2;

//---

string         custom_ind_name;

string         array_symbols[];

string         gv_name;

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

//| Custom indicator initialization function                         |

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

int OnInit()

  {

//--- timer

   EventSetMillisecondTimer(16);

//--- setting indicator parameters

   gv_name="MTF_MCP_Percentage_price_follower";

   custom_ind_name="Percentage_Price_Follower";

//--- PPF

   range1=int(InpPercentRange1<1 ? 1 : InpPercentRange1);

   range2=(InpPercentRange2==0 ? 1 : InpPercentRange2);

//---

   if(!ArraysPreparing())

     {

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

      return INIT_FAILED;

     }

//---

   list_ind.Clear();

   int total_sym=list_symbols.Total();

   int total_tfs=list_timeframes.Total();

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

     {

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

        {

         ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)list_timeframes.At(t);

         string symbol=list_symbols.At(s);

         CIndCollection* collection=new CIndCollection(symbol,timeframe);

         if(collection==NULL)

            continue;

         //--- Set coordinates

         collection.SetIndexX(t);

         collection.SetIndexY(s);

         //--- Add TDI into array_obj list

         CIndicatorsBase* ppf=new CIndicatorsBase(symbol,timeframe,IND_CUSTOM);

         if(ppf!=NULL)

           {

            collection.Add(ppf);

            ppf.SetParameter((int)InpTypeFollow);     // Set PPF Type of following

            ppf.SetParameter(range1);                 // Set PPF High-Low Range

            ppf.SetParameter(range2);                 // Set PPF Open-Close Range

            if(!ppf.Create(custom_ind_name,1))

              {

               Print(ppf.Symbol()," ",ppf.TimeframeDescription(),": Failed to create ",ppf.Name(),"'s handle. Please restart the indicator");

               delete ppf;

               return INIT_FAILED;

              }

            else

              {

               ppf.SetRefreshFlags(true,OBJ_ALL_PERIODS);

               ppf.Refresh();

              }

           }

         list_ind.Add(collection);

        }

     }



//--- 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()

  {

   static long last_time=0;

   MqlTick tick;

   bool refresh=false;

   int total=list_ind.Total();

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

     {

      CIndCollection* collection=list_ind.At(i);

      if(collection==NULL)

         continue;

      collection.OnTimer();

      if(collection.IsCounterRefreshDone())

        {

         if(SymbolInfoTick(collection.Symbol(),tick))

           {

            if(tick.time_msc>last_time)

              {

               last_time=tick.time_msc;

               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=list_timeframes.Total();

   CCanvas *canvas=panel.GetFieldCanvas();

   if(canvas==NULL)

     {

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

      return;

     }

   int shiftV=14,shiftH=68,startH=56,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_ind.Total();

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

     {

      CIndCollection* collection=list_ind.At(i);

      if(collection==NULL)

         continue;

      collection.Refresh();

      int x=collection.IndexX();

      int y=collection.IndexY();

      if(y==0)

        {

         string tf=collection.TimeframeDescription();

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

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

         if(x==0)

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

        }

      if(x==0)

        {

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

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

        }

      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));



   //--- PPF

      int digits=collection.Digits();

      double ppf0=0,ppf1=0;

      CIndicatorsBase* ppf=collection.GetIndByID(IND_CUSTOM);

      if(ppf!=NULL)

        {

         ppf0=ppf.GetData(0,0);

         ppf1=ppf.GetData(0,1);

         color clr_ppf=InpColorNL;

         if(ppf0!=EMPTY_VALUE && ppf1!=EMPTY_VALUE)

           {

            if(ppf0>ppf1)

              {

               clr_ppf=InpColorUP;

               TriangleUp(canvas,gx+20,gy,clr_ppf,panel.NewColor(clr_ppf,40,40,40));

               string text=DoubleToString(ppf0,digits);

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

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

              }

            else if(ppf0<ppf1)

              {

               clr_ppf=InpColorDN;

               TriangleDown(canvas,gx+20,gy,clr_ppf,panel.NewColor(clr_ppf,40,40,40));

               string text=DoubleToString(ppf0,digits);

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

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

              }

            else

              {

               clr_ppf=InpColorNL;

               TriangleRight(canvas,gx+20,gy,panel.NewColor(clr_ppf,-40,-40,-40),panel.NewColor(clr_ppf,40,40,40));

               string text=DoubleToString(ppf0,digits);

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

               canvas.TextOut(startH+(shiftH/2)-14+x*shiftH,startV+y*shiftV,text,ColorToARGB(panel.NewColor(clr_ppf,-50,-50,-50)),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)

  {

   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));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd),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)

  {

   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));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd),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)

  {

   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));

   canvas.TriangleWu(x1,y1,x2,y2,x3,y3,ColorToARGB(clr_bd),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)

  {

   if(canvas==NULL)

      return;

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

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

  }

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

//| @>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;

  }

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

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

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

int IndexTimeframe(const ENUM_TIMEFRAMES timeframe)

  {

   int total=list_timeframes.Total();

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

      if((ENUM_TIMEFRAMES)list_timeframes.At(i)==timeframe)

         return i;

   return WRONG_VALUE;

  }

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

//| >43>B>2:0 <0AA82>2                                              |

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

bool ArraysPreparing(void)

  {

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

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

     }

//---

   list_timeframes.Clear();

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

     {

      int tf=GetInputTimeframe(i);

      if(tf==WRONG_VALUE)

         continue;

      list_timeframes.Add((int)tf);

     }

   if(list_timeframes.Total()==0)

      list_timeframes.Add(Period());

   return true;

  }

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

//| >72@0I05B 2E>4=>9 ?0@0<5B@ B09<D@59<0 ?> 8=45:AC                |

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

int GetInputTimeframe(const int index)

  {

   switch(index)

     {

      case 0   : return (InpUseM1   ? PERIOD_M1    : WRONG_VALUE);

      case 1   : return (InpUseM2   ? PERIOD_M2    : WRONG_VALUE);

      case 2   : return (InpUseM3   ? PERIOD_M3    : WRONG_VALUE);

      case 3   : return (InpUseM4   ? PERIOD_M4    : WRONG_VALUE);

      case 4   : return (InpUseM5   ? PERIOD_M5    : WRONG_VALUE);

      case 5   : return (InpUseM6   ? PERIOD_M6    : WRONG_VALUE);

      case 6   : return (InpUseM10  ? PERIOD_M10   : WRONG_VALUE);

      case 7   : return (InpUseM12  ? PERIOD_M12   : WRONG_VALUE);

      case 8   : return (InpUseM15  ? PERIOD_M15   : WRONG_VALUE);

      case 9   : return (InpUseM20  ? PERIOD_M20   : WRONG_VALUE);

      case 10  : return (InpUseM30  ? PERIOD_M30   : WRONG_VALUE);

      case 11  : return (InpUseH1   ? PERIOD_H1    : WRONG_VALUE);

      case 12  : return (InpUseH2   ? PERIOD_H2    : WRONG_VALUE);

      case 13  : return (InpUseH3   ? PERIOD_H3    : WRONG_VALUE);

      case 14  : return (InpUseH4   ? PERIOD_H4    : WRONG_VALUE);

      case 15  : return (InpUseH6   ? PERIOD_H6    : WRONG_VALUE);

      case 16  : return (InpUseH8   ? PERIOD_H8    : WRONG_VALUE);

      case 17  : return (InpUseH12  ? PERIOD_H12   : WRONG_VALUE);

      case 18  : return (InpUseD1   ? PERIOD_D1    : WRONG_VALUE);

      case 19  : return (InpUseW1   ? PERIOD_W1    : WRONG_VALUE);

      default  : return (InpUseMN1  ? PERIOD_MN1   : WRONG_VALUE);

     }

  }

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

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---