Author: Copyright 2019, Igor Chemodanov
1 Views
0 Downloads
0 Favorites
Channel_v1
ÿþ//+------------------------------------------------------------------+

//|                                                      Channel.mq4 |

//|                                  Copyright 2019, Igor Chemodanov |

//|                                             https://www.mql5.com |

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

#property copyright "Copyright 2019, Igor Chemodanov"

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

#property version   "1.00"

#property strict

#property description "Script draws \"Equidistant Channel\" graphical object." 

#property script_show_inputs 

input    string            InpName="Channel";      // Channel name

extern   ENUM_TIMEFRAMES   CanelTF=PERIOD_CURRENT; // Timeframe of determination  cannel's coordinates

input    color             InpColor=clrCoral;      // Channel color 

input    ENUM_LINE_STYLE   InpStyle=STYLE_SOLID;   // Style of channel lines 

input    int               InpWidth=1;             // Channel line width 

input    bool              InpSelection=false;     // Highlight to move 

bool  InpBack=false;    // Background channel 

bool  InpFill=false;    // Filling the channel with color 

bool  InpRayRight=true; // Channel's continuation to the right 

bool  InpHidden=true;   // Hidden in the object list 

long  InpZOrder=0;      // Priority for mouse click

//---



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

//| Create an equidistant channel by the given coordinates           | 

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

bool ChannelCreate(const long            chart_ID=0,        // chart's ID 

                   const string          name="Channel",    // channel name 

                   const int             sub_window=0,      // subwindow index  

                   datetime              time1=0,           // first point time 

                   double                price1=0,          // first point price 

                   datetime              time2=0,           // second point time 

                   double                price2=0,          // second point price 

                   datetime              time3=0,           // third point time 

                   double                price3=0,          // third point price 

                   const color           clr=clrRed,        // channel color 

                   const ENUM_LINE_STYLE style=STYLE_SOLID, // style of channel lines 

                   const int             width=1,           // width of channel lines 

                   const bool            fill=false,        // filling the channel with color 

                   const bool            back=false,        // in the background 

                   const bool            selection=true,    // highlight to move 

                   const bool            ray_right=false,   // channel's continuation to the right 

                   const bool            hidden=true,       // hidden in the object list 

                   const long            z_order=0)         // priority for mouse click 

  {

//--- reset the error value 

   ResetLastError();

//--- create a channel by the given coordinates 

   if(!ObjectCreate(chart_ID,name,OBJ_CHANNEL,sub_window,time1,price1,time2,price2,time3,price3))

     {

      Print(__FUNCTION__,

            ": failed to create an equidistant channel! Error code = ",GetLastError());

      return(false);

     }

//--- set channel color 

   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);

//--- set style of the channel lines 

   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);

//--- set width of the channel lines 

   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);

//--- display in the foreground (false) or background (true) 

   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);

//--- enable (true) or disable (false) the mode of highlighting the channel for moving 

//--- when creating a graphical object using ObjectCreate function, the object cannot be 

//--- highlighted and moved by default. Inside this method, selection parameter 

//--- is true by default making it possible to highlight and move the object 

   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);

   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);

//--- enable (true) or disable (false) the mode of continuation of the channel's display to the right 

   ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right);

//--- hide (true) or display (false) graphical object name in the object list 

   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);

//--- set the priority for receiving the event of a mouse click in the chart 

   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);

//--- successful execution 

   return(true);

  }

//---



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

//| Move the channel's anchor point                                  | 

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

bool ChannelPointChange(const long   chart_ID=0,     // chart's ID 

                        const string name="Channel", // channel name 

                        const int    point_index=0,  // anchor point index 

                        datetime     time=0,         // anchor point time coordinate 

                        double       price=0)        // anchor point price coordinate 

  {

//--- if point position is not set, move it to the current bar having Bid price 

   if(!time)

      time=TimeCurrent();

   if(!price)

      price=SymbolInfoDouble(Symbol(),SYMBOL_BID);

//--- reset the error value 

   ResetLastError();

//--- move the anchor point 

   if(!ObjectMove(chart_ID,name,point_index,time,price))

     {

      Print(__FUNCTION__,

            ": failed to move the anchor point! Error code = ",GetLastError());

      return(false);

     }

//--- successful execution 

   return(true);

  }

//---



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

//| Delete the channel                                               | 

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

