!channels_move

Download script
Author: Nikolay Semko SemkoNV@bk.ru
!channels_move

This script is designed to analyze historical market data and automatically draw a series of support and resistance "channels" on a trading chart. Instead of just identifying single points in time, it attempts to visualize the geometric structure of price movements across multiple timeframes.

Here is a professional breakdown of the logic:

Multi-Timeframe Analysis

The script does not look at the market from just one perspective. It pulls historical data from nine different timeframes simultaneously (ranging from very short periods like 1 minute up to much larger scales like 43,200 minutes). By doing this, the script ensures that the channels it identifies are grounded in both immediate price action and broader market trends.

Dynamic Channel Construction

The core logic revolves around identifying "channels"—linear trends where price has historically moved. The script performs the following steps:

  • Geometric Calculation: It uses mathematical formulas to calculate linear regressions (best-fit lines) for price movements over specific windows of time.
  • Optimization: It looks for "optimal" lines by calculating the distance between price points and a theoretical line, attempting to find the path of least resistance or most significant trend.
  • Width and Depth: The script calculates the "width" of these channels. This helps in visualizing how much room the market typically has to move before encountering a boundary.

Visual Mapping & Identification

Once the logic identifies a significant channel, it translates that data into visual objects on your chart:

  • Trend Lines: It draws primary lines representing the trajectory of the price.
  • Support and Resistance Boundaries: It creates "Upper" and "Lower" boundaries for these channels. These act as zones where price might face pressure to bounce back or break through.
  • Zone Filling: If enabled, the script can create triangular shapes between these boundaries, visually highlighting the "trading zone" or the corridor in which the price is currently oscillating.

Automated Scanning Logic

Rather than drawing lines manually, the script systematically scans back through history:

  1. It defines a starting point and a look-back range.
  2. It identifies local minimums and maximums within the data.
  3. It filters these points based on a sensitivity setting (the "filter" variable), ensuring that only significant historical movements are turned into visible channels, while "noise" is ignored.
  4. It assigns unique colors to different channels so you can distinguish between various trends at a glance.

Summary for the User

In short, this script acts as an automated architect for your chart. It digs through multiple layers of time to find out where the market has historically "traveled" in linear paths, then draws a map of those corridors (with upper and lower bounds) to help you see where potential support and resistance zones currently exist.

Price Data Components
Series array that contains open prices of each barSeries array that contains the highest prices of each barSeries array that contains the lowest prices of each bar
4 Views
0 Downloads
0 Favorites
!channels_move
//+------------------------------------------------------------------+
//|                                               !channels_move.mq4 |
//|                      Copyright © 2011, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Nikolay Semko SemkoNV@bk.ru"
#property link      "http://www.7ko.org" //in the development of

// praise and scold at: SemkoNV@bk.ru
                                    

int StartR2=1000;
int FinishL2=400;
int MinDlina=0;
int tochnost=40;
double filtr = 0.55;
double k_shirina=4; 
double MinShirina=0;
bool luch =  true;      
bool maxmin =  true;   
                               
                               
bool color_fill =  true;

int p[9]={43200,10080,1440,240,60,30,15,5,1};
double     Shirina[2000];
double     Kanals[20][9];
double     CanalR[2000];
double     CanalL[2000];
double     ShirinaU[2000];
double     ShirinaD[2000];
int StartR;
int FinishL;

datetime x1,x2;
double sumPlus=0;
double sumMinus=0;
double yOptR,yOptL;
int prexL=0;
int prexR=0;
int  prevxR=-5;
int  prevp=0;
int prevper=-5;
double ma=0;
double sum1=0;
double sum2=0;
double curdeltaMax=-10000;
double curdeltaMin=10000;  
int pause=0;



