Skip to content
NEXORA Money & AI

How to Build a Multi-Pair Market Scanner That Filters Out Ranging Markets

October 3, 2026 · OYIN ADESOLA · 5 min read · Updated October 12, 2026
Cover graphic for the article: How to Build a Multi-Pair Market Scanner That Filters Out Ranging Markets

Last checked: 12 October 2026. This guide draws on the MQL5 reference for iADX, iATR and iBands. Thresholds are starting points, not proven values. Test on a demo account.

A scanner that reports a signal on every pair is noisy. A better scanner first asks whether the market is trending at all, and ignores pairs that are going sideways. This guide builds a multi-pair scanner that filters out ranging markets using two measurements: ADX for trend strength and Bollinger Band width for compression.

What “ranging” means in numbers

There is no single official definition, so you must choose measurable conditions and test them. Two common ones are:

  • Low ADX. The Average Directional Index measures trend strength, not direction. Many traders treat readings below about 20 as weak, but that cut-off is a convention, not a rule from MetaQuotes.
  • Narrow band width. Bollinger Bands contract when volatility is low. If the width divided by the middle line is small compared with its own recent history, price is compressed.

The scanner below labels a pair TRENDING only when ADX is above your threshold, and RANGING otherwise, with an extra flag when bands are squeezed.

Summary graphic listing the main sections of: How to Build a Multi-Pair Market Scanner That Filters Out Ranging Markets

Why compare width with its own history

A fixed width number means different things on EURUSD and on gold. Comparing the current width with the average width over the last 100 bars makes the test relative to each symbol. A ratio below 0.7, for example, says the bands are 30 percent narrower than usual. Again, 0.7 is an adjustable starting point.

The scanner

#property script_show_inputs

input string          InpSymbols   = "EURUSD,GBPUSD,USDJPY,XAUUSD";
input ENUM_TIMEFRAMES InpTF        = PERIOD_M30;
input int             InpAdxPeriod = 14;
input double          InpAdxMin    = 20.0;
input int             InpBBPeriod  = 20;
input double          InpBBDev     = 2.0;
input int             InpWidthBars = 100;
input double          InpSqueeze   = 0.70;

bool Analyse(const string sym, double &adx, double &widthRatio)
  {
   int hA = iADX(sym, InpTF, InpAdxPeriod);
   int hB = iBands(sym, InpTF, InpBBPeriod, 0, InpBBDev, PRICE_CLOSE);
   if(hA == INVALID_HANDLE || hB == INVALID_HANDLE) return(false);

   double a[], up[], mid[], lo[];
   int n = InpWidthBars;
   bool ok = (CopyBuffer(hA, 0, 1, 1, a)   == 1 &&      // main ADX line
              CopyBuffer(hB, 1, 1, n, up)  == n &&      // upper band
              CopyBuffer(hB, 0, 1, n, mid) == n &&      // middle line
              CopyBuffer(hB, 2, 1, n, lo)  == n);         // lower band
   IndicatorRelease(hA); IndicatorRelease(hB);
   if(!ok) return(false);

   // arrays are oldest-first; the last element is the last closed bar
   double sum = 0.0;
   for(int i = 0; i < n; i++)
      if(mid[i] != 0.0) sum += (up[i] - lo[i]) / mid[i];
   double avg = sum / n;
   double cur = (up[n-1] - lo[n-1]) / mid[n-1];
   if(avg <= 0.0) return(false);

   adx = a[0];
   widthRatio = cur / avg;
   return(true);
  }

void OnStart()
  {
   string list[];
   int cnt = StringSplit(InpSymbols, ',', list);
   for(int i = 0; i < cnt; i++)
     {
      string s = list[i];
      StringTrimLeft(s); StringTrimRight(s);
      if(!SymbolSelect(s, true)) { Print(s, ": not available"); continue; }

      double adx = 0, wr = 0;
      if(!Analyse(s, adx, wr)) { PrintFormat("%-8s data not ready", s); continue; }

      string state = (adx >= InpAdxMin) ? "TRENDING" : "RANGING";
      string note  = (wr < InpSqueeze) ? " (bands squeezed)" : "";
      PrintFormat("%-8s ADX %.1f  width ratio %.2f  -> %s%s", s, adx, wr, state, note);
     }
  }

Reading the buffers correctly

For the Bollinger Bands handle, buffer 0 is the middle line, buffer 1 is the upper band and buffer 2 is the lower band. For ADX, buffer 0 is the main line, with the plus and minus directional lines in buffers 1 and 2. Mixing these up is a classic mistake that produces plausible but wrong numbers. Always print a few values and compare them with the indicator on a chart.

How to use the output

  1. Run the scanner on the timeframe you trade.
  2. Take pairs marked TRENDING to your signal tool for direction.
  3. Treat RANGING pairs as “no trade by this system” rather than as a failure.
  4. A squeeze followed by a trend start is the idea behind the Bollinger breakout article in this series.

Limits

  • ADX lags, so a trend is often visible before ADX confirms it.
  • A low ADX does not guarantee price will stay sideways.
  • Symbols with different trading hours may show stale data when their market is closed.

Step by step: running and reading the scanner

  1. Create a new script in MetaEditor, paste the code and compile with F7.
  2. Make sure every symbol in your list appears in Market Watch. Right-click Market Watch and choose Symbols to add missing ones.
  3. Drag the script onto a chart and set the timeframe you actually trade in the inputs.
  4. Open the Experts tab and read one line per symbol.

Interpreting ADX sensibly

ADX is derived from directional movement and smoothed over the period you choose, so it reacts slowly. A rising ADX tells you a trend is strengthening, regardless of whether price is going up or down. A falling ADX after a strong trend tells you momentum is fading, not that price will reverse. Because the scanner reads the last closed bar, the label can be one candle behind. That delay is the price of avoiding a value that flickers while the candle forms.

Comparing thresholds on your own data

Instead of trusting the default 20, run the scanner at the same moment with thresholds of 15, 20 and 25, and look at the charts of the pairs it labels differently. Ask yourself which setting matches what you would call a trending chart if you looked at it by eye. Write the answer in a notebook with the date. After a few weeks you will have a threshold chosen from your own observations rather than from an internet rule of thumb.

Combining with the other tools in this series

The natural workflow is to run this scanner first to remove sideways pairs, then use the trend scanner to see direction, then the signal indicator to time entries, and finally the risk calculator to size the trade. Each tool answers one question, and none of them replaces your judgement.

What we could not confirm

  • The best ADX threshold or squeeze ratio. Backtest your own values.
  • That filtering ranging markets improves net results for any particular system.

Frequently asked questions

Why use a script? It runs on demand and can read other symbols. For continuous scanning, move the logic into an Expert Advisor with a timer.

Can I add more filters? Yes, but each filter must be tested. More filters can also mean fewer opportunities.

Key takeaways

Define “ranging” with numbers, compare volatility with each symbol’s own history, read the right buffers and use the filter to remove pairs, not to predict them.

Sources checked

  • MQL5 Reference, iADX, iBands, iATR and CopyBuffer, mql5.com

Educational content only — not financial advice. Income and savings results vary and are never guaranteed. How we write

Enjoyed this story?

Get the best stories delivered weekly.

Leave a Reply

Your email address will not be published. Required fields are marked *

Share with