Generate code in 3 minutes
Enter your idea and AI generates runnable code.
To make your trading robot avoid flat (ranging) markets and trade only during volatile periods, the most robust method is to implement a Volatility Filter.
The most common and effective indicators for this in MQL4 are:
Below is a complete, functional MQL4 Expert Advisor template. It uses ATR to detect price range expansion and ADX to ensure there is enough directional momentum before allowing a trade.
//+------------------------------------------------------------------+
//| Volatility_Filter_EA.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- INPUT PARAMETERS ---
input string Filter_Settings = "--- Volatility Settings ---";
input bool Use_ATR_Filter = true; // Enable ATR Filter
input int ATR_Period = 14; // ATR Period
input double Min_ATR_Level = 0.0010; // Minimum ATR Value (e.g. 10 pips on EURUSD)
input bool Use_ADX_Filter = true; // Enable ADX Filter
input int ADX_Period = 14; // ADX Period
input double Min_ADX_Level = 25.0; // Minimum ADX Level (Trend Strength)
input string Trade_Settings = "--- Trading Settings ---";
input double LotSize = 0.1;
input int MagicNumber = 123456;
input int Slippage = 3;
//--- GLOBAL VARIABLES ---
int Ticket = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we have open orders to avoid opening multiple trades in this example
if(OrdersTotal() > 0) return;
// 2. CHECK VOLATILITY CONDITIONS
if(!IsMarketVolatile())
{
// Optional: Print comment to chart to see why it's not trading
Comment("Market is Flat. Trading Paused.");
return;
}
Comment("Market is Volatile. Searching for signals...");
// 3. YOUR STRATEGY LOGIC HERE (Example: Simple MA Crossover)
// This is just a placeholder strategy to demonstrate the filter
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 1);
double maFastPrev = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 2);
double maSlowPrev = iMA(NULL, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 2);
// Buy Signal
if(maFast > maSlow && maFastPrev <= maSlowPrev)
{
Ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, 0, 0, "Volatile Buy", MagicNumber, 0, clrGreen);
}
// Sell Signal
if(maFast < maSlow && maFastPrev >= maSlowPrev)
{
Ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, 0, 0, "Volatile Sell", MagicNumber, 0, clrRed);
}
}
//+------------------------------------------------------------------+
//| Function to check if market meets volatility requirements |
//+------------------------------------------------------------------+
bool IsMarketVolatile()
{
// --- Check ATR Filter ---
if(Use_ATR_Filter)
{
// Get current ATR value
double currentATR = iATR(NULL, 0, ATR_Period, 1);
// If current volatility is less than the threshold, return false
if(currentATR < Min_ATR_Level) return(false);
}
// --- Check ADX Filter ---
if(Use_ADX_Filter)
{
// Get current ADX Main line value
double currentADX = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
// If trend strength is weak (below threshold), return false
if(currentADX < Min_ADX_Level) return(false);
}
// If we passed all enabled checks, the market is volatile
return(true);
}
//+------------------------------------------------------------------+
The ATR measures the average size of the candles.
iATR(...) < Min_ATR_LevelMin_ATR_Level based on the timeframe and symbol you are trading.
0.0005 (5 pips) is very flat. An ATR of 0.0020 (20 pips) is volatile.The ADX measures the strength of the trend, regardless of direction.
iADX(...) < Min_ADX_LevelMin_ADX_Level to 20 or 25. This effectively blocks trades when the market is chopping sideways.If you already have a robot, copy the IsMarketVolatile() function from the code above to the bottom of your file. Then, inside your OnTick() function, wrap your trade logic like this:
void OnTick()
{
// ... existing code ...
// Only proceed to trade logic if volatility is high enough
if(IsMarketVolatile() == false) return;
// ... your entry logic (OrderSend) ...
}
Q: Why does my robot still trade in flat markets even with ADX?
A: ADX is a lagging indicator. If a sudden spike occurs, ADX might still be rising from a low number. Combining ADX with ATR helps because ATR reacts faster to immediate price expansion.
Q: Can I use time filters instead?
A: Yes. Often, "flat" markets are simply specific times of day (e.g., Asian Session for GBPUSD). You can add a simple time check: if(Hour() < 8 || Hour() > 20) return;. However, technical indicators (ATR/ADX) are safer because they handle holidays or unusual calm periods during active hours.
Q: How do I handle different currency pairs with ATR?
A: ATR is an absolute value. 0.0010 on EURUSD is different from 0.50 on Gold (XAUUSD). If you trade multiple pairs, you must adjust the Min_ATR_Level input for each specific chart.