void init()
  {
   LoadHist();
   Print("point = ", Point,"   bars=",Bars);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void deinit()
  {
   ObjectDelete("vertical");
   ObjectDelete("gorizontal");
   for (int i =0;i<20;i++)
   {
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0));
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" UP");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" DOWN");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" TRIUP");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" TRIDown");
   }
  }
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
   string name;
   double curdelta=0;
   datetime t;
   t = iTime(NULL,0,StartR2);
   ObjectCreate("vertical",OBJ_VLINE,0,t,0);
   ObjectSet("vertical", OBJPROP_COLOR, Crimson);
   ObjectCreate("gorizontal",OBJ_HLINE,0,iOpen(NULL,0,StartR2),0);
   ObjectSet("gorizontal", OBJPROP_COLOR, Crimson);
   
   datetime x1,x2;
   double y1,y2;
   int limit;
   /////////////////////////////////////////////////////////////////////
   for (int ii=StartR2;ii>0;ii--)
   {
       //ii=ii-1;
       Sleep(pause);
       t = iTime(NULL,0,ii);
       ObjectSet("vertical",OBJPROP_TIME1,t);
       ObjectSet("gorizontal",OBJPROP_PRICE1,iOpen(NULL,0,ii));
       StartR=ii;
       FinishL=StartR+FinishL2;
   
       limit=FinishL;
   
       int j=AllCanals(StartR,limit);
       BildCanals( j, StartR);
    }
  
   return(0);
  }

//+------------------------------------------------------------------+
///////////////////////////// Functions //////////////////////////////
//+------------------------------------------------------------------+

