//+------------------------------------------------------------------+
//| WRB-Hidden-Gap.mq5 |
//| Copyright © 2014, EarnForex.com |
//| http://www.earnforex.com/ |
//+------------------------------------------------------------------+
#property copyright "EarnForex.com"
#property link ""
#property version "1.01"
//---
#property description ""
#property description ""
#property description ""
#property description "by Andriy Moraru."
//---
#property indicator_chart_window
//---
#property indicator_plots 1
#property indicator_buffers 1
//---
#property indicator_type1 DRAW_ARROW
#property indicator_style1 STYLE_SOLID
#property indicator_color1 clrAqua // WRB symbol
#property indicator_width1 1
//---
#define UNFILLED_PREFIX "HG_UNFILLED_"
#define FILLED_PREFIX "HG_FILLED_"
#define PREFIX "HG_"
//---
input bool UseWholeBars=false;
input int WRB_LookBackBarCount= 3;
input int WRB_WingDingsSymbol = 115;
input color HGcolor1 = clrDodgerBlue;
input color HGcolor2 = clrBlue;
input ENUM_LINE_STYLE HGstyle=STYLE_SOLID;
input int StartCalculationFromBar=100;
input bool HollowBoxes=false;
input bool DoAlerts=false;
//---- buffers
double WRB[];
//---
int totalBarCount=-1;
//+------------------------------------------------------------------+
//| Delete all objects with given prefix |
//+------------------------------------------------------------------+
void ObDeleteObjectsByPrefix(string Prefix)
{
int L = StringLen(Prefix);
int i = 0;
while(i<ObjectsTotal(0,-1,OBJ_RECTANGLE))
{
string ObjName=ObjectName(0,i,-1,OBJ_RECTANGLE);
if(StringSubstr(ObjName,0,L)!=Prefix)
{
i++;
continue;
}
ObjectDelete(0,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,const double &High[],const double &Low[],const datetime &Time[],int rates_total)
{
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(0,-1,OBJ_RECTANGLE)) // loop over all unfilled boxes
{
string ObjName=ObjectName(0,i,-1,OBJ_RECTANGLE);
if(StringSubstr(ObjName,0,L)!=Prefix)
{
i++;
continue;
}
box_H=ObjectGetDouble(0,ObjName,OBJPROP_PRICE,0); // get HG high and low values
box_L= ObjectGetDouble(0, ObjName, OBJPROP_PRICE, 1);
objectColor=(color)ObjectGetInteger(0,ObjName,OBJPROP_COLOR);
startTime=(color)ObjectGetInteger(0,ObjName,OBJPROP_TIME,0);
//---
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>=0) && (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(0,ObjName);
ObjectText=FILLED_PREFIX+TimeToString(startTime,TIME_DATE|TIME_MINUTES);
ObjectCreate(0,ObjectText,OBJ_RECTANGLE,0,startTime,box_H,Time[barNumber],box_L);
ObjectSetInteger(0,ObjectText,OBJPROP_STYLE,HGstyle);
ObjectSetInteger(0,ObjectText,OBJPROP_COLOR,objectColor);
ObjectSetInteger(0,ObjectText,OBJPROP_FILL,!HollowBoxes);
break;
}
j++;
}
i++;
}
}
//+------------------------------------------------------------------+
//| checkWRB: Check if the given bar is a WRB or not |
//| The lookback period can be changed by user input |
//| If UseWholeBars = true, High[] and Low[] will be passed |
//| to this function. |
//+------------------------------------------------------------------+
bool checkWRB(int i,const double &Open[],const double &Close[])
{
int j;
bool WRB_test;
double body,bodyPrior;
//---
WRB_test=true;
body=MathAbs(Open[i]-Close[i]);
for(j=1; j<=WRB_LookBackBarCount; j++)
{
bodyPrior=MathAbs(Open[i-j]-Close[i-j]);
if(bodyPrior>body)
{
WRB_test=false;
break;
}
}
//---
if(WRB_test) 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,const double &High[],const double &Low[],const double &Open[],const double &Close[],const datetime &Time[])
{
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(0,-1,OBJ_RECTANGLE)) // loop over all unfilled boxes
{
ObjectText=ObjectName(0,j,-1,OBJ_RECTANGLE);
if(StringSubstr(ObjectText,0,Length)!=UNFILLED_PREFIX)
{
j++;
continue;
}
//--- Switch colors if the new Hidden Gap is intersecting with previous Hidden Gap.
if(intersect(ObjectGetDouble(0,ObjectText,OBJPROP_PRICE),ObjectGetDouble(0,ObjectText,OBJPROP_PRICE,1),A,B)!=0)
{
HGcolor=(color)ObjectGetInteger(0,ObjectText,OBJPROP_COLOR);
if(HGcolor==HGcolor1) HGcolor=HGcolor2;
else HGcolor=HGcolor1;
break;
}
j++;
}
ObjectText=UNFILLED_PREFIX+TimeToString(Time[i-1],TIME_DATE|TIME_MINUTES);
ObjectCreate(0,ObjectText,OBJ_RECTANGLE,0,Time[i-1],A,TimeCurrent()+10*365*24*60*60,B);
ObjectSetInteger(0,ObjectText,OBJPROP_STYLE,HGstyle);
ObjectSetInteger(0,ObjectText,OBJPROP_COLOR,HGcolor);
ObjectSetInteger(0,ObjectText,OBJPROP_FILL,!HollowBoxes);
}
} //End of HG-Test
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CheckAlert()
{
int total=ObjectsTotal(0,-1,OBJ_RECTANGLE);
//--- Loop over all unfilled boxes.
for(int j=0; j<total; j++)
{
string ObjectText=ObjectName(0,j,-1,OBJ_RECTANGLE);
//--- 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(0,ObjectNameWithoutA)>=0) ObjectDelete(0,ObjectNameWithoutA);
continue;
}
int Length=StringLen(UNFILLED_PREFIX);
if(StringSubstr(ObjectText,0,Length)!=UNFILLED_PREFIX) continue;
//---
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double Price1 = ObjectGetDouble(0, ObjectText, OBJPROP_PRICE);
double Price2 = ObjectGetDouble(0, ObjectText, OBJPROP_PRICE, 1);
double High= MathMax(Price1,Price2);
double Low = MathMin(Price1,Price2);
//--- Current price above lower border
if((Ask>Low) && (Bid<High))
{
Alert(Symbol()+": "+"WRB rectangle breached.");
PlaySound("alert.wav");
ObjectSetString(0,ObjectText,OBJPROP_NAME,ObjectText+"A");
return;
}
}
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
SetIndexBuffer(0,WRB,INDICATOR_DATA);
PlotIndexSetInteger(0,PLOT_ARROW,WRB_WingDingsSymbol);
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
PlotIndexSetString(0,PLOT_LABEL,"WRB");
IndicatorSetString(INDICATOR_SHORTNAME,"WRB+HG");
ArrayInitialize(WRB,EMPTY_VALUE);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObDeleteObjectsByPrefix(PREFIX);
}
//+------------------------------------------------------------------+
//| Custom Market Profile main iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &Time[],
const double &Open[],
const double &High[],
const double &Low[],
const double &Close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(DoAlerts) CheckAlert();
//--- A new bar started.
if(totalBarCount!=rates_total)
{
int start=prev_calculated;
start--;
//--- Need at least WRB_LookBackBarCount bars from the end of the chart to work.
if(start<WRB_LookBackBarCount) start=WRB_LookBackBarCount;
//--- Maximum number of bars to calculate is StartCalculationFromBar.
if(start<rates_total-1-StartCalculationFromBar) start=rates_total-1-StartCalculationFromBar;
//---
for(int i=start; i<rates_total-1; i++)
{
if(UseWholeBars)checkWRB(i,High,Low);
else checkWRB(i,Open,Close);
checkHG(i,High,Low,Open,Close,Time);
checkHGFilled(i,High,Low,Time,rates_total);
}
totalBarCount=rates_total;
}
//--- Additional check to see if current bar made the Hidden Gap filled.
checkHGFilled(rates_total-1,High,Low,Time,rates_total);
WRB[rates_total-1]=EMPTY_VALUE;
//---
return(rates_total);
}
//+------------------------------------------------------------------+
Comments