MT4 handles asynchronous data poorly compared to MT5, and iBarShift can easily return -1 if history is missing. This version implements strict error checking to prevent array crashes.
Code: Select all
//+------------------------------------------------------------------+
//| PRO_HTF_Regime_Bias.mq4 |
//+------------------------------------------------------------------+
#property strict
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 1
#property indicator_buffers 4
#property indicator_color1 clrTeal // Bullish
#property indicator_color2 clrMaroon // Bearish
#property indicator_color3 clrGray // Chop
#property indicator_color4 clrGoldenrod // Exhausted
#property indicator_width1 4
#property indicator_width2 4
#property indicator_width3 4
#property indicator_width4 4
extern int InpHTF = PERIOD_D1; // Higher Timeframe
extern int InpMAType = MODE_EMA; // MA Type (0=SMA, 1=EMA, 2=SMMA, 3=LWMA)
extern int InpMAPeriod = 20; // MA Period
extern int InpATRPeriod = 14; // ATR Period
extern double InpATRNeutral = 0.5; // Chop Zone Multiplier
extern double InpATRExhaustion = 2.5; // Exhaustion Multiplier
double BullBuffer[], BearBuffer[], ChopBuffer[], ExhaustBuffer[];
int OnInit() {
SetIndexStyle(0, DRAW_HISTOGRAM); SetIndexBuffer(0, BullBuffer);
SetIndexStyle(1, DRAW_HISTOGRAM); SetIndexBuffer(1, BearBuffer);
SetIndexStyle(2, DRAW_HISTOGRAM); SetIndexBuffer(2, ChopBuffer);
SetIndexStyle(3, DRAW_HISTOGRAM); SetIndexBuffer(3, ExhaustBuffer);
IndicatorShortName("Pro Regime Bias");
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[]) {
// MT4 Data Check: Ensure HTF data exists
if(iBars(Symbol(), InpHTF) < InpMAPeriod + InpATRPeriod) {
return 0; // Wait for history download
}
int limit = rates_total - prev_calculated;
if (prev_calculated == 0) limit = rates_total - 1;
for (int i = limit; i >= 0; i--) {
int htf_shift = iBarShift(Symbol(), InpHTF, time[i], false);
// Failsafe: if MT4 returns -1 for a missing historical bar, skip
if(htf_shift < 0) continue;
int target_shift = htf_shift + 1;
double htf_c = iClose(Symbol(), InpHTF, target_shift);
double htf_ma = iMA(Symbol(), InpHTF, InpMAPeriod, 0, InpMAType, PRICE_CLOSE, target_shift);
double htf_atr = iATR(Symbol(), InpHTF, InpATRPeriod, target_shift);
// Clear buffers on this index
BullBuffer[i] = 0; BearBuffer[i] = 0;
ChopBuffer[i] = 0; ExhaustBuffer[i] = 0;
// Failsafe against empty ATR/MA values during early history loading
if(htf_ma == 0 || htf_atr == 0) continue;
double upper_chop = htf_ma + (htf_atr * InpATRNeutral);
double lower_chop = htf_ma - (htf_atr * InpATRNeutral);
double upper_exhaust = htf_ma + (htf_atr * InpATRExhaustion);
double lower_exhaust = htf_ma - (htf_atr * InpATRExhaustion);
if (htf_c > upper_exhaust || htf_c < lower_exhaust) {
ExhaustBuffer[i] = 1.0;
} else if (htf_c > upper_chop) {
BullBuffer[i] = 1.0;
} else if (htf_c < lower_chop) {
BearBuffer[i] = 1.0;
} else {
ChopBuffer[i] = 1.0;
}
}
return(rates_total);
}