int BildCanals( int j,int Start)
{
 string name;
 datetime x1,x2;
 double y1,y2;
 int  color_i[]={C'200,0,0',C'200,100,0',C'160,160,0',C'100,200,0',C'0,200,0',C'0,200,100',C'0,180,180',C'0,60,120',C'0,0,200',C'100,0,200',C'160,0,160',C'160,80,120'};
 int color_i2[]={C'80,0,0', C'80,40,0',  C'60,60,0',  C'40,80,0',  C'0,80,0', C'0,80,40',  C'0,50,50',  C'0,20,40', C'0,0,80', C'40,0,80',  C'50,0,60',  C'60,20,50'};
 for (int i =j;i<20;i++)
   {
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0));
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" UP");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" DOWN");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" TRIUP");
   ObjectDelete("LineCanal9_"+DoubleToStr(i,0)+" TRIDown");

   Kanals[i][2]=0;
   Kanals[i][1]=0;
   Kanals[i][0]=0;
   }
  Comment("Êîëëè÷åñòâî êàíàëîâ = ",j);
                                 
  for (i=0; i<j; i++) 
     {
       x1 = iTime(NULL,0,Start);
       y1 = Kanals[i][3];
       if (iTime(NULL,0,(Bars-1))<=iTime(NULL,Kanals[i][2],Kanals[i][1]))
              {
              x2 = iTime(NULL,Kanals[i][2],Kanals[i][1]);
              y2 = Kanals[i][4];
              }
       else   
              {
              x2 = iTime(NULL,0,(Bars-1));
              if ((Kanals[i][6])!=0) y2 = y1-((iBarShift(NULL,Kanals[i][2],x2,FALSE)-iBarShift(NULL,Kanals[i][2],x1,FALSE))/Kanals[i][6])*(y1-Kanals[i][4]);
              }
       
       name = "LineCanal9_"+DoubleToStr(i,0);
       if (ObjectFind(name)==-1)
           {
           if (!ObjectCreate(name, OBJ_TREND, 0,x2,y2,x1,y1))    Comment("Error 0 = ",GetLastError());
           ObjectSet(name, OBJPROP_RAY, FALSE);
           ObjectSet(name, OBJPROP_COLOR, color_i[j-i-1]);
           ObjectSet(name, OBJPROP_STYLE, STYLE_DOT);
           ObjectSet(name, OBJPROP_RAY, luch);
           
           if (maxmin==true)
           ObjectCreate(name+" UP",   OBJ_TREND, 0, x2,(y2+Point*Kanals[i][7]),x1,(y1+Point*Kanals[i][7]));
           else
           ObjectCreate(name+" UP",   OBJ_TREND, 0, x2,(y2+k_shirina*Point*Kanals[i][0]), x1,(y1+k_shirina*Point*Kanals[i][0]));
           ObjectSet(name+" UP", OBJPROP_RAY, FALSE);
           ObjectSet(name+" UP", OBJPROP_COLOR, color_i[i]);
           ObjectSet(name+" UP", OBJPROP_STYLE, STYLE_DASH);
           ObjectSet(name+" UP", OBJPROP_RAY, luch);
           
           if (maxmin==true)
           ObjectCreate(name+" DOWN", OBJ_TREND, 0, x2,(y2+Point*Kanals[i][8]),x1,(y1+Point*Kanals[i][8]));
           else 
           ObjectCreate(name+" DOWN", OBJ_TREND, 0, x2,(y2-k_shirina*Point*Kanals[i][0]), x1,(y1-k_shirina*Point*Kanals[i][0]));
           ObjectSet(name+" DOWN", OBJPROP_RAY, FALSE);
           ObjectSet(name+" DOWN", OBJPROP_COLOR, color_i[i]);
           ObjectSet(name+" DOWN", OBJPROP_STYLE, STYLE_DASH);
           ObjectSet(name+" DOWN", OBJPROP_RAY, luch);
           
           if (color_fill==true)
           {
           ObjectCreate(name+" TRIUP", OBJ_TRIANGLE, 0, x2,(y2+Point*Kanals[i][7]),x1,(y1+Point*Kanals[i][7]),x2,(y2+Point*Kanals[i][8]));
           ObjectSet(name+" TRIUP", OBJPROP_COLOR, color_i2[i]);
           ObjectCreate(name+" TRIDown", OBJ_TRIANGLE, 0, x1,(y1+Point*Kanals[i][7]),x1,(y1+Point*Kanals[i][8]),x2,(y2+Point*Kanals[i][8]));
           ObjectSet(name+" TRIDown", OBJPROP_COLOR, color_i2[i]);
           }  
                      
           }
       else
           {
           if (!ObjectMove(name, 0, x2 ,y2))    Comment("Îøèáêà 1 = ",GetLastError());
           if (!ObjectMove(name, 1, x1, y1))    Comment("Îøèáêà 2 = ",GetLastError());
           if (maxmin==true)
            {
           ObjectMove(name+" UP", 0, x2, y2+Point*Kanals[i][7]);
           ObjectMove(name+" UP", 1, x1 ,y1+Point*Kanals[i][7]);
           
           ObjectMove(name+" DOWN", 0, x2, y2+Point*Kanals[i][8]);
           ObjectMove(name+" DOWN", 1, x1 ,y1+Point*Kanals[i][8]);
            
            if (color_fill==true)
           {
           ObjectMove(name+" TRIUP", 0, x2,(y2+Point*Kanals[i][7]));
           ObjectMove(name+" TRIUP", 1, x1,(y1+Point*Kanals[i][7]));
           ObjectMove(name+" TRIUP", 2, x2,(y2+Point*Kanals[i][8]));
           
           ObjectMove(name+" TRIDown", 0, x1,(y1+Point*Kanals[i][7]));
           ObjectMove(name+" TRIDown", 1, x1,(y1+Point*Kanals[i][8]));
           ObjectMove(name+" TRIDown", 2, x2,(y2+Point*Kanals[i][8]));
           }
           }
           else
            {
           ObjectMove(name+" UP", 0, x2 ,y2+k_shirina*Point*Kanals[i][0]);
           ObjectMove(name+" UP", 1, x1, y1+k_shirina*Point*Kanals[i][0]);
           
           ObjectMove(name+" DOWN", 0, x2 ,y2-k_shirina*Point*Kanals[i][0]);
           ObjectMove(name+" DOWN", 1, x1, y1-k_shirina*Point*Kanals[i][0]);
            }
           }
     }
return(0);
}

////////////////////////////////////////////////////////

