GannSwingsXV
Download scriptThis script is designed to analyze market price movements and identify key "swings"—the significant high and low points that define the structure of a price trend. It works by tracking the peaks and troughs of the market to help visualize how price cycles move from one point of interest to another.
Here is a breakdown of the logic used by the script:
Core Trend Identification
The indicator classifies the market into different states (Upward or Downward trends) based on price action. It looks for specific "swing" points where the price reaches a new extreme.
- High Swings: These are marked when the price hits a peak. The script tracks these to identify resistance levels.
- Low Swings: These are marked when the price hits a trough. The script tracks these to identify support levels.
Logic for Swing Detection
The script uses a counting system to decide when a swing is "confirmed." It doesn't just mark every high or low; it waits for specific conditions to be met:
- Trend Continuity: If the price continues to move in the same direction as the current trend, the script updates the highest high or lowest low.
- Trend Reversal: When the price moves sufficiently against the current trend (reaching a count defined by the user settings), the script recognizes this as a potential reversal. It then resets its counters and prepares to track the new trend direction.
Handling "Outside Bars"
A unique feature of this logic is how it handles "Outside Bars"—bars where the price movement is so wide that it encompasses both the previous high and the previous low. The script treats these differently:
- If a bar is an "Outside Bar," it triggers a specific logic path to determine if the trend has been broken or if the new move is significant enough to redefine the swing points.
- It can also highlight these bars visually, providing a cue that high volatility is occurring.
Dynamic Updates and Smoothing
To ensure the visual representation is accurate, the script includes features to manage how swings are displayed:
- Moving Swings: There is an option to allow the "last swing" to move forward if two consecutive bars have the exact same high or low price. This prevents the indicator from creating redundant points at the same price level.
- Visual Buffers: The script maintains internal memory (buffers) of these swings, allowing it to draw lines or arrows on the chart that represent the "active" swing levels versus historical ones.
Summary of User Experience
For a trader using this tool, the logic provides a cleaned-up view of market structure. Instead of seeing every minor price fluctuation, the script filters out the "noise" and highlights:
- The primary highs and lows of the current price action.
- Clear visual cues for trend reversals.
- Identification of volatile "Outside Bars" that may signal a significant shift in market momentum.
//+------------------------------------------------------------------+
//| GannSwings.mq4 |
//| Copyright © 2005, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1 Yellow
#property indicator_color2 Yellow
#property indicator_color3 Blue
#property indicator_color4 Red
#property indicator_color5 Aqua
#property indicator_color6 HotPink
#define version "XV"
extern int kind=1;// òèï òåíäåíöèè, 1- ìàëàÿ, 2 - ïðîìåæóòî÷íàÿ, 3 - îñíîâíàÿ
extern bool ShowHiLo=false;
extern bool ShowOutSideBars=false;
extern bool MoveLastSwing=false; // åñëè ðàâíî true, òî êîí÷èê õâîñòà áóäåò ñäâèãàòüñÿ áëèæå ê íóëåâîìó áàðó äëÿ äâóõ îäèíàêîâûõ áàðîâ ïî High èëè Low
//---- buffers
double HighSwings[];
double LowSwings[];
double HighsBuffer[];
double LowsBuffer[];
double TrendBuffer[];
double UpCloseOutSideBuffers[];
double DownCloseOutSideBuffers[];
double SwingHigh,SwingLow;
int prevSwing,LastSwing,myBars,lowCounter,highCounter , cnt;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(7);
SetIndexStyle(0,DRAW_ZIGZAG);
SetIndexBuffer(0,HighSwings);
SetIndexEmptyValue(0,0.0);
SetIndexLabel(0,"HighSwing");
SetIndexStyle(1,DRAW_ZIGZAG);
SetIndexBuffer(1,LowSwings);
SetIndexEmptyValue(1,0.0);
SetIndexLabel(1,"LowSwing");
SetIndexBuffer(2,HighsBuffer);
SetIndexLabel(2,"HighActive");
SetIndexEmptyValue(2,0.0);
SetIndexBuffer(3,LowsBuffer);
SetIndexLabel(3,"LowActive");
SetIndexEmptyValue(3,0.0);
if (ShowHiLo)
{
SetIndexStyle(2,DRAW_ARROW);
SetIndexArrow(2,159);
SetIndexStyle(3,DRAW_ARROW);
SetIndexArrow(3,159);
}
else
{
SetIndexStyle(2,DRAW_NONE);
SetIndexStyle(3,DRAW_NONE);
}
SetIndexBuffer(4,UpCloseOutSideBuffers);
SetIndexStyle(4,DRAW_ARROW);
SetIndexArrow(4,108);
SetIndexLabel(4,"UpClose");
SetIndexEmptyValue(4,0.0);
SetIndexBuffer(5,DownCloseOutSideBuffers);
SetIndexStyle(5,DRAW_ARROW);
SetIndexArrow(5,108);
SetIndexLabel(5,"DownClose");
SetIndexEmptyValue(5,0.0);
SetIndexBuffer(6,TrendBuffer);
for (int i=Bars-1; i>=0; i--)
{
HighSwings[i]=0.0;
LowSwings[i]=0.0;
HighsBuffer[i]=0.0;
LowsBuffer[i]=0.0;
TrendBuffer[i]=0.0;
UpCloseOutSideBuffers[i]=0.0;
DownCloseOutSideBuffers[i]=0.0;
}
SwingHigh=0.0;
SwingLow=0.0;
prevSwing=0;
LastSwing=0.0;
myBars=0;
lowCounter=0;
highCounter=0;
Comment("\n","GannSwings ",version," kind=",kind);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
Comment("\n","\n"," ");
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
void DownTrendOutSide()
{
//----
//1
if (Close[cnt]<=Open[cnt] && lowCounter==1)
{
SwingHigh=High[cnt];
SwingLow=Low[cnt];
HighSwings[cnt]=High[cnt];
LowSwings[cnt]=Low[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
}
//2
if ( Close[cnt]>Open[cnt] && lowCounter==1)
{
LowSwings[LastSwing]=0.0;
SwingLow=Low[cnt];
SwingHigh=High[cnt];
HighSwings[cnt]=High[cnt];
LowSwings[cnt]=Low[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
TrendBuffer[cnt]=1.0;
//Print("breakout àïòðåíä ÷åðåç âíåøíèé áàð");
}
//3
if (Close[cnt]>Open[cnt] && highCounter==kind)
{
SwingLow=Low[cnt];
SwingHigh=High[cnt];
LowSwings[cnt]=Low[cnt];
HighSwings[cnt]=High[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
TrendBuffer[cnt]=1.0;
//Print("breakout äàóíòðåíä ÷åðåç âíåøíèé áàð");
}
//4
if (Close[cnt]<=Open[cnt] && highCounter==kind)
{
SwingLow=Low[cnt];
SwingHigh=High[cnt];
if (Low[cnt]<LowSwings[LastSwing])
{
LowSwings[LastSwing]=0.0;
LowSwings[cnt]=Low[cnt];
}
HighSwings[cnt]=High[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
//Print("Ðàçâîðîò äàóíòðåíäà ÷åðåç âíåøíèé áàð");
TrendBuffer[cnt]=1.0;
}
//----
return;
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
void UpTrendOutSide()
{
//----
if ( Close[cnt]>=Open[cnt] && highCounter==1)
{
SwingLow=Low[cnt];
SwingHigh=High[cnt];
LowSwings[cnt]=Low[cnt];
HighSwings[cnt]=High[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
//Print("Ïðîäîëæåíèå àïòðåíä ÷åðåç âíåøíèé áàð");
}
if (Close[cnt]< Open[cnt] && highCounter==1)
{
HighSwings[LastSwing]=0.0;
SwingLow=Low[cnt];
SwingHigh=High[cnt];
LowSwings[cnt]=Low[cnt];
HighSwings[cnt]=High[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
TrendBuffer[cnt]=-1.0;
//Print("breakout àïòðåíä ÷åðåç âíåøíèé áàð");
}
if (Close[cnt]>= Open[cnt] && lowCounter==kind)
{
SwingLow=Low[cnt];
SwingHigh=High[cnt];
LowSwings[cnt]=Low[cnt];
HighSwings[cnt]=High[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
TrendBuffer[cnt]=-1.0;
//Print("breakout àïòðåíä ÷åðåç âíåøíèé áàð");
}
// TrendBuffer[cnt+1]==1.0 &&
if (Close[cnt]<Open[cnt] && lowCounter==kind)
{
SwingLow=Low[cnt];
SwingHigh=High[cnt];
if (High[cnt]>HighSwings[LastSwing])
{
HighSwings[LastSwing]=0.0;
HighSwings[cnt]=High[cnt];
}
LowSwings[cnt]=Low[cnt];
highCounter=0;
lowCounter=0;
LastSwing=cnt;
//Print("Ðàçâîðîò àïòðåíäà ÷åðåç âíåøíèé áàð");
TrendBuffer[cnt]=-1.0;
}
//----
return;
}
//+------------------------------------------------------------------+
//| OutSidePart function |
//+------------------------------------------------------------------+
void OutSidePart()
{
//----
if (TrendBuffer[cnt+1]==1.0)
{
UpTrendOutSide();
}//TrendBuffer[cnt+1]==1.0;
else
{// TrendBuffer[cnt+1]==-1.0
DownTrendOutSide();
}//TrendBuffer[cnt+1]==-1.0
//----
return;
}
//+------------------------------------------------------------------+
//| nonOutSidePart() function |
//+------------------------------------------------------------------+
void nonOutSidePart()
{
//----
if (TrendBuffer[cnt+1]==-1.0)
{
if (lowCounter==1)
{
if (LastSwing!=Bars-1) LowSwings[LastSwing]=0.0; // çàòðåì ïðåäûäóùèé ñâèíã
//Print("çàòðåì ïðåäûäóùèé Down ñâèíã");
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
//TrendBuffer[cnt]=-1.0;
highCounter=0;
lowCounter=0;
LowSwings[cnt]=Low[cnt];
HighsBuffer[cnt]=SwingHigh;
//Print("ïðîäîëæåíèå äàóíòðåíäà");
}
else
{
if (highCounter==kind)
{
//if (LastSwing=!cnt)
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
TrendBuffer[cnt]=1.0;
highCounter=0;
lowCounter=0;
HighSwings[cnt]=High[cnt];
LowsBuffer[cnt]=SwingLow;
//Print("ðàçâîðîò äàóíòðåíäà");
}
else
{
if (Low[cnt]==SwingLow && MoveLastSwing)
{
LowSwings[LastSwing]=0.0;
LastSwing=cnt;
LowSwings[cnt]=Low[cnt];
// continue;
}
}
}
}// TrendBuffer[cnt+1]==-1.0
else // TrendBuffer[cnt+1]==1.0
{
if (highCounter==1)
{
if (LastSwing!=Bars-1) HighSwings[LastSwing]=0.0; // çàòðåì ïðåäûäóùèé ñâèíã
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
highCounter=0;
lowCounter=0;
HighSwings[cnt]=High[cnt];
HighsBuffer[cnt]=SwingHigh;
LowsBuffer[cnt]=SwingLow;
//Print("ïðîäîëæåíèå àïòðåíäà");
}
else
{
if (lowCounter==kind)
{
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
TrendBuffer[cnt]=-1.0;
highCounter=0;
lowCounter=0;
LowSwings[cnt]=Low[cnt];
HighsBuffer[cnt]=SwingHigh;
LowsBuffer[cnt]=SwingLow;
//Print("ðàçâîðîò àïòðåíäà");
}
else
{
if (High[cnt]==SwingHigh && MoveLastSwing)
{
HighSwings[LastSwing]=0.0;
LastSwing=cnt;
HighSwings[cnt]=High[cnt];
}
}
}
} //TrendBuffer[cnt+1]==1.0
//----
return;
}
//+------------------------------------------------------------------+
//| return shift of last swing |
//+------------------------------------------------------------------+
int GetLastSwing()
{
//----
int point=1;
while (HighSwings[point]==0.0 && LowSwings[point]==0.0 && point<Bars) point++;
//----
return(point);
}
//+------------------------------------------------------------------+
//| Check prev swing |
//+------------------------------------------------------------------+
void SetPrevSwing()
{
//----
int LastPoint;
LastPoint=GetLastSwing();
HighSwings[0]=0.0;
SwingHigh=High[LastPoint];
SwingLow=Low[LastPoint];
LastSwing=LastPoint;
//----
return;
}
//+------------------------------------------------------------------+
//| check Out side bar |
//+------------------------------------------------------------------+
bool isOutSideSwingBar(int shift)
{
bool res=false;
//----
res=((High[shift]>SwingHigh)&&(Low[shift]<SwingLow));
if (res && ShowOutSideBars)
{
if (Close[shift]>Open[shift]) UpCloseOutSideBuffers[shift]=(High[shift]+Low[shift])/2.0;
else DownCloseOutSideBuffers[shift]=(High[shift]+Low[shift])/2.0;
}
//----
return(res);
}
//+------------------------------------------------------------------+
//| Check new low |
//+------------------------------------------------------------------+
void SetSwings(int shift)
{
//----
//----
return;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars=IndicatorCounted();
int limit;
bool nonOutSide;
if (counted_bars==0)
{
limit=Bars-1;
LowsBuffer[limit]=Low[limit];
LowSwings[limit]=Low[limit];
SwingHigh=High[limit];
SwingLow=Low[limit];
LastSwing=limit;
TrendBuffer[limit]=-1.0;
}
if (counted_bars>0) limit=Bars-counted_bars;
if ( (counted_bars<0)|| ((counted_bars>0)&&(Bars-myBars>1)) ) init();
limit--;
//----
for ( cnt=limit;cnt>0;cnt--)
{
//if (cnt==0) SetPrevSwing();
nonOutSide=!isOutSideSwingBar(cnt);
if (High[cnt]>SwingHigh) {highCounter++;SwingHigh=High[cnt];HighsBuffer[cnt]=SwingHigh;}
if (Low[cnt]<SwingLow) {lowCounter++;SwingLow=Low[cnt];LowsBuffer[cnt]=SwingLow;}
TrendBuffer[cnt]=TrendBuffer[cnt+1];// åñëè íå áóäóò èçìåíåíèé - òðåíä ñîõðàíèòñÿ
if (nonOutSide)
{
nonOutSidePart(); // òóò ìû ðàáîòàåì ñ îáû÷íûìè áàðàìè
}// if (nonOutSide)
else // outSideBars
{
OutSidePart();
}// isOutSideSwingBar(cnt)
} // ÊÎÍÅÖ ÖÈÊËÀ
myBars=Bars;
//----
return(0);
}
//+------------------------------------------------------------------+
Comments