!channels_move
Download scriptThis 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:
- It defines a starting point and a look-back range.
- It identifies local minimums and maximums within the data.
- 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.
- 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.
//+------------------------------------------------------------------+
//| !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