int AllCanals(int Start, int Finish)
{
int i1=0,i2,i3;
int k=0;
int i=0;
int per;
int lastper;
int St,Fin;
datetime S,F,prevS,CurStart;
int lastmin;
double lmin;
double premin;
ArrayInitialize(Kanals,0);
lastper=9;


CurStart=iTime(NULL,Period(),Start);
if (Start==0) CurStart=iTime(NULL,1,0);
prevS=iTime(NULL,p[0],(iBarShift(NULL,p[0],CurStart,FALSE)+(Finish-Start)));
//ArrayInitialize(Kanals,0);
//ArrayInitialize(Shirina,0);

for (int jj=0;jj<lastper;jj++)
{
//ArrayInitialize(Shirina,0);
if (jj==8) 
     S = CurStart;
else S = iTime(NULL,p[jj+1],(iBarShift(NULL,p[jj+1],CurStart,FALSE)+(Finish-Start))); 
F = prevS;
prevS=S;
St= iBarShift(NULL,p[jj],CurStart,FALSE);
Fin=iBarShift(NULL,p[jj],F,FALSE);

if (St==0 && Fin==0)  return(0);
if (jj!=8) {ArrShirina(St,Fin,(iBarShift(NULL,p[jj],S,FALSE))-St-7,p[jj]);}// Print("1111111111  ",p[jj],"   ", St,"   ", Fin,"   ",(iBarShift(NULL,p[jj],S,FALSE))-St-7);}
     else  {ArrShirina(St,Fin,0,p[jj]); }//Print("888888888  ",p[jj],"   ", St,"   ", Fin);}
lastmin=Fin+1;
if (jj==0) lmin=10000000;
if (jj==0) premin=Shirina[Fin-St-1];  
 // Print(Start,"  ",p[jj],"  Ñòàðò - ",(iBarShift(NULL,p[jj],S,FALSE)),"  Ôèíèø - ",Fin);
   if(Fin>iBarShift(NULL,p[jj],S,FALSE)) 
    for(i=Fin-1; i>(iBarShift(NULL,p[jj],S,FALSE))-1; i--)
      {
        if (iTime(NULL,0,Bars-1)<=iTime(NULL,p[jj],i))
            {
            i3=iBarShift(NULL,0,iTime(NULL,p[jj],i),FALSE);
            for (i2=0;i2<=p[jj]/Period();i2++)
              {
              Shirina[i3-i2]=Shirina[i-St];
              }
            }
        if (Shirina[i-St]<lmin) {lmin=Shirina[i-St];lastmin=i;} 
        if(Shirina[i-St]<=Shirina[i-St-1] && Shirina[i-St]<=Shirina[i-St+1])
        if (lastmin==i)
          {
            if (Shirina[i-St]<premin*filtr && Shirina[i-St]>MinShirina)// && Shirina[i-St]<200) 
                 {
                   if (i1>0) for (k=0; k<i1; k++)
                      {
                       if (Shirina[i-St]!=0) if ((Kanals[k][0]/Shirina[i-St])<1.2 && (Kanals[k][0]/Shirina[i-St])>0.8) i1=k;
                      }
                  
                   Kanals[i1][0]= Shirina[i-St];                            
                   Kanals[i1][1]= i;                                        
                   Kanals[i1][2]= p[jj];                                    
                   Kanals[i1][3]= CanalR[i-St];                             
                   Kanals[i1][4]= CanalL[i-St];                             
                   if ((i-St)*p[jj]!=0) Kanals[i1][5]= (CanalR[i-St]-CanalL[i-St])/((i-St)*p[jj]);  
                   Kanals[i1][6]= (i-St);                                
                   Kanals[i1][7]= ShirinaU[i-St];                          
                   Kanals[i1][8]= ShirinaD[i-St];                           
                   premin=Shirina[i-St];
                   i1++;
                 }
          }
      }

}
return(i1);
}