bool ChannelDelete(const long   chart_ID=0,     // chart's ID 

                   const string name="Channel") // channel name 

  {

//--- reset the error value 

   ResetLastError();

//--- delete the channel 

   if(!ObjectDelete(chart_ID,name))

     {

      Print(__FUNCTION__,

            ": failed to delete the channel! Error code = ",GetLastError());

      return(false);

     }

//--- successful execution 

   return(true);

  }

//---



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

//| Calculates the angle of the channel (points per minute)          | 

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

double Angle(ushort &B[],        // offset coordinate

             datetime &Date[],   // time coordinate

             double &Price[],    // price coordinate

             int tf)             // timeframe of channel

  {

// time coordinate

   Date[0]=iTime(Symbol(),tf,B[0]);

   Date[1]=iTime(Symbol(),tf,B[1]);

   Date[2]=iTime(Symbol(),tf,B[2]);

   bool down=false; // slope of the channel down

   double High0=iHigh(Symbol(),tf,B[0]);

   double High1=iHigh(Symbol(),tf,B[1]);

   double Low0=iLow(Symbol(),tf,B[0]);

   double Low1=iLow(Symbol(),tf,B[1]);

   double DiffHigh=High1-High0;

   double DiffLow=Low1-Low0;

   if(DiffHigh<0.0 && DiffLow<0.0) down=true;

   else

      if(DiffHigh>=0.0 && DiffLow>=0.0) down=false;

   else

     {

      if(MathAbs(DiffHigh)>=MathAbs(DiffLow))

        {

         if(DiffHigh<0) down=true;

         else down=false;

        }

      else

         if(DiffLow<0) down=true;

      else down=false;

     }

// price coordinate

   if(down)

     {

      Price[0]=High0;

      Price[1]=High1;

      Price[2]=iLow(Symbol(),tf,B[2]);

     }

   else

     {

      Price[0]=Low0;

      Price[1]=Low1;

      Price[2]=iHigh(Symbol(),tf,B[2]);

     }

// check of price coordinate

   if(Price[1]-Price[0]<0.0)

     {

      Price[0]=High0;

      Price[1]=High1;

      Price[2]=iLow(Symbol(),tf,B[2]);

     }

   if(Price[1]-Price[0]>=0.0)

     {

      Price[0]=Low0;

      Price[1]=Low1;

      Price[2]=iHigh(Symbol(),tf,B[2]);

     }

// return angle of the channel

   return ((Price[1]-Price[0])/(Date[1]-Date[0]));

  }

//---



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

//| Move the channel                                                 | 

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

bool ChannelChange(datetime &Date[],   // time coordinate

                   double &Price[])    // price coordinate

  {

   for(uchar i=0;i<=2;i++)

      if(!ChannelPointChange(0,InpName,i,Date[i],Price[i]))

         return(false);

   Redraw();

   return(true);

  }

//---



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

//| Check anchor points                                              | 

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

