Author: Copyright 2019, Igor Chemodanov
Price Data Components
Series array that contains the highest prices of each barSeries array that contains the highest prices of each barSeries array that contains the lowest prices of each barSeries array that contains the lowest prices of each bar
0 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

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