//////////////////////////////////////////////////////////////////////
double ArrShirina(int Start1, int Finish, int Sdvig, int per)
{
if (Sdvig<0) Sdvig=0;
Shirina[0]=0;
yOptR=iOpen(NULL,per,Start1);

int d,i1;
double dC,dR,dL;
int p=0;
int lnz=Sdvig;
//Print("Start  ",Start1,"Finish   ",Finish);
for(int i=(1+Sdvig); i<(Finish-Start1); i++)
      {
      //x2 = iTime(NULL,per,i);
      if (tochnost!=0) p=MathFloor((i-1)/tochnost);
      i=i+p;
      Shirina[i] = MinCanal2(Start1,i+Start1,per);
      if(maxmin==true)
      {
      if( k_shirina*Shirina[i]<curdeltaMax/Point) ShirinaU[i]=(curdeltaMax/Point+k_shirina*Shirina[i])/2; else ShirinaU[i]=curdeltaMax/Point;
      if(-k_shirina*Shirina[i]>curdeltaMin/Point) ShirinaD[i]=(curdeltaMin/Point-k_shirina*Shirina[i])/2; else ShirinaD[i]=curdeltaMin/Point;
      }
      CanalL[i]  = yOptL;
      CanalR[i]  = yOptR;
      d=i-lnz;
      if (d!=0) {dC=(Shirina[i]-Shirina[lnz])/d;
      dR=(CanalR[i]-CanalR[lnz])/d;
      dL=(CanalL[i]-CanalL[lnz])/d;
      }
      if (d>1)
        for (i1=1;i1<d;i1++)
          {
            Shirina[lnz+i1] = Shirina[lnz+i1-1]+dC;
            CanalL[lnz+i1]  = CanalL[lnz+i1-1]+dL;
            CanalR[lnz+i1]  = CanalR[lnz+i1-1]+dR;
          }
      lnz=i;
      }
return(0);
}

///////////////////////////////////////////////////////
double MinCanal2(int xR,int xL,int per)
{
  double p=xL-xR;
  double j1,j2,j3,h1,h2,yR,yL,d;

  j1 = p + 1;
  j2 = p*(p+1)/2;
  j3 = p*(p+1)*(2*p+1)/6;
       

  if (prevxR!=xR || prevper!=per) 
   {
    prevp=0;
    sum1=0; 
    sum2=0;
   } 
   
   for(int n = prevp; n <= p; n++) 
         {
           sum2 += iOpen(NULL,per,n+xR); 
         }
    
   for(n = prevp; n <= p; n++) 
         {
           sum1 += iOpen(NULL,per,n+xR)*n; 
         }
   
  
  h2 = sum2;
  h1 = sum1;
  prevxR=xR;
  prevp=p+1;
  prevper=per;

  d = (j2*h2-j1*h1)/(j2*j2-j1*j3);
  
  yOptR = (h1-j3*d)/j2;
  yOptL = d*p+yOptR; 
  
  return(SumPlus2(xL,xR,yOptR,yOptL,per)/j1);
}
///////////////////////////////////////////////////////

double SumPlus2(int xL1, int xR1, double yR1,double yL1,int per)
{
double curLinePrice, curdelta,curdeltaH,curdeltaL,delta;
curdeltaMax=-100000;
curdeltaMin=100000;
int i = xR1;
if(xL1==xR1)return(0);
if ((xL1-xR1)!=0) delta = (yL1-yR1)/(xL1-xR1);
curLinePrice = yR1;
sumPlus=0;
 while (i<=xL1)
  {
    curdelta = iOpen(NULL,per,i) - curLinePrice;
    curdeltaH = iHigh(NULL,per,i) - curLinePrice;
    curdeltaL = iLow(NULL,per,i) - curLinePrice;
    if (curdeltaMax<curdeltaH) curdeltaMax=curdeltaH;
    if (curdeltaMin>curdeltaL) curdeltaMin=curdeltaL;
    if (curdelta>0) sumPlus = sumPlus+curdelta;
    curLinePrice = curLinePrice + delta;
    i++;
  }
return(sumPlus/Point);
}

////////////////////////////////////////////////////////////////////////////////////
void LoadHist()
{
int iPeriod[9];
iPeriod[0]=1;
iPeriod[1]=5;
iPeriod[2]=15;
iPeriod[3]=30;
iPeriod[4]=60;
iPeriod[5]=240;
iPeriod[6]=1440;
iPeriod[7]=10080;
iPeriod[8]=43200;
for (int iii=0;iii<9;iii++)
{
   datetime open = iTime(Symbol(), iPeriod[iii], 0);
   //datetime open = MarketInfo(Symbol(),MODE_TIME);
   int error=GetLastError();
   //Comment("");
   while(error==4066)
   {
      Comment("Did not load historical data for ",iPeriod[iii]," period, the indicator needs to be rebooted or move on to another timeframe");
      Sleep(10000);
      open = iTime(Symbol(), iPeriod[iii], 0);
      error=GetLastError();
   }
}
}


Comments