wrb-hidden-gap
Download scriptThis script is designed to help traders identify specific price action structures on a chart—specifically Wide Range Bars (WRB) and Hidden Gaps (HG). It automates the visual identification of these patterns, marking them on the chart with symbols and boxes to highlight potential areas of market interest.
Core Functionality
The logic operates through three primary screening processes:
1. Identifying Wide Range Bars (WRB)
The script scans historical price data to find "Wide Range Bars." A bar is flagged as a WRB if its size (the distance between its high and low or open and close prices, depending on user settings) is larger than the preceding bars in a set look-back period. When a WRB is identified, the script places a specific visual symbol on the chart to mark it.
2. Detecting Hidden Gaps (HG)
The script looks for "Hidden Gaps," which occur when there is a structural break between two price movements that hasn't been bridged by actual price gaps.
- The Logic: It checks if a bar qualifies as a Wide Range Bar and then compares the current bar's price range with the previous bar's range.
- Visual Representation: If a gap is detected, the script draws a rectangle (a "box") on the chart. These boxes represent the price zone that constitutes the hidden gap.
- Dynamic Coloring: The script includes a smart coloring system; if a new hidden gap overlaps with an existing one, it automatically alternates colors to ensure visual clarity for the trader.
3. Tracking "Filled" Gaps
One of the most important features of this logic is its ability to track whether a Hidden Gap has been "filled" by subsequent price action.
- Continuous Monitoring: The script constantly monitors the current price movement against all currently active (unfilled) hidden gap boxes.
- Status Update: If the market price moves into and completely covers the price range of a hidden gap box, the script recognizes that the gap is "filled." It then updates the visual on the chart—changing its style or prefix—to signal to the trader that the specific gap zone is no longer active.
User Notifications and Alerts
Beyond just drawing shapes on the chart, the script includes an active monitoring system:
- Breach Alerts: If the user enables alerts, the script will monitor the current live price against all unfilled hidden gap boxes.
- Real-time Interaction: If the current market price "breaches" (enters) a hidden gap zone, the script triggers an audible sound and a visual alert on the platform. This serves as a real-time notification that price has entered a specific area of interest identified by the WRB/HG logic.
Summary for the Trader
Essentially, this tool cleans up "market noise" by highlighting where significant expansion (WRBs) occurs and where structural imbalances (Hidden Gaps) remain open. It provides a visual map of the market's history, showing which gaps have been cleared by price and which are still waiting to be tested, while providing live notifications when the market interacts with those unfinished areas.
//+------------------------------------------------------------------+
//| WRB-Hidden-Gap.mq4 |
//| Copyright © 2010, Akif TOKUZ |
//| akifusenet@gmail.com |
//| Identifies Wide Range Bars and Hidden Gaps. |
//| WRB and HG definitions are taken from the WRB Analysis Tutorial-1|
//| by M.A.Perry from TheStrategyLab.com |
//| |
//| History: |
//| 09.04.2014: Alerts and optimization. |
//| 06.04.2010: Correction to make sure Hidden Gaps are not filled |
//| with real gaps. |
//| 03.04.2010: Initial release |
//| |
//+------------------------------------------------------------------+
#property copyright "Akif TOKUZ and EarnForex.com"
#property link ""
#property version "1.0"
#property strict
//----
#property description "."
#property description ""
#property description ""
#property description "Alerts and optimization by Andriy Moraru."
//----
#property indicator_chart_window
#property indicator_buffers 1
//----
#property indicator_color1 clrAqua // WRB symbol
#property indicator_width1 1
//----
#define UNFILLED_PREFIX "HG_UNFILLED_"
#define FILLED_PREFIX "HG_FILLED_"
#define PREFIX "HG_"
//----
extern bool UseWholeBars=false;
extern int WRB_LookBackBarCount= 3;
extern int WRB_WingDingsSymbol = 115;
extern color HGcolor1 = clrDodgerBlue;
extern color HGcolor2 = clrBlue;
extern ENUM_LINE_STYLE HGstyle=STYLE_SOLID;
extern int StartCalculationFromBar=100;
extern bool HollowBoxes=false;
extern bool DoAlerts=false;
//---- buffers
double WRB[];
//----
int totalBarCount=-1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(1);
IndicatorShortName("WRB+HG");
//----
SetIndexStyle(0,DRAW_ARROW);
SetIndexArrow(0,WRB_WingDingsSymbol);
SetIndexLabel(0,"WRB");
SetIndexBuffer(0,WRB);
ArrayInitialize(WRB,EMPTY_VALUE);
return(0);
}
//+------------------------------------------------------------------+
//| Delete all objects with given prefix |
//+------------------------------------------------------------------+
void ObDeleteObjectsByPrefix(string Prefix)
{
int L = StringLen(Prefix);
int i = 0;
while(i<ObjectsTotal())
{
string ObjName=ObjectName(i);
if(StringSubstr(ObjName,0,L)!=Prefix)
{
i++;
continue;
}
ObjectDelete(ObjName);
}
}
//+------------------------------------------------------------------+
//| intersect: Check two bars intersect or not |
//+------------------------------------------------------------------+
int intersect(double H1,double L1,double H2,double L2)
{
if( (L1>H2) || (H1<L2) ) return (0);
if( (H1>=H2) && (L1>=L2) ) return (1);
if( (H1<=H2) && (L1<=L2) ) return (2);
if( (H1>=H2) && (L1<=L2) ) return (3);
if( (H1<=H2) && (L1>=L2) ) return (4);
return(0);
}
//+------------------------------------------------------------------+
//| checkHGFilled: Check if the hidden gap is filled or not |
//+------------------------------------------------------------------+
void checkHGFilled(int barNumber)
{
int j,i;
string ObjectText;
string Prefix=UNFILLED_PREFIX;
double box_H,box_L;
double HGFillPA_H,HGFillPA_L;
datetime startTime;
color objectColor;
//----
int L=StringLen(Prefix);
i=0;
while(i<ObjectsTotal()) // loop over all unfilled boxes
{
string ObjName=ObjectName(i);
if(StringSubstr(ObjName,0,L)!=Prefix)
{
i++;
continue;
}
box_H=ObjectGet(ObjName,OBJPROP_PRICE1); // get HG high and low values
box_L=ObjectGet(ObjName, OBJPROP_PRICE2);
objectColor=(color)ObjectGet(ObjName,OBJPROP_COLOR);
startTime=(color)ObjectGet(ObjName,OBJPROP_TIME1);
//----
HGFillPA_H = High[barNumber];
HGFillPA_L = Low[barNumber];
j=0;
while((intersect(High[barNumber+j],Low[barNumber+j],box_H,box_L)!=0) && (barNumber+j<Bars) && (startTime<Time[barNumber+j]))
{
if(High[barNumber+j] > HGFillPA_H) HGFillPA_H = High[barNumber+j];
if(Low[barNumber+j] < HGFillPA_L) HGFillPA_L = Low[barNumber+j];
if((HGFillPA_H>box_H) && (HGFillPA_L<box_L))
{
ObjectDelete(ObjName);
ObjectText=FILLED_PREFIX+TimeToStr(startTime,TIME_DATE|TIME_MINUTES);
ObjectCreate(ObjectText,OBJ_RECTANGLE,0,startTime,box_H,Time[barNumber],box_L);
ObjectSet(ObjectText,OBJPROP_STYLE,HGstyle);
ObjectSet(ObjectText,OBJPROP_COLOR,objectColor);
ObjectSet(ObjectText,OBJPROP_BACK,!HollowBoxes);
break;
}
j++;
}
i++;
}
}
//+------------------------------------------------------------------+
//| checkWRB: Check if the given bar is a WRB or not |
//| The lookback period can be changed by user input |
//+------------------------------------------------------------------+
bool checkWRB(int i)
{
int j;
bool WRB_test;
double body,bodyPrior;
//----
WRB_test=true;
if(UseWholeBars) body=High[i]-Low[i];
else body=MathAbs(Open[i]-Close[i]);
for(j=1;j<=WRB_LookBackBarCount; j++)
{
if(UseWholeBars) bodyPrior=High[i+j]-Low[i+j];
else bodyPrior=MathAbs(Open[i+j]-Close[i+j]);
if(bodyPrior>body)
{
WRB_test=false;
break;
}
}
//----
if(WRB_test)
{
if(UseWholeBars) WRB[i]=(High[i]+Low[i])/2;
else WRB[i]=(Open[i]+Close[i])/2;
}
else WRB[i]=EMPTY_VALUE;
//----
return(WRB_test);
}
//+------------------------------------------------------------------+
//| checkHG: Checks HG status of the previous bar. |
//+------------------------------------------------------------------+
void checkHG(int i)
{
string ObjectText;
double H,L,H2,L2,H1,L1,A,B;
int j;
color HGcolor=HGcolor1;
//---- HG-TEST ( test the previous bar i+1)
if(WRB[i+1]!=EMPTY_VALUE) // First rule to become a HG is to become a WRB
{
H2 = High[i+2];
L2 = Low[i+2];
H1 = High[i];
L1 = Low[i];
//----
if(UseWholeBars)
{
H = High[i + 1];
L = Low[i + 1];
}
else if(Open[i+1]>Close[i+1])
{
H = Open[i+1];
L = Close[i+1];
}
else
{
H = Close[i+1];
L = Open[i+1];
}
//---- Older bar higher than the newer.
if(L2>H1)
{
A = MathMin(L2, H);
B = MathMax(H1, L);
}
else if(L1>H2)
{
A = MathMin(L1, H);
B = MathMax(H2, L);
}
else return;
//----
if(A>B)
{
int Length=StringLen(UNFILLED_PREFIX);
j=0;
while(j<ObjectsTotal()) // loop over all unfilled boxes
{
ObjectText=ObjectName(j);
if(StringSubstr(ObjectText,0,Length)!=UNFILLED_PREFIX)
{
j++;
continue;
}
//---- Switch colors if the new Hidden Gap is intersecting with previous Hidden Gap.
if(intersect(ObjectGet(ObjectText,OBJPROP_PRICE1),ObjectGet(ObjectText,OBJPROP_PRICE2),A,B)!=0)
{
HGcolor=(color)ObjectGet(ObjectText,OBJPROP_COLOR);
if(HGcolor==HGcolor1) HGcolor=HGcolor2;
else HGcolor=HGcolor1;
break;
}
j++;
}
//----
ObjectText=UNFILLED_PREFIX+TimeToStr(Time[i+1],TIME_DATE|TIME_MINUTES);
ObjectCreate(ObjectText,OBJ_RECTANGLE,0,Time[i+1],A,TimeCurrent()+10*365*24*60*60,B);
ObjectSet(ObjectText,OBJPROP_STYLE,HGstyle);
ObjectSet(ObjectText,OBJPROP_COLOR,HGcolor);
ObjectSet(ObjectText,OBJPROP_BACK,!HollowBoxes);
}
} //End of HG-Test
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
ObDeleteObjectsByPrefix(PREFIX);
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
void start()
{
if(DoAlerts) CheckAlert();
//---- A new bar started.
if(totalBarCount!=Bars)
{
int begin=Bars-IndicatorCounted();
//---- Need at least WRB_LookBackBarCount bars from the end of the chart to work.
if(begin>Bars-WRB_LookBackBarCount) begin=Bars-WRB_LookBackBarCount;
//---- Maximum number of bars to calculate is StartCalculationFromBar.
if(begin>StartCalculationFromBar) begin=StartCalculationFromBar;
//----
for(int i=begin; i>0; i--)
{
checkWRB(i);
checkHG(i);
checkHGFilled(i);
}
totalBarCount=Bars;
}
//---- Additional check to see if current bar made the Hidden Gap filled.
checkHGFilled(0);
WRB[0]=EMPTY_VALUE;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CheckAlert()
{
int total=ObjectsTotal();
//---- Loop over all unfilled boxes.
for(int j=0; j<total; j++)
{
string ObjectText=ObjectName(j);
//---- Object marked as alerted.
if(StringSubstr(ObjectText,StringLen(ObjectText)-1,1)=="A")
{
//---- Try to find a dupe object (could be result of a bug) and delete it.
string ObjectNameWithoutA=StringSubstr(ObjectText,0,StringLen(ObjectText)-1);
if(ObjectFind(ObjectNameWithoutA)>=0) ObjectDelete(ObjectNameWithoutA);
continue;
}
int Length=StringLen(UNFILLED_PREFIX);
if(StringSubstr(ObjectText,0,Length)!=UNFILLED_PREFIX) continue;
//----
double Price1 = ObjectGet(ObjectText, OBJPROP_PRICE1);
double Price2 = ObjectGet(ObjectText, OBJPROP_PRICE2);
double bHigh= MathMax(Price1,Price2);
double bLow = MathMin(Price1,Price2);
//---- Current price above lower border
if((Ask>bLow) && (Bid<bHigh))
{
Alert(Symbol()+": "+"WRB rectangle breached.");
PlaySound("alert.wav");
ObjectSetString(0,ObjectText,OBJPROP_NAME,ObjectText+"A");
return;
}
}
}
//+------------------------------------------------------------------+
Comments