bool CheckChannel(ushort &pos[], // offset coordinate

                  datetime &D[], // time coordinate

                  double &P[],   // price coordinate

                  int tf)        // timeframe of channel

  {

// Error in determining the intersection of the channel lines with price extrema

   double Delta=SymbolInfoDouble(Symbol(),SYMBOL_POINT)

                *(double)SymbolInfoInteger(Symbol(),SYMBOL_SPREAD);

   bool CorrectChanel=false;

   while(!IsStopped() &&                                                 // Check the forced shutdown

         iBarShift(Symbol(),PERIOD_MN1,iTime(Symbol(),tf,pos[0]))<250 && // Check time coordinate less 250 month 

         !CorrectChanel)                                                 // Channel not built

     {

      bool CorrectLine1=true;

      bool CorrectLine2=true;

      double A=0.0;

      ushort temp[3];

      ArrayCopy(temp,pos);

// Check coordinate of first line

      for(temp[1]=1;temp[1]<pos[0];temp[1]++)

        {

         temp[2]=temp[1];

         A=Angle(temp,D,P,tf);

         ChannelChange(D,P);

         CorrectLine1=true;

         for(ushort i=0;i<pos[0];i++)

           {

            if(i==temp[1]) continue;

            if((A<0.0 && ObjectGetValueByTime(0,InpName,iTime(Symbol(),tf,i),0)<

               iHigh(Symbol(),tf,i)-Delta) || 

               (A>=0.0 && ObjectGetValueByTime(0,InpName,iTime(Symbol(),tf,i),0)>

               iLow(Symbol(),tf,i)+Delta))

              {

               CorrectLine1=false;

               break;

              }

           }

         if(CorrectLine1)

           {

            pos[1]=temp[1];

            break;

           }

        }

// Check coordinate of second line

      if(CorrectLine1)

        {

         A=Angle(pos,D,P,tf);

         ArrayCopy(temp,pos);

         for(temp[2]=pos[1];temp[2]<=pos[0];temp[2]++)

           {

            D[2]=iTime(Symbol(),tf,temp[2]);

            if(A<0.0)

               P[2]=iLow(Symbol(),tf,temp[2]);

            else

               P[2]=iHigh(Symbol(),tf,temp[2]);

            ChannelChange(D,P);

            CorrectLine2=true;

            for(ushort i=0;i<=pos[0];i++)

              {

               if(i==temp[2]) continue;

               if((A<0.0 && ObjectGetValueByTime(0,InpName,iTime(Symbol(),tf,i),1)>

                  iLow(Symbol(),tf,i)+Delta)

                  || 

                  (A>=0.0 && ObjectGetValueByTime(0,InpName,iTime(Symbol(),tf,i),1)<

                  iHigh(Symbol(),tf,i)-Delta))

                 {

                  CorrectLine2=false;

                  break;

                 }

              }

            if(CorrectLine2)

              {

               pos[2]=temp[2];

               break;

              }

           }

        }

      if(!CorrectLine1 || !CorrectLine2)

         pos[0]++;

      else

        {

         if(Angle(pos,D,P,tf)<0.0)

           {

            if(iHigh(Symbol(),tf,pos[0])<=iHigh(Symbol(),tf,iHighest(Symbol(),tf,MODE_HIGH,3,pos[0]+1)))

              {pos[0]++; continue;}

           }

         else

         if(iLow(Symbol(),tf,pos[0])>=iLow(Symbol(),tf,iLowest(Symbol(),tf,MODE_LOW,3,pos[0]+1)))

           {pos[0]++; continue;}

         ChannelChange(D,P);

         CorrectChanel=true;

         Print("Channel built");

        }

     }

   return(CorrectChanel);

  }

//---



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

//| Redraw the chart and wait                                        | 

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

void Redraw()

  {

   ChartRedraw();

   Sleep(10);

  }

//---



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

//| Script program start function                                    | 

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

void OnStart()

  {

   int TF=CanelTF;

   if(TF==0) TF=Period();

// Delete the channel with same name

   if(ObjectFind(0,InpName)==0)

     {

      ChannelDelete(0,InpName);

      Redraw();

     }

// create the equidistant channel

   ushort Bar[3];

   datetime d[3];

   double p[3];

   Bar[0]=2; // offset 1 st point

   Bar[1]=1; // offset 2 nd point

   Bar[2]=1; // offset 3 rd point

   d[0]=iTime(Symbol(),TF,Bar[0]);  // time 1 st point

   d[1]=iTime(Symbol(),TF,Bar[1]);  // time 2 nd point

   d[2]=iTime(Symbol(),TF,Bar[2]);  // time 3 rd point

   p[0]=iHigh(Symbol(),TF,Bar[0]);  // price 1 st point

   p[1]=iHigh(Symbol(),TF,Bar[1]);  // price 2 nd point

   p[2]=iLow(Symbol(),TF,Bar[2]);   // price 3 rd point

   if(!ChannelCreate(0,InpName,0,d[0],p[0],d[1],p[1],d[2],p[2],InpColor,

      InpStyle,InpWidth,InpFill,InpBack,InpSelection,InpRayRight,InpHidden,InpZOrder))

      return;

   Redraw();

// Move the channel by angle

   double Angl=Angle(Bar,d,p,TF);

   if(!ChannelChange(d,p))

      return;

// Check anchor points & rebuild channel

   if(CheckChannel(Bar,d,p,TF))

     {

      Print("Angle=",(short)MathRound(60.0*TF*Angle(Bar,d,p,TF)/Point)," points per bar, bar=",TF," minutes");

      datetime T=TimeCurrent();

      Print("Price 1 st line ",NormalizeDouble(ObjectGetValueByTime(0,InpName,T,0),Digits),", ",

            "Price 2 nd line ",NormalizeDouble(ObjectGetValueByTime(0,InpName,T,1),Digits),", ",

            "Time ",T);

     }

   else

     {

      ChannelDelete(0,InpName);

      Redraw();

      Print("Channel not built!");

     }

  }

//---

Comments