Why Your Supertrend EA Keeps Losing in Ranges
You've backtested a Supertrend-based EA on EURUSD H1. The equity curve looks like a ski slope — smooth upward glide. Then you run it forward on demo, and within a week it's given back three months of paper profits. Sound familiar?
The Supertrend indicator is a fantastic trend-following tool when markets trend. But it's brutal in ranges. Every flip of the Supertrend line in a sideways market is a false signal, and your EA dutifully takes it. The problem isn't the indicator — it's that you're using a single timeframe. A flip on M15 might mean nothing if H4 is still flat. A flip on H1 might be noise if D1 is strongly trending.
I've been coding MQL4 EAs for over seven years, and the single biggest improvement I've made to trend-following robots is adding a multi-timeframe Supertrend filter. It's not a magic bullet, but it cuts false signals by 40-60% in ranging markets without missing major trends. Let me show you exactly how to implement it.
How a Multi-Timeframe Supertrend Filter Works
The core idea is simple: before your EA takes a trade on its execution timeframe (say M15), it checks the Supertrend direction on a higher timeframe (say H1 or H4). If both timeframes agree on the trend direction, the trade is valid. If they disagree, the EA sits on its hands.
Why does this work? Because higher timeframes filter out the noise. A Supertrend flip on M15 might be a 20-pip retracement. The same flip on H4 requires a 150-pip move. When H4 Supertrend is green (uptrend) and M15 flips red, that's often a pullback within the larger uptrend — a perfect entry for a trend continuation, not a reversal signal.
The filter has two modes I've used in production:
- Strict mode: Only trade when both timeframes show the same Supertrend direction. This is for choppy markets.
- Relaxed mode: Trade in the direction of the higher timeframe Supertrend, even if the lower timeframe just flipped. This catches early entries in strong trends.
I prefer strict mode by default. You can always relax it if your backtest shows you're missing too many trades. But here's the thing: most traders go straight to relaxed mode because they're afraid of missing out. That's the wrong instinct. Missing a trade is better than taking a bad one.
Choosing Timeframe Pairs That Actually Work
Not all pairs of timeframes work well together. From my testing, the multiplier between timeframes should be at least 4x to 6x. Here's what I've found practical:
| Execution TF | Filter TF | Multiplier | Best For |
|---|---|---|---|
| M15 | H1 | 4x | Scalping on EURUSD, GBPUSD |
| M30 | H4 | 8x | Swing trading indices, gold |
| H1 | D1 | 24x | Position trading on majors |
| H4 | W1 | 42x | Long-term trend following |
Notice I don't recommend M5 with H1 (12x) — too wide a gap causes you to miss too many entries. And M15 with M30 (2x) is too close — both timeframes see the same noise. Stick to 4x-8x for most pairs. I've also tested M1 with M15 (15x) and found it unreliable for anything except very liquid pairs like EURUSD during London session.
MQL4 Implementation: The Code
Let's get our hands dirty. I'll show you the core function you need to add to any existing Supertrend EA. This assumes you already have a Supertrend indicator file (Supertrend.ex4 or Supertrend_v1.ex4) in your Indicators folder. If not, download one from the MQL4 code base — the standard one with ATR multiplier works fine.
Here's the filter function I use in all my trend EAs:
//+------------------------------------------------------------------+
//| Check multi-timeframe Supertrend alignment |
//+------------------------------------------------------------------+
bool IsMultiTFSuperTrendAligned(int tf_execution, int tf_filter,
int atr_period, double multiplier)
{
// Get Supertrend values from both timeframes
double st_execution = iCustom(NULL, tf_execution, "Supertrend",
atr_period, multiplier, 0, 1);
double st_filter = iCustom(NULL, tf_filter, "Supertrend",
atr_period, multiplier, 0, 1);
// Supertrend returns a positive value for uptrend (green),
// negative for downtrend (red). Check alignment.
if(st_execution > 0 && st_filter > 0)
return true; // Both uptrend
if(st_execution < 0 && st_filter < 0)
return true; // Both downtrend
return false; // Misaligned — no trade
}
Wait — there's a subtle bug here. The iCustom call with 0, 1 gets the value from the first buffer, bar index 1 (the previous completed bar). But most Supertrend indicators use two buffers: buffer 0 for the uptrend line (positive values) and buffer 1 for the downtrend line (negative values). Some use a single buffer where positive = uptrend, negative = downtrend. You need to check which version you have.
Here's a more robust version that handles both cases:
//+------------------------------------------------------------------+
//| Robust multi-timeframe Supertrend alignment check |
//+------------------------------------------------------------------+
bool IsMultiTFSuperTrendAligned(int tf_execution, int tf_filter,
int atr_period, double multiplier)
{
double st_exec_up = iCustom(NULL, tf_execution, "Supertrend",
atr_period, multiplier, 0, 1);
double st_exec_down = iCustom(NULL, tf_execution, "Supertrend",
atr_period, multiplier, 1, 1);
double st_filt_up = iCustom(NULL, tf_filter, "Supertrend",
atr_period, multiplier, 0, 1);
double st_filt_down = iCustom(NULL, tf_filter, "Supertrend",
atr_period, multiplier, 1, 1);
// Determine trend direction on each timeframe
bool exec_uptrend = (st_exec_up != EMPTY_VALUE);
bool exec_dntrend = (st_exec_down != EMPTY_VALUE);
bool filt_uptrend = (st_filt_up != EMPTY_VALUE);
bool filt_dntrend = (st_filt_down != EMPTY_VALUE);
// Both timeframes must agree
if((exec_uptrend && filt_uptrend) || (exec_dntrend && filt_dntrend))
return true;
return false;
}
I've seen too many EAs fail because they assumed buffer 0 always holds the active trend value. Always check both buffers against EMPTY_VALUE — that's the standard way Supertrend marks empty bars. If you're not sure which buffer holds what, open the indicator in MetaEditor and check the SetIndexBuffer calls at the top.
Integrating Into Your EA's Trade Logic
You don't need to rewrite your EA. Just add the filter check before your entry conditions. Here's a typical snippet from an OnTick() function:
void OnTick()
{
// Only check on new bar
if(Volume[0] > 1) return;
// Your existing Supertrend signal on M15
double st_m15 = iCustom(NULL, PERIOD_M15, "Supertrend",
10, 3.0, 0, 1);
// Multi-timeframe filter: check H1 alignment
if(!IsMultiTFSuperTrendAligned(PERIOD_M15, PERIOD_H1, 10, 3.0))
{
// Misaligned — skip this bar
return;
}
// Now proceed with your original entry logic
if(st_m15 > 0 && !IsTradeOpen(OP_BUY))
OpenBuy();
else if(st_m15 < 0 && !IsTradeOpen(OP_SELL))
OpenSell();
}
Notice I check the filter before the entry condition. That way, if the filter blocks the trade, we don't even evaluate the entry signal — saves CPU cycles and avoids edge cases where the entry condition might have side effects. Also, I'm using Volume[0] > 1 to detect new bars. This is a common trick in MQL4 that checks if the current tick is the first one on a new bar. If you're on MQL5, you'd use SeriesInfoInteger() with SERIES_LASTBAR_DATE instead.
Parameterizing the Filter for Flexibility
Hardcoding timeframe values is fine for a quick test, but you'll want to make them configurable. Here's how I set up my external parameters:
//--- Input parameters
input int InpATRPeriod = 10; // ATR Period
input double InpMultiplier = 3.0; // Supertrend Multiplier
input ENUM_TIMEFRAMES InpExecTF = PERIOD_M15; // Execution Timeframe
input ENUM_TIMEFRAMES InpFilterTF = PERIOD_H1; // Filter Timeframe
input bool InpUseFilter = true; // Use Multi-TF Filter
Then in your OnTick():
void OnTick()
{
if(Volume[0] > 1) return;
if(InpUseFilter)
{
if(!IsMultiTFSuperTrendAligned(InpExecTF, InpFilterTF,
InpATRPeriod, InpMultiplier))
return;
}
// Rest of your logic...
}
This way, you can toggle the filter on and off in the EA's input dialog without recompiling. I always include a checkbox parameter like InpUseFilter so I can run A/B comparisons in the Strategy Tester.
Backtest Validation: What to Expect
I ran a backtest on EURUSD from January 2023 to June 2024 using a simple Supertrend EA (ATR period 10, multiplier 3.0) on M15. Then I added the H1 multi-timeframe filter. Here's what the Strategy Tester showed:
| Metric | Without Filter | With M15+H1 Filter | Change |
|---|---|---|---|
| Total Trades |






