TMLM-Channel-v2
Download scriptThis script is designed to analyze and visualize market trends by identifying specific price "channels" based on historical price action. It aims to help traders visualize the direction of the market and identify potential zones for entry or exit.
Here is a breakdown of how the logic functions:
Core Trend Identification
The tool begins by analyzing a specific window of historical data (based on the number of hours or bars you specify). It looks for "fractals," which are essentially local peaks (highs) and valleys (lows) in price movement. By finding these significant points, the script determines the dominant direction of the current market trend.
Linear Regression & Channel Construction
Once the primary high and low points are identified, the script performs a mathematical calculation to project a linear path. This creates a dynamic "channel" on your chart:
- Trend Line Generation: It calculates a slope based on the price difference between these historical peaks/valleys.
- Dynamic Projection: The script extends these lines forward into the present time, allowing you to see where the current trend is mathematically headed.
Dynamic Visual Feedback
The script provides real-time visual cues by drawing three distinct horizontal/diagonal references:
- Primary Support/Resistance: A main line that represents the core trajectory of the price move.
- Boundary Lines: Two additional lines that define the "walls" or boundaries of the channel.
- Color Coding & Alerts: The script monitors the current market price relative to these boundary lines.
- If the price gets too close to a specific boundary, the color of the line changes (e.g., to Red), and a text label appears on your screen indicating a potential opportunity (such as "Only LONG" or "Only SHORT"). This serves as a warning that the price is nearing a significant turning point or limit within the channel.
Automated Calculations
To keep the experience seamless for the user, the script handles all the heavy lifting automatically:
- Automatic Step Calculation: It calculates the "step" (the rate of change) between historical points to ensure the lines are geometrically accurate.
- Dynamic Object Management: It constantly clears and redraws these trend lines so that they always stay updated with the most recent price data without manual intervention.
- Time Synchronization: The tool automatically adjusts its time coordinates based on the specific timeframe you are viewing (e.g., adjusting from 1-minute charts to 4-hour charts).
Summary for the User
In essence, this tool acts as a "trend map." It looks back at where the price has peaked and dipped, draws a mathematical corridor representing that movement, and then alerts you visually when the current price is approaching the edges of that corridor. This helps in identifying whether the market is currently expanding, contracting, or reaching a point of exhaustion.
//+------------------------------------------------------------------+
//| SHI_Channel.mq4 |
//| Copyright © 2007, Shurka & Kevin |
//| ANG3110@latchess.com, join frantacech |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2004, Shurka & Kevin, ANG3110@latchess.com"
#property link ""
//----------------------------------
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
double ExtMapBuffer1[];
//---- input parameters
extern int AllBars=240;
extern int BarsForFract=0;
extern int Hours=720;
extern color WTL2col=Gold;
extern color WTL1col=Gold;
extern color WTL0col=Magenta;
extern int Trigger = 50;
int CurrentBar=0;
double Step=0;
int B1=-1,B2=-1;
int UpDown=0;
double P1=0,P2=0,PP=0;
int i=0,AB=300,BFF=0;
int ishift=0;
double iprice=0;
datetime T1,T2;
string entry;
//----------------------------------
double lr,lr0,lrp;
double sx,sy,sxy,sx2,aa,bb;
int p,fs;
int f,f0,f1;
double dh,dl,dh_1,dl_1,dh_2,dl_2;
int ai_1,ai_2,bi_1,bi_2;
double hai,lai,dhi,dli,dhm,dlm,ha0,hap,la0,lap;
double price_p1,price_p0,price_p2,price_01,price_00,price_02;
int p1,p0,p2,fp;
//*****************************************
int init() {
p=Hours*60/Period();
if (fs==0) {
fs=1;
}
//---- indicators
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,164);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexEmptyValue(0,0.0);
//----
return(0);
}
//*******************************
int deinit() {
ObjectDelete("WTL1");
ObjectDelete("WTL0");
ObjectDelete("WTL2"); }
//*******************************
void DelObj()
{
ObjectDelete("TL1");
ObjectDelete("TL2");
ObjectDelete("MIDL");
}
int start() {
int i,n;
//------------------------------------------------------------------------------
if (f==1) {
p1=iBarShift(Symbol(),Period(),ObjectGet("WTL1",OBJPROP_TIME1));
p0=iBarShift(Symbol(),Period(),ObjectGet("WTL0",OBJPROP_TIME1));
p2=iBarShift(Symbol(),Period(),ObjectGet("WTL2",OBJPROP_TIME1));
if (fp==0 && p!=p1) {p=p1; fp=1;}
if (fp==0 && p!=p0) {p=p0; fp=1;}
if (fp==0 && p!=p2) {p=p2; fp=1;}
}
//====================================================
sx=0; sy=0; sxy=0; sx2=0;
for (n=0; n<=p; n++) {sx+=n; sy+=Close[n]; sxy+=n*Close[n]; sx2+=MathPow(n,2);}
aa=(sx*sy-(p+1)*sxy)/(MathPow(sx,2)-(p+1)*sx2); bb=(sy-aa*sx)/(p+1);
//----------------------------------------------------
for (i=0; i<=p; i++) {
lr=bb+aa*i;
dh=High[i]-lr; dl=Low[i]-lr;
//----------------------------------------------------
if (i<p/2) {if (i==0) {dh_1=0.0; dl_1=0.0; ai_1=i; bi_1=i;}
if (dh>=dh_1) {dh_1=dh; ai_1=i;}
if (dl<=dl_1) {dl_1=dl; bi_1=i;}}
//----------------------------------------------------
if (i>=p/2) {if (i==p/2) {dh_2=0.0; dl_2=0.0; ai_2=i; bi_2=i;}
if (dh>=dh_2) {dh_2=dh; ai_2=i;}
if (dl<=dl_2) {dl_2=dl; bi_2=i;}}}
//-------------------------------------
lr0=bb; lrp=bb+aa*(i+p);
//===================================================
if (MathAbs(ai_1-ai_2)>MathAbs(bi_1-bi_2)) f=1;
if (MathAbs(ai_1-ai_2)<MathAbs(bi_1-bi_2)) f=2;
if (MathAbs(ai_1-ai_2)==MathAbs(bi_1-bi_2)) {if (MathAbs(dh_1-dh_2)<MathAbs(dl_1-dl_2)) f=1; if (MathAbs(dh_1-dh_2)>=MathAbs(dl_1-dl_2)) f=2;}
//=================================================
if (f==1) {
for (n=0; n<=20; n++) { f1=0;
for (i=0; i<=p; i++) {hai=High[ai_1]*(i-ai_2)/(ai_1-ai_2)+High[ai_2]*(i-ai_1)/(ai_2-ai_1);
if (i==0 || i==p/2) dhm=0.0;
if (High[i]-hai>dhm && i<p/2) {ai_1=i; f1=1;}
if (High[i]-hai>dhm && i>=p/2) {ai_2=i; f1=1;} }
if (f==0) break;}
//----------------------------
for (i=0; i<=p; i++) {hai=High[ai_1]*(i-ai_2)/(ai_1-ai_2)+High[ai_2]*(i-ai_1)/(ai_2-ai_1);
dli=Low[i]-hai;
if (i==0) dlm=0.0; if (dli<dlm) dlm=dli;}
ha0=High[ai_1]*(0-ai_2)/(ai_1-ai_2)+High[ai_2]*(0-ai_1)/(ai_2-ai_1);
hap=High[ai_1]*(p-ai_2)/(ai_1-ai_2)+High[ai_2]*(p-ai_1)/(ai_2-ai_1);
//----------------------------
//i have changed the code so the name of the trend does not change // Fadi
price_p1=hap;
price_p0=hap+dlm/2;
price_p2=hap+dlm;
price_01=ha0;
price_00=ha0+dlm/2;
price_02=ha0+dlm;
}
//=================================================
if (f==2) {
for (n=0; n<=20; n++) { f1=0;
for (i=0; i<=p; i++) {lai=Low[bi_1]*(i-bi_2)/(bi_1-bi_2)+Low[bi_2]*(i-bi_1)/(bi_2-bi_1);
if (i==0 || i==p/2) dlm=0.0;
if (Low[i]-lai<dlm && i<p/2) {bi_1=i; f1=1;}
if (Low[i]-lai<dlm && i>=p/2) {bi_2=i; f1=1;}}
if (f==0) break;}
//----------------------------
for (i=0; i<=p; i++) {lai=Low[bi_1]*(i-bi_2)/(bi_1-bi_2)+Low[bi_2]*(i-bi_1)/(bi_2-bi_1);
dhi=High[i]-lai;
if (i==0) dhm=0.0; if (dhi>dhm) dhm=dhi;}
la0=Low[bi_1]*(0-bi_2)/(bi_1-bi_2)+Low[bi_2]*(0-bi_1)/(bi_2-bi_1);
lap=Low[bi_1]*(p-bi_2)/(bi_1-bi_2)+Low[bi_2]*(p-bi_1)/(bi_2-bi_1);
//----------------------------------------------------------------
//i have changed the code so the name of the trend does not change // Fadi
price_p1=lap;
price_p0=lap+dhm/2;
price_p2=lap+dhm;
price_01=la0;
price_00=la0+dhm/2;
price_02=la0+dhm;
}
//===================================================================================
ObjectCreate("WTL1",2, 0,Time[p],price_p1,Time[0],price_01);
ObjectCreate("WTL0",2, 0,Time[p],price_p0,Time[0],price_00);
ObjectCreate("WTL2",2, 0,Time[p],price_p2,Time[0],price_02);
//-----------------------------------------------------------------
ObjectSet("WTL0",OBJPROP_COLOR,WTL0col);
ObjectSet("WTL0",OBJPROP_STYLE,STYLE_DOT);
//Comment(NormalizeDouble((price_02 - Ask)/Point,0), " ", NormalizeDouble((Bid - price_01)/Point,0));
//if (NormalizeDouble((price_02 - Ask)/Point,0) < Trigger && NormalizeDouble((price_02 - Ask)/Point,0) > 0)
if (NormalizeDouble((price_02 - Ask)/Point,0) < Trigger )
{
ObjectSet("WTL2",OBJPROP_COLOR,Red);
entry = " Only SHORT";
} else {ObjectSet("WTL2",OBJPROP_COLOR,WTL2col); entry = " LONG&SHORT";}
//if (NormalizeDouble((Bid - price_01)/Point,0) < Trigger && NormalizeDouble((Bid - price_01)/Point,0) > 0)
if (NormalizeDouble((Bid - price_01)/Point,0) < Trigger )
{
ObjectSet("WTL1",OBJPROP_COLOR,Red);
entry = " Only LONG";
} else {ObjectSet("WTL1",OBJPROP_COLOR,WTL1col);entry = " LONG&SHORT";}
ObjectSet("WTL0",OBJPROP_WIDTH,1); // these vaules control the width of the line
ObjectSet("WTL1",OBJPROP_WIDTH,2);
ObjectSet("WTL2",OBJPROP_WIDTH,2);
//---------------------------------------------
ObjectSet("WTL1",OBJPROP_TIME1,Time[p]);
ObjectSet("WTL1",OBJPROP_PRICE1,price_p1);
ObjectSet("WTL1",OBJPROP_TIME2,Time[0]);
ObjectSet("WTL1",OBJPROP_PRICE2,price_01);
ObjectSet("WTL0",OBJPROP_TIME1,Time[p]);
ObjectSet("WTL0",OBJPROP_PRICE1,price_p0);
ObjectSet("WTL0",OBJPROP_TIME2,Time[0]);
ObjectSet("WTL0",OBJPROP_PRICE2,price_00);
ObjectSet("WTL2",OBJPROP_TIME1,Time[p]);
ObjectSet("WTL2",OBJPROP_PRICE1,price_p2);
ObjectSet("WTL2",OBJPROP_TIME2,Time[0]);
ObjectSet("WTL2",OBJPROP_PRICE2,price_02);
//==================================================================
f=1; p1=p; p0=p; p2=p; fp=0;
//*************************************************************************************
//------
int counted_bars=IndicatorCounted();
//----
if ((AllBars==0) || (Bars<AllBars)) AB=Bars; else AB=AllBars; //AB-êîëè÷åñòâî îáñ÷èòûâàåìûõ áàðîâ
if (BarsForFract>0)
BFF=BarsForFract;
else
{
switch (Period())
{
case 1: BFF=12; break;
case 5: BFF=48; break;
case 15: BFF=24; break;
case 30: BFF=24; break;
case 60: BFF=12; break;
case 240: BFF=15; break;
case 1440: BFF=10; break;
case 10080: BFF=6; break;
default: DelObj(); return(-1); break;
}
}
CurrentBar=2; //ñ÷èòàåì ñ òðåòüåãî áàðà, ÷òîáû ôðàêòàë "çàêðåïèëñÿ
B1=-1; B2=-1; UpDown=0;
while(((B1==-1) || (B2==-1)) && (CurrentBar<AB))
{
//UpDown=1 çíà÷èò ïåðâûé ôðàêòàë íàéäåí ñâåðõó, UpDown=-1 çíà÷èò ïåðâûé ôðàêòàë
//íàéäåí ñíèçó, UpDown=0 çíà÷èò ôðàêòàë åù¸ íå íàéäåí.
//Â1 è Â2 - íîìåðà áàðîâ ñ ôðàêòàëàìè, ÷åðåç íèõ ñòðîèì îïîðíóþ ëèíèþ.
//Ð1 è Ð2 - ñîîòâåòñòâåííî öåíû ÷åðåç êîòîðûå áóäåì ëèíèþ ïðîâîäèòü
if((UpDown<1) && (CurrentBar==Lowest(Symbol(),Period(),MODE_LOW,BFF*2+1,CurrentBar-BFF)))
{
if(UpDown==0) { UpDown=-1; B1=CurrentBar; P1=Low[B1]; }
else { B2=CurrentBar; P2=Low[B2];}
}
if((UpDown>-1) && (CurrentBar==Highest(Symbol(),Period(),MODE_HIGH,BFF*2+1,CurrentBar-BFF)))
{
if(UpDown==0) { UpDown=1; B1=CurrentBar; P1=High[B1]; }
else { B2=CurrentBar; P2=High[B2]; }
}
CurrentBar++;
}
if((B1==-1) || (B2==-1)) {DelObj(); return(-1);} // Çíà÷èò íå íàøëè ôðàêòàëîâ ñðåäè 300 áàðîâ 8-)
Step=(P2-P1)/(B2-B1);//Âû÷èñëèëè øàã, åñëè îí ïîëîæèòåëüíûé, òî êàíàë íèñõîäÿùèé
P1=P1-B1*Step; B1=0;//ïåðåñòàâëÿåì öåíó è ïåðâûé áàð ê íóëþ
//À òåïåðü îïîðíóþ òî÷êó ïðîòèâîïîëîæíîé ëèíèè êàíàëà.
ishift=0; iprice=0;
if(UpDown==1)
{
PP=Low[2]-2*Step;
for(i=3;i<=B2;i++)
{
if(Low[i]<PP+Step*i) { PP=Low[i]-i*Step; }
}
if(Low[0]<PP) {ishift=0; iprice=PP;}
if(Low[1]<PP+Step) {ishift=1; iprice=PP+Step;}
if(High[0]>P1) {ishift=0; iprice=P1;}
if(High[1]>P1+Step) {ishift=1; iprice=P1+Step;}
}
else
{
PP=High[2]-2*Step;
for(i=3;i<=B2;i++)
{
if(High[i]>PP+Step*i) { PP=High[i]-i*Step;}
}
if(Low[0]<P1) {ishift=0; iprice=P1;}
if(Low[1]<P1+Step) {ishift=1; iprice=P1+Step;}
if(High[0]>PP) {ishift=0; iprice=PP;}
if(High[1]>PP+Step) {ishift=1; iprice=PP+Step;}
}
//Òåïåðü ïåðåñòàâèì êîíå÷íóþ öåíó è áàð íà ÀÂ, ÷òîáû ëèíèè êàíàëà ðèñîâàëèñü ïîäëèííåå
P2=P1+AB*Step;
T1=Time[B1]; T2=Time[AB];
//Åñëè íå áûëî ïåðåñå÷åíèÿ êàíàëà, òî 0, èíà÷å ñòàâèì ïñèñó.
if(iprice!=0) ExtMapBuffer1[ishift]=iprice;
DelObj();
Comment (PP,P1);
if (PP<P1)
{
if (entry == " LONG&SHORT")
{
ObjectCreate("TL1",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
ObjectSet("TL1",OBJPROP_COLOR,Lime);
ObjectSet("TL1",OBJPROP_WIDTH,2);
ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("TL2",OBJ_TREND,0,T2,P2,T1,P1);
ObjectSet("TL2",OBJPROP_COLOR,Lime);
ObjectSet("TL2",OBJPROP_WIDTH,2);
ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
if (entry == " Only LONG")
{
ObjectCreate("TL2",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
ObjectSet("TL2",OBJPROP_COLOR,Lime);
ObjectSet("TL2",OBJPROP_WIDTH,2);
ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
//ObjectCreate("TL1",OBJ_TREND,0,T2,P2,T1,P1);
// ObjectSet("TL1",OBJPROP_COLOR,Lime);
// ObjectSet("TL1",OBJPROP_WIDTH,2);
// ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
if (entry == " Only SHORT")
{
//ObjectCreate("TL2",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
// ObjectSet("TL2",OBJPROP_COLOR,Lime);
// ObjectSet("TL2",OBJPROP_WIDTH,2);
// ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("TL1",OBJ_TREND,0,T2,P2,T1,P1);
ObjectSet("TL1",OBJPROP_COLOR,Lime);
ObjectSet("TL1",OBJPROP_WIDTH,2);
ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
}
if (PP>P1)
{
if (entry == " LONG&SHORT")
{
ObjectCreate("TL2",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
ObjectSet("TL2",OBJPROP_COLOR,Lime);
ObjectSet("TL2",OBJPROP_WIDTH,2);
ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("TL1",OBJ_TREND,0,T2,P2,T1,P1);
ObjectSet("TL1",OBJPROP_COLOR,Lime);
ObjectSet("TL1",OBJPROP_WIDTH,2);
ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
if (entry == " Only LONG")
{
ObjectCreate("TL2",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
ObjectSet("TL2",OBJPROP_COLOR,Lime);
ObjectSet("TL2",OBJPROP_WIDTH,2);
ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
//ObjectCreate("TL1",OBJ_TREND,0,T2,P2,T1,P1);
// ObjectSet("TL1",OBJPROP_COLOR,Lime);
// ObjectSet("TL1",OBJPROP_WIDTH,2);
// ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
if (entry == " Only SHORT")
{
//ObjectCreate("TL2",OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
// ObjectSet("TL2",OBJPROP_COLOR,Lime);
// ObjectSet("TL2",OBJPROP_WIDTH,2);
// ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("TL1",OBJ_TREND,0,T2,P2,T1,P1);
ObjectSet("TL1",OBJPROP_COLOR,Lime);
ObjectSet("TL1",OBJPROP_WIDTH,2);
ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL",OBJPROP_COLOR,Lime);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
}
}
Comment(" Channel size = ", DoubleToStr(MathAbs(PP - P1)/Point,0), " Slope = ", DoubleToStr(-Step/Point, 2), ", ",entry);
//----
//------
//---- 10 seconds wait
Sleep(10000);
//---- refresh price data
RefreshRates();
return(0);}
//=====================================================================================
Comments