Why Your EA Keeps Entering Trades Against the Trend
You've backtested your Expert Advisor on the 15-minute chart. The equity curve looks like a staircase going up. But when you let it run live, it hits stop after stop, giving back weeks of gains in three days. Sound familiar?
I've been there. After years of building and breaking EAs for clients and my own accounts, I've learned that the single most common flaw in algorithmic strategies is timeframe blindness. Your EA might have a brilliant entry logic on the M15, but if it's fighting a strong daily downtrend, you're just bleeding money in style.
This post is about timeframe alignment — a systematic way to let higher timeframe structure filter your lower timeframe entries. I'll show you exactly how to implement it in MQL4 and MQL5, with real code and the trade-offs you need to know.
What Is Timeframe Alignment?
Timeframe alignment means using a higher timeframe (HTF) to determine the dominant trend or market regime, then taking entries on a lower timeframe (LTF) only in the direction of that HTF bias. It's not a new idea — discretionary traders have done it for decades. But coding it into an EA requires careful thinking about data handling, lag, and synchronization.
The core concept is simple: don't trade counter-trend on the higher timeframe. If the daily chart is making lower highs and lower lows, you only take short entries on the 15-minute chart. If the 4-hour chart is above its 200 EMA, you only take long entries on the 1-hour chart.
This isn't about predicting reversals. It's about stacking probabilities. A strong daily uptrend means that even mediocre M15 setups have a higher chance of succeeding, because the market is already biased to move up.
Choosing the Right Timeframe Ratio
Not all timeframe combinations work well. Here's what I've found effective after testing hundreds of combinations:
| Entry Timeframe | Filter Timeframe | Ratio | Best Use Case |
|---|---|---|---|
| M15 | H1 | 1:4 | Scalping with trend confirmation |
| M30 | H4 | 1:8 | Intraday swing trading |
| H1 | D1 | 1:24 | Position trading with daily bias |
| H4 | W1 | 1:6 | Swing trading with weekly structure |
The ratio matters. A 1:4 ratio (M15 to H1) gives you four times as many bars on the entry timeframe, which means the filter updates more frequently relative to your entries. A 1:24 ratio (H1 to D1) means the filter changes only once per day, which can cause you to miss early trend shifts. I prefer ratios between 1:4 and 1:8 for most strategies.
Practical MQL4 Implementation
Let's build a simple but effective timeframe filter. We'll use a 200-period Exponential Moving Average (EMA) on the higher timeframe as our trend filter. If price is above the EMA, we only take longs. If below, only shorts.
Here's the core function in MQL4:
//+------------------------------------------------------------------+
//| Check higher timeframe trend bias |
//+------------------------------------------------------------------+
bool IsHTFBullish(ENUM_TIMEFRAMES htFrame)
{
double emaHTF = iMA(_Symbol, htFrame, 200, 0, MODE_EMA, PRICE_CLOSE, 1);
double closeHTF = iClose(_Symbol, htFrame, 1);
if(emaHTF == 0 || closeHTF == 0) return false; // data not ready
return (closeHTF > emaHTF);
}
Now integrate this into your EA's trade signal logic:
//+------------------------------------------------------------------+
//| Main tick function - entry logic |
//+------------------------------------------------------------------+
void OnTick()
{
// Only check for new signals on new bar
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// Get higher timeframe bias
ENUM_TIMEFRAMES filterTF = PERIOD_H1; // filter on H1
bool htfBullish = IsHTFBullish(filterTF);
// Your entry signal logic here (example: RSI crossover)
double rsiCurrent = iRSI(_Symbol, PERIOD_M15, 14, PRICE_CLOSE, 1);
double rsiPrev = iRSI(_Symbol, PERIOD_M15, 14, PRICE_CLOSE, 2);
bool buySignal = (rsiPrev < 30 && rsiCurrent > 30); // RSI oversold bounce
bool sellSignal = (rsiPrev > 70 && rsiCurrent < 70); // RSI overbought drop
// Apply timeframe alignment filter
if(htfBullish && buySignal)
{
// Open buy order
OpenOrder(OP_BUY);
}
else if(!htfBullish && sellSignal)
{
// Open sell order
OpenOrder(OP_SELL);
}
}
Notice what we didn't do: we didn't check if the HTF just turned bullish. That would introduce confirmation lag. Instead, we simply check the current state. This keeps the filter responsive while still blocking counter-trend trades.
Handling Data Synchronization in MQL5
MQL5 requires explicit data copying. Here's the same function adapted:
//+------------------------------------------------------------------+
//| Check higher timeframe trend bias (MQL5 version) |
//+------------------------------------------------------------------+
bool IsHTFBullish(ENUM_TIMEFRAMES htFrame)
{
double emaBuffer[];
double closeBuffer[];
ArraySetAsSeries(emaBuffer, true);
ArraySetAsSeries(closeBuffer, true);
// Copy HTF data
int emaHandle = iMA(_Symbol, htFrame, 200, 0, MODE_EMA, PRICE_CLOSE);
CopyBuffer(emaHandle, 0, 1, 1, emaBuffer);
CopyClose(_Symbol, htFrame, 1, 1, closeBuffer);
if(emaBuffer[0] == 0 || closeBuffer[0] == 0) return false;
return (closeBuffer[0] > emaBuffer[0]);
}
Always check that CopyBuffer and CopyClose return the expected number of elements. In MQL5, uninitialized buffers can silently return zero values, which would break your filter.
Beyond Simple Moving Averages
Using a single EMA is a good starting point, but you can make the filter more robust:
- Multiple EMAs: Require price above both 50 and 200 EMA on the HTF for a bullish bias. This avoids whipsaws during tight consolidations.
- ADX filter: Only trade with the HTF bias when ADX is above 25 (trending). In low ADX environments, disable the filter and trade both directions.
- Market structure: Use a ZigZag indicator on the HTF to identify swing highs and lows. Only go long if the last completed swing was higher than the previous.
- Volume profile: On the HTF, check if price is above the value area high (VAH) for bullish bias, or below value area low (VAL) for bearish.
Here's how to implement an ADX + EMA combined filter:
bool IsHTFTrendingBullish(ENUM_TIMEFRAMES htFrame)
{
double ema200 = iMA(_Symbol, htFrame, 200, 0, MODE_EMA, PRICE_CLOSE, 1);
double close = iClose(_Symbol, htFrame, 1);
double adxMain[];
ArraySetAsSeries(adxMain, true);
int adxHandle = iADX(_Symbol, htFrame, 14);
CopyBuffer(adxHandle, 0, 1, 1, adxMain);
bool aboveEMA = (close > ema200);
bool trending = (adxMain[0] > 25);
return (aboveEMA && trending);
}
Pros, Cons, and Risks
Let's be honest about what timeframe alignment can and cannot do:
Advantages
- Higher win rate: By removing counter-trend trades, your EA will have fewer losing streaks. This improves psychological comfort and reduces drawdown.
- Better risk-adjusted returns: The Sharpe ratio of your strategy typically improves because you're not fighting the dominant force.
- Fewer false breakouts: Many false breakouts on lower timeframes occur because the HTF trend is against the breakout direction.
- Simpler optimization: You reduce the parameter space because the filter is independent of your entry logic.
Disadvantages
- Fewer trades: You'll skip potentially profitable counter-trend moves. In ranging markets, this can mean long periods of inactivity.
- Lag in trend changes: When the HTF trend reverses, your EA will continue trading in the old direction for a while, taking losses.
- Curve-fitting risk: It's tempting to optimize the HTF indicator parameters to fit past data. This is a form of overfitting.
- Data dependency: In MQL4, you need sufficient history on the HTF. On a new symbol or after a broker change, the HTF data may not be available.
Critical Risk to Understand
The biggest risk is trend exhaustion. A strong HTF trend that has been running for months is more likely to reverse than continue. Your timeframe alignment filter will keep you in trades right until the trend breaks, often catching the worst part of the reversal. To mitigate this, I recommend adding a volatility filter that reduces position size when HTF volatility expands beyond a certain threshold (e.g., ATR on HTF above its 20-period moving average).
Walkthrough: Building a Complete Filter
Let's walk through a real scenario. You have an EA that trades M15 breakouts of a 20-period Bollinger Band. Without a filter, it gets chopped up in ranging markets. Here's how to add timeframe alignment:
- Choose the filter timeframe: For M15 entries, H1 is a good filter. It's close enough to react to intraday shifts but high enough to filter noise.
- Select the filter indicator: Use the 50-period Simple Moving Average (SMA) on H1. Why SMA instead of EMA? Because SMA is slower to react, which is actually beneficial for a filter — you want to avoid reacting to every H1 wiggle.
- Define the bias: Bullish when H1 close is above H1 SMA50. Bearish when below.
- Combine with entry: Only take long breakouts when H1 is bullish. Only take short breakouts when H1 is bearish. In a flat H1 (price oscillating around SMA50), disable the filter and trade both directions with reduced lot size.
- Add a cooldown: After the HTF bias changes (e.g., H1 just crossed below SMA50), wait for 3 H1 bars before taking any short trades. This avoids the whip at the crossover point.
Here's the cooldown logic in code:
datetime lastBiasChange = 0;
bool prevHTFBullish = false;
bool IsCooldownOver(ENUM_TIMEFRAMES htFrame)
{
bool currentBullish = IsHTFBullish(htFrame);
if(currentBullish != prevHTFBullish)
{
lastBiasChange = TimeCurrent();
prevHTFBullish = currentBullish;
}
// Wait for 3 periods of the filter timeframe
int secondsPerBar = PeriodSeconds(htFrame);
return (TimeCurrent() - lastBiasChange >= 3 * secondsPerBar);





