# Institutional Balanced Signal - Design Specification (MT4, priority is given to XAUUSD_2 | Gold EA Download - MetaTrader 4 Resources
// InstitutionalBalanceSignal.mq4 // Institutional-style MT4 indicator (XAUUSD-first) using value-area logic without traditional indicators. // - Data: O/H/L/C, tick volume, spread, time only // - Non-repainting: stamp signals on bar close (index 1) // - Pre-warn on current bar without stamping // - Multi-timeframe gate (default M15) // - Event blackout list #property indicator_chart_window #property indicator_buffers 8 #property indicator_plots 8 #property indicator_label1 "LongSignal" #property indicator_type1 DRAW_ARROW #property indicator_color1 clrLime #property indicator_width1 1 #property indicator_label2 "ShortSignal" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrTomato #property indicator_width2 1 #property indicator_label3 "VAH_fast" #property indicator_type3 DRAW_LINE #property indicator_color3 clrDeepSkyBlue #property indicator_style3 STYLE_DOT #property indicator_label4 "VAL_fast" #property indicator_type4 DRAW_LINE #property indicator_color4 clrDeepSkyBlue #property indicator_style4 STYLE_DOT #property indicator_label5 "POC_fast" #property indicator_type5 DRAW_LINE #property indicator_color5 clrOrange #property indicator_style5 STYLE_DASH #property indicator_label6 "VAH_slow" #property indicator_type6 DRAW_LINE #property indicator_color6 clrSteelBlue #property indicator_style6 STYLE_DASHDOT #property indicator_label7 "VAL_slow" #property indicator_type7 DRAW_LINE #property indicator_color7 clrSteelBlue #property indicator_style7 STYLE_DASHDOT #property indicator_label8 "POC_slow" #property indicator_type8 DRAW_LINE #property indicator_color8 clrSandyBrown #property indicator_style8 STYLE_DASH extern int LookbackMinutes = 480; extern double ValueAreaPercent = 70.0; extern bool AutoBin = true; extern double BinSpreadFactor = 0.5; extern double BinRealizedFactor = 0.15; extern double MinBinUSD = 0.20; extern bool AutoBuffer = true; 1.2; extern double MinBufferUSD = 0.10; extern int ConfirmBars = 5; extern double BreakoutSpeedZ = 1.4; extern double ReversionSpeedZ = 0.8; extern double ImbalanceThreshold = 0.20; extern double SpreadWidenFactor_Breakout = 1.8; extern int SlowTF = PERIOD_M15; extern double ExtremeZFactor = 3.0; extern double extern double MinVAWidthUSD = 1.0; extern double MinVAWidthSpreadMult = 15.0; extern int CooldownBars = 10; extern bool EnableBreakout = true; extern bool EnableReversion = true; extern bool EnablePrewarn = true; double BufLong[]; double BufShort[]; double VAH_fast[]; double VAL_fast[]; double POC_fast[]; double VAH_slow[]; double VAL_slow[]; double POC_slow[]; datetime lastLong=0, lastShort=0; int PeriodSecondsTF(int tf){ switch(tf){ case PERIOD_M1: return 60; case PERIOD_M5: return 300; case PERIOD_M15: return 900; case PERIOD_M30: return 1800; case PERIOD_H1: return 3600; case PERIOD_H4: return 14400; case PERIOD_D1: return 86400; default: return PeriodSeconds(); } } double Clamp(double v,double lo,double hi){ if(v<lo) return lo;
if(v> hi) return hi; return v; } double Median(double &arr[], int n){ if(n<=0) return 0.0; double tmp[]; ArrayResize(tmp,n); for(int i=0;iint k=0; int end=start+count-1; if(end>=Bars) end=Bars-1; for(int i=start;i<=end;i++) tmp[k++]=(double)arr[i]; ArraySort(tmp,WHOLE_ARRAY,0,MODE_ASCEND); if((k%2)==1) return tmp[k/2]; return 0.5*(tmp[k/2-1]+tmp[k/2]); } double MADCloseDiff(const double &close[], int start, int count){ int end=start+count-1; if(end>=Bars-1) end=Bars-2; int n=end-start+1; if(n<3) return 0.0; double d[]; ArrayResize(d,n-1); int k=0; for(int i=start;i <start+n-1;i++) d[k++]=MathAbs(close[i]-close[i+1]);
double med=Median(d,k);
if(med<=0) return 0.0;
for(int j=0;j<k;j++) d[j]=MathAbs(d[j]-med);
double mad=Median(d,k);
return (mad> 0? mad : med); } double TickImbalance(const double &open[], const double &close[], const long &tvol[], int start, int len){ int end=start+len-1; if(end>=Bars) end=Bars-1; long b=0,s=0; for(int i=start;i<=end;i++){ if(close[i]>open[i]) b+=tvol[i]; else if(close[i] <open[i]) s+=tvol[i];
else {
b+=tvol[i]/2;
s+=tvol[i]/2;
}
}
double tot=(double)(b+s);
if(tot<=0) return 0.0;
return (double)(b-s)/tot;
}
bool InSession(datetime t){
int hr=TimeHour(t), mn=TimeMinute(t);
bool in=(hr> =SessionStartHour && hr<=SessionEndHour); bool near=(mn<=NoTradeMinutesAroundHour || mn>=60-NoTradeMinutesAroundHour); if(!in) return false; if(NoTradeMinutesAroundHour>0 && near) return false; return true; } bool InEventBlackout(datetime t){ if(StringLen(EventBlackoutCsv)<=0) return false; string segs[]; int parts=StringSplit(EventBlackoutCsv,';',segs); if(parts<=0) return false; for(int i=0;i <parts;i++){
string seg=Trim(segs[i]);
if(StringLen(seg)==0) continue;
int p=StringFind(seg,"|");
if(p<=0) continue;
string ts=StringSubstr(seg,0,p);
string ms=StringSubstr(seg,p+1);
datetime c=StringToTime(ts);
int rad=(int)StringToInteger(ms);
if(c==0 || rad<=0) continue;
if(MathAbs((int)(t-c))<=rad*60) return true;
}
return false;
}
bool BuildValueAreaFast(const double &high[], const double &low[], const long &tvol[], int startIndex, int barsN,
double pct, double binUsd, double &VAH, double &VAL, double &POC){
if(barsN<10) return false;
int start=startIndex;
int end=startIndex+barsN-1;
if(end> =Bars) end=Bars-1; double lo=1e100, hi=-1e100; for(int i=start;i<=end;i++){ if(low[i]<lo) lo=low[i];
if(high[i]> hi) hi=high[i]; } if(hi<=lo) return false; int bins=(int)MathCeil((hi-lo)/binUsd); bins=MathMax(10,MathMin(bins,2000)); double hist[]; ArrayResize(hist,bins); ArrayInitialize(hist,0.0); for(int j=start;j<=end;j++){ double px=0.5(high[j]+low[j]); int binIdx=(int)MathFloor((px-lo)/binUsd); binIdx=MathMax(0,MathMin(binIdx,bins-1)); double w=(double)tvol[j]; if(w<=0) w=1.0; hist[binIdx]+=w; } double tot=0.0; int poc=0; double pocMass=-1.0; for(int bin=0;bin<bins;bin++){
tot+=hist[bin];
if(hist[bin]> pocMass){ pocMass=hist[bin]; poc=bin; } } if(tot<=0.0) return false; double target=totClamp(pct/100.0,0.10,0.95); int L=poc,R=poc; double acc=hist[poc]; while(acc<target && (L> 0 || R<bins-1)){
double LM=(L> 0)?hist[L-1]:-1.0, RM=(R<bins-1)?hist[R+1]:-1.0;
if(RM> LM){ if(R<bins-1){
R++;
acc+=hist[R];
} else if(L> 0){ L--; acc+=hist[L]; } else break; } else{ if(L>0){ L--; acc+=hist[L]; } else if(R <bins-1){
R++;
acc+=hist[R];
} else break;
}
}
VAL=lo+LbinUsd;
VAH=lo+(R+1)binUsd;
POC=lo+(poc+0.5)*binUsd;
return true;
}
bool BuildValueAreaSlow(int minutes, int tf, double pct, double binUsd, double &VAH, double &VAL, double &POC){
int sec=PeriodSecondsTF(tf);
int need=MathMax(10, minutes60/sec);
int total=iBars(Symbol(),tf);
if(total<=need+1) return false;
int start=1;
int end=start+need-1;
double lo=1e100, hi=-1e100;
for(int i=start;i<=end;i++){
double l=iLow(Symbol(),tf,i), h=iHigh(Symbol(),tf,i);
if(l<lo) lo=l;
if(h> hi) hi=h; } if(hi<=lo) return false; int bins=(int)MathCeil((hi-lo)/binUsd); bins=MathMax(10,MathMin(bins,2000)); double hist[]; ArrayResize(hist,bins); ArrayInitialize(hist,0.0); for(int j=start;j<=end;j++){ double px=0.5(iHigh(Symbol(),tf,j)+iLow(Symbol(),tf,j)); int binIdx=(int)MathFloor((px-lo)/binUsd); binIdx=MathMax(0,MathMin(binIdx,bins-1)); double w=(double)iVolume(Symbol(),tf,j); if(w<=0) w=1.0; hist[binIdx]+=w; } double tot=0.0; int poc=0; double pocMass=-1.0; for(int bin=0;bin<bins;bin++){
tot+=hist[bin];
if(hist[bin]> pocMass){ pocMass=hist[bin]; poc=bin; } } if(tot<=0.0) return false; double target=totClamp(pct/100.0,0.10,0.95); int L=poc,R=poc; double acc=hist[poc]; while(acc<target && (L> 0 || R<bins-1)){
double LM=(L> 0)?hist[L-1]:-1.0, RM=(R<bins-1)?hist[R+1]:-1.0;
if(RM> LM){ if(R<bins-1){
R++;
acc+=hist[R];
} else if(L> 0){ L--; acc+=hist[L]; } else break; } else{ if(L>0){ L--; acc+=hist[L]; } else if(R <bins-1){
R++;
acc+=hist[R];
} else break;
}
}
VAL=lo+LbinUsd;
VAH=lo+(R+1)binUsd;
POC=lo+(poc+0.5)binUsd;
return true;
}
string Trim(const string s){
string t=s;
StringTrimLeft(t);
StringTrimRight(t);
return t;
}
int OnInit(){
IndicatorDigits(Digits);
SetIndexBuffer(0,BufLong); SetIndexEmptyValue(0,EMPTY_VALUE); SetIndexArrow(0,233);
SetIndexBuffer(1,BufShort); SetIndexEmptyValue(1,EMPTY_VALUE); SetIndexArrow(1,234);
SetIndexBuffer(2,VAH_fast); SetIndexEmptyValue(2,EMPTY_VALUE);
SetIndexBuffer(3,VAL_fast); SetIndexEmptyValue(3,EMPTY_VALUE);
SetIndexBuffer(4,POC_fast); SetIndexEmptyValue(4,EMPTY_VALUE);
SetIndexBuffer(5,VAH_slow); SetIndexEmptyValue(5,EMPTY_VALUE);
SetIndexBuffer(6,VAL_slow); SetIndexEmptyValue(6,EMPTY_VALUE);
SetIndexBuffer(7,POC_slow); SetIndexEmptyValue(7,EMPTY_VALUE);
ArraySetAsSeries(BufLong,true); ArraySetAsSeries(BufShort,true);
ArraySetAsSeries(VAH_fast,true); ArraySetAsSeries(VAL_fast,true); ArraySetAsSeries(POC_fast,true);
ArraySetAsSeries(VAH_slow,true); ArraySetAsSeries(VAL_slow,true); ArraySetAsSeries(POC_slow,true);
// Initialize buffers with EMPTY_VALUE to avoid spurious drawings at 0.0
int total = Bars;
ArrayInitialize(BufLong, EMPTY_VALUE);
ArrayInitialize(BufShort, EMPTY_VALUE);
ArrayInitialize(VAH_fast, EMPTY_VALUE);
ArrayInitialize(VAL_fast, EMPTY_VALUE);
ArrayInitialize(POC_fast, EMPTY_VALUE);
ArrayInitialize(VAH_slow, EMPTY_VALUE);
ArrayInitialize(VAL_slow, EMPTY_VALUE);
ArrayInitialize(POC_slow, EMPTY_VALUE);
return(INIT_SUCCEEDED);
}
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(rates_total<200) return 0;
int sec=PeriodSeconds();
int need=MathMax(10, LookbackMinutes60/sec);
if(need> rates_total-2) need=rates_total-2; double spArr[]; ArrayResize(spArr, MathMin(200, rates_total-2)); int k=0; for(int i=1;i<1+ArraySize(spArr);i++) spArr[k++]=(double)spread[i]; double medSpread=Median(spArr,k); if(medSpread<=0) medSpread=(double)spread[1]; double trArr[]; int trN=MathMin(120, rates_total-1); ArrayResize(trArr,trN); k=0; for(int t=1;t<1+trN;t++) trArr[k++]=high[t]-low[t]; double medTR=Median(trArr,k); if(medTR<=0) medTR=high[1]-low[1]; double binUsd=(AutoBin? MathMax(MathMax(BinSpreadFactormedSpreadPoint, BinRealizedFactormedTR), MinBinUSD) : MinBinUSD); double bufferUsd=(AutoBuffer? MathMax(BufferSpreadFactormedSpreadPoint, MinBufferUSD) : MinBufferUSD); double fVAH=0,fVAL=0,fPOC=0; bool okFast=BuildValueAreaFast(high,low,tick_volume,1,need,ValueAreaPercent,binUsd,fVAH,fVAL,fPOC); if(okFast){ VAH_fast[1]=fVAH; VAL_fast[1]=fVAL; POC_fast[1]=fPOC; } else { VAH_fast[1]=EMPTY_VALUE; VAL_fast[1]=EMPTY_VALUE; POC_fast[1]=EMPTY_VALUE; } double sVAH=0,sVAL=0,sPOC=0; bool okSlow=false; if(UseMTFFilter) okSlow=BuildValueAreaSlow(LookbackMinutes,SlowTF,ValueAreaPercent,binUsd,sVAH,sVAL,sPOC); if(okSlow){ VAH_slow[1]=sVAH; VAL_slow[1]=sVAL; POC_slow[1]=sPOC; } else { VAH_slow[1]=EMPTY_VALUE; VAL_slow[1]=EMPTY_VALUE; POC_slow[1]=EMPTY_VALUE; } BufLong[1]=EMPTY_VALUE; BufShort[1]=EMPTY_VALUE; bool inSess=InSession(time[1]); bool inBlk=InEventBlackout(time[1]); if(!inSess || inBlk) return rates_total; double mad=MADCloseDiff(close,1,MathMin(200,rates_total-1)); if(mad<=0) mad=2Point; int back=MathMin(ConfirmBars,rates_total-2); double z=(close[1]-close[1+back])/mad; bool extreme=(MathAbs(z)>=ExtremeZFactor) || ((double)spread[1] >= medSpreadExtremeSpreadFactor); if(!okFast || extreme) return rates_total; double fWidth=fVAH-fVAL; bool tooNarrow=(fWidth < MathMax(MinVAWidthUSD, MinVAWidthSpreadMultmedSpreadPoint)); if(tooNarrow) return rates_total; double imb=TickImbalance(open,close,tick_volume,1,MathMax(3,ConfirmBars)); bool mtfLong=true, mtfShort=true; if(UseMTFFilter && okSlow){ mtfLong=(close[1]>=sPOC); mtfShort=(close[1]<=sPOC); } bool cdLong=(Time[1]-lastLong >= CooldownBarssec); bool cdShort=(Time[1]-lastShort >= CooldownBarssec); if(EnableBreakout){ bool spWide=((double)spread[1] >= medSpreadSpreadWidenFactor_Breakout); if(close[1] > fVAH + bufferUsd && z>BreakoutSpeedZ && imb>ImbalanceThreshold && spWide && mtfLong && cdLong){ BufLong[1]=low[1] - 0.2(high[1]-low[1]); lastLong=Time[1]; } if(close[1] < fVAL - bufferUsd && z<-BreakoutSpeedZ && imb<-ImbalanceThreshold && spWide && mtfShort && cdShort){ BufShort[1]=high[1] + 0.2(high[1]-low[1]); lastShort=Time[1]; } } if(EnableReversion){ bool spNorm=((double)spread[1] <= medSpreadSpreadNormalize_Reversion); bool wasAbove=(close[2]>fVAH), backInFromAbove=(close[1]<fVAH && close[1]> fVAL); bool wasBelow=(close[2]<fVAL), backInFromBelow=(close[1]> fVAL && close[1] <fVAH);
if(wasAbove && backInFromAbove && z<-ReversionSpeedZ && imb<=0.0 && spNorm && mtfShort && cdShort){
BufShort[1]=high[1] + 0.2(high[1]-low[1]);
lastShort=Time[1];
}
if(wasBelow && backInFromBelow && z> ReversionSpeedZ && imb>=0.0 && spNorm && mtfLong && cdLong){ BufLong[1]=low[1] - 0.2(high[1]-low[1]); lastLong=Time[1]; } } if(EnablePrewarn && okFast){ string warn=""; double z0=(close[0]-close[MathMin(ConfirmBars, rates_total-2)])/mad; double imb0=TickImbalance(open,close,tick_volume,0,MathMax(3,ConfirmBars)); bool spWide0=((double)spread[0] >= medSpreadSpreadWidenFactor_Breakout); bool up=(close[0] > fVAH + 0.8bufferUsd); bool dn=(close[0] < fVAL - 0.8bufferUsd); if(up && z0>0.8BreakoutSpeedZ && imb0>0.8ImbalanceThreshold && spWide0 && (!UseMTFFilter || (okSlow && close[0]>=sPOC)) && InSession(time[0]) && !InEventBlackout(time[0])) warn="PREWARN: Breakout LONG"; if(dn && z0<-0.8BreakoutSpeedZ && imb0<-0.8*ImbalanceThreshold && spWide0 && (!UseMTFFilter || (okSlow && close[0]<=sPOC)) && InSession(time[0]) && !InEventBlackout(time[0])) warn=(StringLen(warn)>0? warn+" | ":"")+"PREWARN: Breakout SHORT"; string obj="IBS_PREWARN"; if(StringLen(warn)>0){ if(ObjectFind(0,obj) < 0){ ObjectCreate(0,obj,OBJ_LABEL,0,0,0); ObjectSetInteger(0,obj,OBJPROP_CORNER,CORNER_LEFT_UPPER); ObjectSetInteger(0,obj,OBJPROP_XDISTANCE,8); ObjectSetInteger(0,obj,OBJPROP_YDISTANCE,8); ObjectSetInteger(0,obj,OBJPROP_COLOR,clrGoldenrod); ObjectSetInteger(0,obj,OBJPROP_FONTSIZE,10); } ObjectSetString(0,obj,OBJPROP_TEXT,warn); } else { if(ObjectFind(0,obj) >= 0) ObjectDelete(0,obj); } } return rates_total; }
💡 Featured Recommendations
✍️ Latest by the author
- •
- •
- •
- •
- •
- •
📌 Popular topics
- •
- •
- •
- •
- •
- •
- •
- •
🔗 You May Be Interested In
- •
- •
- •
- •
- •
- •