Summary: Advanced guide to detecting and removing future functions in MQL4 EAs. Covers Volume[0] misuse, iCustom forward-peeking, Time[0] trap, and bar shifting techniques with fix code.




Future functions are the number one killer of EA backtest reliability. A single look-ahead bias can turn a losing strategy into a “profitable” one in MT4 strategy tester. Detecting and eliminating these requires systematic code auditing.

1. The Volume[0] Trap

The most common future function in MQL4 is accessing `Volume[0]` or `Volume[1]` on the current incomplete bar.

```cpp
// DANGEROUS - contains future information
double currentVolume = Volume[0]; // This tick count can change as the bar develops
double futureBias = (Volume[0] > Volume[1]) ? 1 : 0; // Decision based on incomplete data

// FIXED - wait for bar close
double safeVolume = Volume[1]; // Only use closed bar data
bool barJustClosed = (Volume[1] > Volume[2]); // Compare completed bars
```

2. Time[0] And Open[0] Illegal Usage

Using `Time[0]` for decision-making creates forward-looking logic.

```cpp
// DANGEROUS - enters trade based on current bar's open time
if(Time[0] - lastTradeTime > Period() * 60) {
OpenTrade(); // This check can trigger multiple times on same bar
}

// FIXED - use bar shift + bar opening detection
static datetime lastBarTime = 0;
if(Time[0] != lastBarTime) {
lastBarTime = Time[0];
// New bar has just formed, safe to evaluate
if(Time[1] - lastTradeTime > Period() * 60) {
OpenTrade();
}
}
```

3. iCustom Function Peek Forward

Custom indicators with `iCustom()` often peek into future if not properly constructed.

```cpp
// DANGEROUS - custom indicator may use future bars internally
double futureSignal = iCustom(Symbol(), 0, "MyIndicator", 0, 0); // buffer 0 at current bar

// FIXED - shift by 1, or better, use indicator that only references lower indexes
double safeSignal = iCustom(Symbol(), 0, "MyIndicator", 0, 1); // use previous bar only

// Helper function to validate indicator
bool IsIndicatorFutureSafe(string indicatorName) {
// Load indicator and check if it references bar indexes < 0
// Properly written indicators should only use indexes >= shift parameter
return true; // Placeholder - actual validation requires source inspection
}
```

4. Comprehensive Future Function Detection Checklist

Add this diagnostic to your EA for systematic detection:

```cpp
void DetectFutureFunctionRisks() {
Print("=== Future Function Audit ===");

// Check 1: Volume array access
if(ArraySize(Volume) > 0) {
Print("WARNING: Volume[] used. Ensure never using Volume[0] for decisions");
}

// Check 2: Time array index 0
Print("Time[0] usage: ", (Time[0] > 0) ? "present - verify bar close check exists" : "not used");

// Check 3: iCustom without shift offset
// Manual code review required for this

// Check 4: MarketInfo MODE_ASK/MODE_BID on current tick
Print("Real-time prices: " + string(Ask) + "/" + string(Bid) + " - ensure backtest mode uses Open prices");
}
```

5. Bar Shifting Pattern For Accurate Backtest

The industry standard to eliminate future bias:

```cpp
// Use this pattern throughout your EA
int GetSafeShift(int desiredShift) {
// Shift 0 = current forming bar (DANGEROUS)
// Shift 1 = last completed bar (SAFE for entry decisions)
return MathMax(desiredShift, 1); // Never return 0 for decision logic
}

// Standardized open price access
double GetSafeOpen(int shift) {
shift = GetSafeShift(shift);
return Open[shift];
}

// Entry signal - only use closed bar data
bool GetEntrySignal() {
double prevRSI = iRSI(NULL, 0, 14, PRICE_CLOSE, 2); // two bars ago
double currRSI = iRSI(NULL, 0, 14, PRICE_CLOSE, 1); // last completed bar

// Decision based on completed bars only
if(prevRSI < 30 && currRSI > 30) {
return true; // Oversold reversal confirmed on closed bar
}
return false;
}
```

6. Backtest Mode Detection For Hybrid Safety

For EAs that need both realtime and backtest accuracy:

```cpp
bool IsRealtimeMode() {
return !IsTesting() && !IsOptimization();
}

double GetExecutionPrice() {
if(IsRealtimeMode()) {
return Ask; // Use real market price in live
} else {
// In backtest, use next bar's open to simulate realistic execution
return Open[1]; // After bar confirmation
}
}

// Complete backtest-safe order function
int BacktestSafeOrderSend(int cmd, double volume) {
double price;
if(cmd == OP_BUY) {
price = IsRealtimeMode() ? Ask : Open[1];
} else {
price = IsRealtimeMode() ? Bid : Open[1];
}

return OrderSend(Symbol(), cmd, volume, price, 3, 0, 0, "SafeEA", magic, 0, clrNONE);
}
```

Reference: MQL4 Community, “Avoiding Future Functions in Backtesting” (mql4.com/articles/backtest); Pardo, Robert. “The Evaluation and Optimization of Trading Strategies” (2008).