#MTF_shi_channel_1_001
Download scriptOverview of the Indicator Logic
This script is designed to identify and visualize market trends by constructing a dynamic "channel" based on historical price extremes. Instead of relying on simple moving averages, it uses a geometric approach to detect structural shifts in the market, providing visual cues for potential entry points and trend directions.
Core Logic Breakdown
1. Identifying Key Structural Points (Fractals)
The script begins by scanning historical price data to find "fractals"—specific points where the price reaches a local high or low relative to the surrounding bars. It looks for these extremes over a specific window of time (the distance of which is automatically adjusted based on the timeframe you are viewing).
By identifying two significant extremes, the script establishes the foundation for its geometric channel:
- Point A: A primary anchor point.
- Point B: A secondary anchor point.
2. Channel Geometry and Slope
Once these two points are established, the script calculates the "Step" (the rate of change/slope) between them. This slope determines the angle of the channel.
- If the price is moving consistently in one direction, a clear upward or downward slope is formed.
- The logic then projects this slope forward into the future to create a visible corridor on your chart.
3. Dynamic Trend Analysis (The "Flat" Criteria)
A key feature of this script is its ability to distinguish between a trending market and a "flat" (sideways) market. It compares the current channel width against the market's volatility (using an Average True Range calculation).
- Trending Market: If the channel is wide enough relative to recent volatility, it considers the market to be in a clear trend.
- Flat Market: If the price movement is tight and lacks significant expansion, the script identifies the market as "flat" or consolidating.
4. Visual Projection and Signals
The script draws three distinct lines on your chart:
- Outer Boundary Lines: These represent the upper and lower limits of the current price channel.
- Mid-Line: A dotted line that represents the equilibrium point (the median) of the channel.
5. Automated Labeling
Depending on the relationship between the current price, the channel's slope, and the "Flat" criteria mentioned above, the script automatically attaches text labels to the lines:
- Buy/Sell: These appear when the market is in a trending phase and price interacts with the boundaries in a way that suggests a trend continuation or reversal.
- Take: These labels appear when the market is identified as "flat" or reaching a specific equilibrium, suggesting a zone where price may stall or consolidate rather than break out aggressively.
Summary of User Experience
When you apply this script, it essentially "maps" the current market geography. It looks back to see how the price has behaved, draws a corridor based on that behavior, and then projects that corridor forward. It tells you whether the market is currently "running" (Trending) or "resting" (Flat), while labeling the visual boundaries with actionable trend information.
//+------------------------------------------------------------------+
//| SHI_Channel.mq4 |
//|Alex_Bugalter |
//+------------------------------------------------------------------+
#property copyright "Alex_Bugalter"
#property link "Alex_Bugalter@treide.ru"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
double ExtMapBuffer1[];
//---- input parameters
extern int TimeFrame=60;
extern int AllBars=240;
extern int BarsForFract=50;
extern double flatCriteria=0.25;
extern color collor=Blue;
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;
int trend,flat;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,164);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexEmptyValue(0,0.0);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
void DelObj()
{
ObjectDelete("TL1"+TimeFrame);
ObjectDelete("TL2"+TimeFrame);
ObjectDelete("MIDL"+TimeFrame);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int i,limit,y=0;
int counted_bars=IndicatorCounted();
limit=Bars-counted_bars;
int X = (Ask-P1);
int X2 = (Bid-P2);
//----
if ((AllBars==0) || (Bars<AllBars)) AB=Bars; else AB=AllBars; //AB-êîëè÷åñòâî îáñ÷èòûâàåìûõ áàðîâ
// string TimeFrame;
if (BarsForFract>0)
BFF=BarsForFract;
else
{
switch (TimeFrame)
{
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;
X = P1;
}
}
CurrentBar=2; //ñ÷èòàåì ñ òðåòüåãî áàðà, ÷òîáû ôðàêòàë "çàêðåïèëñÿ
B1=y-1; B2=y-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(),TimeFrame,MODE_LOW,BFF*2+1,CurrentBar-BFF)))
{
if(UpDown==0)
{
UpDown=-1; B1=CurrentBar; P1=iLow(Symbol(),TimeFrame,B1);
}
else
{
B2=CurrentBar; P2=iLow(Symbol(),TimeFrame,B2);
}
}
if((UpDown>-1) && (CurrentBar==Highest(Symbol(),TimeFrame,MODE_HIGH,BFF*2+1,CurrentBar-BFF)))
{
if(UpDown==0)
{
UpDown=1; B1=CurrentBar; P1=iHigh(Symbol(),TimeFrame,B1);
}
else
{
B2=CurrentBar; P2=iHigh(Symbol(),TimeFrame,B2);
}
}
CurrentBar++;
}
if((B1==-1) || (B2==-1))
{
DelObj();
return(-1);
} // Çíà÷èò íå íàøëè ôðàêòàëîâ ñðåäè 300 áàðîâ
Step=(P2-P1)/(B2-B1);//Âû÷èñëèëè øàã, åñëè îí ïîëîæèòåëüíûé, òî êàíàë íèñõîäÿùèé
P1=P1-B1*Step; B1=0;//ïåðåñòàâëÿåì öåíó è ïåðâûé áàð ê íóëþ
//À òåïåðü îïîðíóþ òî÷êó ïðîòèâîïîëîæíîé ëèíèè êàíàëà.
ishift=0; iprice=0;
if(UpDown==1)
{
PP=iLow(Symbol(),TimeFrame,2)-2*Step;
for(i=3;i<=B2;i++)
{
if(iLow(Symbol(),TimeFrame,i)<PP+Step*i)
{
PP=iLow(Symbol(),TimeFrame,i)-i*Step;
}
}
if(iLow(Symbol(),TimeFrame,0)<PP)
{
ishift=0;
iprice=PP;
}
if(iLow(Symbol(),TimeFrame,1)<PP+Step)
{
ishift=1;
iprice=PP+Step;
}
if(iHigh(Symbol(),TimeFrame,0)>P1)
{
ishift=0;
iprice=P1;
}
if(iHigh(Symbol(),TimeFrame,1)>P1+Step)
{
ishift=1;
iprice=P1+Step;
}
}
else
{
PP=iHigh(Symbol(),TimeFrame,2)-2*Step;
for(i=3;i<=B2;i++)
{
if(iHigh(Symbol(),TimeFrame,i)>PP+Step*i)
{
PP=iHigh(Symbol(),TimeFrame,i)-i*Step;
}
}
if(iLow(Symbol(),TimeFrame,0)<P1)
{
ishift=0;
iprice=P1;
}
if(iLow(Symbol(),TimeFrame,1)<P1+Step)
{
ishift=1;
iprice=P1+Step;
}
if(iHigh(Symbol(),TimeFrame,0)>PP)
{
ishift=0;
iprice=PP;
}
if(iHigh(Symbol(),TimeFrame,1)>PP+Step)
{
ishift=1;
iprice=PP+Step;
}
}
//Òåïåðü ïåðåñòàâèì êîíå÷íóþ öåíó è áàð íà ÀÂ, ÷òîáû ëèíèè êàíàëà ðèñîâàëèñü ïîäëèííåå
P2=P1+AB*Step;
T1=Time[iBarShift(Symbol(),0,iTime(Symbol(),TimeFrame,B1))];
T2=Time[iBarShift(Symbol(),0,iTime(Symbol(),TimeFrame,AB))];
//Print("P1=",P1," P2=",P2);
//Åñëè íå áûëî ïåðåñå÷åíèÿ êàíàëà, òî 0, èíà÷å ñòàâèì ïñèñó.
if(iprice!=0) ExtMapBuffer1[ishift]=iprice;
//DelObj();
if (Step>0) trend=-1; else trend=1;
if (MathAbs(Step*20)>=2*iATR(Symbol(),TimeFrame,40,0)*flatCriteria) flat=0; else flat=1;
if (ObjectFind("TL1"+TimeFrame)==-1)
{
ObjectCreate("TL1"+TimeFrame,OBJ_TREND,0,T2,PP+Step*AB,T1,PP);
ObjectSet("TL1"+TimeFrame,OBJPROP_COLOR,collor);
ObjectSet("TL1"+TimeFrame,OBJPROP_WIDTH,1);
}
else
{
ObjectSet("TL1"+TimeFrame, OBJPROP_TIME1,T2);
ObjectSet("TL1"+TimeFrame, OBJPROP_PRICE1,PP+Step*AB);
ObjectSet("TL1"+TimeFrame, OBJPROP_TIME2,T1);
ObjectSet("TL1"+TimeFrame, OBJPROP_PRICE2,PP);
ObjectSet("TL1"+TimeFrame,OBJPROP_COLOR,collor);
ObjectSet("TL1"+TimeFrame,OBJPROP_WIDTH,1);
}
/*
ObjectSet("TL1",OBJPROP_COLOR,ForestGreen);
ObjectSet("TL1",OBJPROP_WIDTH,1);
ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
*/
if (ObjectFind("TL2"+TimeFrame)==-1)
{
ObjectCreate("TL2"+TimeFrame,OBJ_TREND,0,T2,P2,T1,P1);
ObjectSet("TL2"+TimeFrame,OBJPROP_COLOR,collor);
ObjectSet("TL2"+TimeFrame,OBJPROP_WIDTH,1);
}
else
{
ObjectSet("TL2"+TimeFrame, OBJPROP_TIME1,T2);
ObjectSet("TL2"+TimeFrame, OBJPROP_PRICE1,P2);
ObjectSet("TL2"+TimeFrame, OBJPROP_TIME2,T1);
ObjectSet("TL2"+TimeFrame, OBJPROP_PRICE2,P1);
ObjectSet("TL2"+TimeFrame,OBJPROP_COLOR,collor);
ObjectSet("TL2"+TimeFrame,OBJPROP_WIDTH,1);
}
/*
ObjectSet("TL2",OBJPROP_COLOR,ForestGreen);
ObjectSet("TL2",OBJPROP_WIDTH,1);
ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
*/
if (ObjectFind("MIDL"+TimeFrame)==-1)
{
ObjectCreate("MIDL"+TimeFrame,OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
ObjectSet("MIDL"+TimeFrame,OBJPROP_COLOR,collor);
ObjectSet("MIDL"+TimeFrame,OBJPROP_WIDTH,1);
ObjectSet("MIDL"+TimeFrame,OBJPROP_STYLE,STYLE_DOT);
}
else
{
ObjectSet("MIDL"+TimeFrame, OBJPROP_TIME1,T2);
ObjectSet("MIDL"+TimeFrame, OBJPROP_PRICE1,(P2+PP+Step*AB)/2);
ObjectSet("MIDL"+TimeFrame, OBJPROP_TIME2,T1);
ObjectSet("MIDL"+TimeFrame, OBJPROP_PRICE2,(P1+PP)/2);
ObjectSet("MIDL"+TimeFrame,OBJPROP_WIDTH,1);
ObjectSet("MIDL"+TimeFrame,OBJPROP_STYLE,STYLE_DOT);
ObjectSet("MIDL"+TimeFrame,OBJPROP_COLOR,collor);
}
/*
ObjectSet("MIDL",OBJPROP_COLOR,ForestGreen);
ObjectSet("MIDL",OBJPROP_WIDTH,1);
ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
*/
if (flat==1)
{
//Print("flat=1");
if(PP+Step*AB>P2)
{
ObjectSetText("TL1"+TimeFrame,"Sell");
ObjectSetText("TL2"+TimeFrame,"Buy");
}
else
{
ObjectSetText("TL2"+TimeFrame,"Sell");
ObjectSetText("TL1"+TimeFrame,"Buy");
}
}
else
{
//Print("flat=0");
if((PP+Step*AB>P2)&&(trend==-1))
{
ObjectSetText("TL1"+TimeFrame,"Sell");
ObjectSetText("TL2"+TimeFrame,"Take");
}
if((PP+Step*AB>P2)&&(trend==1))
{
ObjectSetText("TL1"+TimeFrame,"Take");
ObjectSetText("TL2"+TimeFrame,"Buy");
}
if((PP+Step*AB<P2)&&(trend==-1))
{
ObjectSetText("TL2"+TimeFrame,"Sell");
ObjectSetText("TL1"+TimeFrame,"Take");
}
if((PP+Step*AB<P2)&&(trend==1))
{
ObjectSetText("TL2"+TimeFrame,"Take");
ObjectSetText("TL1"+TimeFrame,"Buy");
}
}
//} //----
// Comment("Âåðõ êàíàëà = ",PP,"\n","Ñåðåäèíà = ",(P1+PP)/2,"\n","Íèç êàíàëà = ",P1,"\n","Øèðèíà = ",(PP-P1),"\n","Êàñàíèå Âåðõà = ",-(PP-Bid)," ïèïñîâ","\n","Êàñàíèå Íèçà = ",(P1-Ask)," ïèïñîâ");
return(0);
}
//+------------------------------------------------------------------+
Comments