Overview of Logic
This script is designed to identify and visualize significant market turning points, referred to as "swings," on a financial trading chart. Rather than simply plotting every price movement, the logic focuses on identifying structural highs and lows that define the prevailing trend. It categorizes these movements into three types: intermediate, main, and minor swings, allowing users to filter out market noise and focus on the most significant price actions.
Core Operational Logic
1. Trend Identification and Tracking The script continuously monitors the "High" and "Low" prices of each bar. It works by keeping track of whether the current price action is moving upward or downward relative to the last established swing point.
- When the price reaches a new low that meets specific criteria, the script recognizes a continuation of a downward trend.
- When the price reaches a new high that meets certain criteria, it identifies an upward trend.
2. Swing Detection Criteria The script distinguishes between various types of market movements based on how many consecutive "higher highs" or "lower lows" occur:
- Trend Continuation: If the price continues to move in its current direction (e.g., making a new low during a downtrend), the script identifies this as a continuation point.
- Trend Reversal: The script looks for specific thresholds (determined by the user's "kind" setting) to decide when a movement is significant enough to be considered a reversal. For example, if the price reaches a certain number of new highs in a row, it flags a shift from a downtrend to an uptrend.
3. Dynamic Visual Mapping The logic includes a mechanism to keep the chart clean and accurate:
- Point Mapping: It identifies specific coordinates on the chart where these swings occur and places visual markers (arrows or lines) to highlight them for the user.
- Swing Updating: There is a specific feature that allows the script to "move" the last detected swing point if new data comes in that matches the previous peak or trough exactly. This ensures that the most recent structural point stays aligned with the actual price action.
- Outlier Detection: The script includes logic to recognize "Outside Bars"—instances where the current bar's high and low exceed the previous bar's range. It calculates the midpoint of these bars and categorizes them based on whether the candle closed as a bullish (up) or bearish (down) move.
Summary of User Experience
For a trader, this script automates the difficult task of "reading" a chart manually. Instead of guessing where a trend might end, the logic calculates those pivot points mathematically. By filtering out minor fluctuations and highlighting only significant structural breaks, it provides a clearer visual map of the market's skeleton—showing you where the "swings" are happening in real-time.
//+------------------------------------------------------------------+
//| 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 5
#property indicator_color1 White
#property indicator_color2 Blue
#property indicator_color3 Red
#property indicator_color4 Aqua
#property indicator_color5 HotPink
extern int kind=1;// òèï òåíäåíöèè, 1- ìàëàÿ, 2 - ïðîìåæóòî÷íàÿ, 3 - îñíîâíàÿ
extern bool MoveLastSwing=false; // åñëè ðàâíî true, òî êîí÷èê õâîñòà áóäåò ñäâèãàòüñÿ áëèæå ê íóëåâîìó áàðó äëÿ äâóõ îäèíàêîâûõ áàðîâ ïî High èëè Low
//---- buffers
double SwingsBuffer[];
double HighsBuffer[];
double LowsBuffer[];
double TrendBuffer[];
double UpCloseOutSideBuffers[];
double DownCloseOutSideBuffers[];
double SwingHigh,SwingLow;
int prevSwing,LastSwing,myBars,lowCounter,highCounter;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(6);
SetIndexStyle(0,DRAW_SECTION);
SetIndexBuffer(0,SwingsBuffer);
SetIndexEmptyValue(0,0.0);
SetIndexBuffer(1,HighsBuffer);
SetIndexStyle(1,DRAW_ARROW);
SetIndexArrow(1,159);
SetIndexBuffer(2,LowsBuffer);
SetIndexStyle(2,DRAW_ARROW);
SetIndexArrow(2,159);
SetIndexBuffer(3,UpCloseOutSideBuffers);
SetIndexStyle(3,DRAW_ARROW);
SetIndexArrow(3,108);
SetIndexBuffer(4,DownCloseOutSideBuffers);
SetIndexStyle(4,DRAW_ARROW);
SetIndexArrow(4,108);
SetIndexBuffer(5,TrendBuffer);
for (int i=Bars-1; i>=0; i--)
{
SwingsBuffer[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;
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| return shift of last swing |
//+------------------------------------------------------------------+
int GetLastSwing()
{
//----
int point=1;
while (SwingsBuffer[point]==0.0 && point<Bars) point++;
//----
return(point);
}
//+------------------------------------------------------------------+
//| Check prev swing |
//+------------------------------------------------------------------+
void SetPrevSwing()
{
//----
int LastPoint;
LastPoint=GetLastSwing();
SwingsBuffer[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]>High[shift+1])&&(Low[shift]<Low[shift+1]));
if (res)
{
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];
SwingsBuffer[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--;
//Print("Bars=",Bars," counted_bars=",counted_bars,);
//----
for (int cnt=limit;cnt>=0;cnt--)
{
if (limit<3)Print("cnt=",cnt," myBars=",myBars," LastSwing=",LastSwing);
//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;}
//isOutSideSwingBar(cnt);
TrendBuffer[cnt]=TrendBuffer[cnt+1];// åñëè íå áóäóò èçìåíåíèé - òðåíä ñîõðàíèòñÿ
if ((TrendBuffer[cnt+1]==-1.0) && (lowCounter==1))// && nonOutSide)
{
//if (LastSwing=!cnt)
if (LastSwing!=Bars-1) SwingsBuffer[LastSwing]=0.0; // çàòðåì ïðåäûäóùèé ñâèíã
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
//TrendBuffer[cnt]=-1.0;
highCounter=0;
lowCounter=0;
SwingsBuffer[cnt]=Low[cnt];
HighsBuffer[cnt]=SwingHigh;
//Print("ïðîäîëæåíèå äàóíòðåíäà");
}
else
{
if (TrendBuffer[cnt+1]==-1.0 &&highCounter==kind)
{
//if (LastSwing=!cnt)
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
TrendBuffer[cnt]=1.0;
highCounter=0;
lowCounter=0;
SwingsBuffer[cnt]=High[cnt];
LowsBuffer[cnt]=SwingLow;
//Print("ðàçâîðîò äàóíòðåíäà");
}
else
{
if (TrendBuffer[cnt+1]==-1.0 && Low[cnt]==SwingLow && MoveLastSwing)
{
SwingsBuffer[LastSwing]=0.0;
LastSwing=cnt;
/* SwingLow=Low[cnt];
SwingHigh=High[cnt];
highCounter=0;
lowCounter=0;
*/ SwingsBuffer[cnt]=Low[cnt];
}
}
}
if ((TrendBuffer[cnt+1]==1.0) && (highCounter==1))// && nonOutSide)
{
//if (LastSwing=!cnt)
if (LastSwing!=Bars-1) SwingsBuffer[LastSwing]=0.0; // çàòðåì ïðåäûäóùèé ñâèíã
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
//TrendBuffer[cnt]=1.0;
highCounter=0;
lowCounter=0;
SwingsBuffer[cnt]=High[cnt];
LowsBuffer[cnt]=SwingLow;
//Print("ïðîäîëæåíèå àïòðåíäà");
}
else
{
if (TrendBuffer[cnt+1]==1.0 &&lowCounter==kind)
{
//if (LastSwing=!cnt)
LastSwing=cnt;
SwingHigh=High[cnt];
SwingLow=Low[cnt];
TrendBuffer[cnt]=-1.0;
highCounter=0;
lowCounter=0;
SwingsBuffer[cnt]=Low[cnt];
HighsBuffer[cnt]=SwingHigh;
//Print("ðàçâîðîò àïòðåíäà");
}
else
{
if (TrendBuffer[cnt+1]==1.0 && High[cnt]==SwingHigh && MoveLastSwing)
{
SwingsBuffer[LastSwing]=0.0;
LastSwing=cnt;
/* SwingLow=Low[cnt];
SwingHigh=High[cnt];
highCounter=0;
lowCounter=0;
*/ SwingsBuffer[cnt]=High[cnt];
}
}
}
}
myBars=Bars;
//----
return(0);
}
//+------------------------------------------------------------------+
Comments