How to Add a Spread Filter to an MQL5 EA (Points vs Pips)
To add a spread filter to an MQL5 EA, read Bid and Ask together with SymbolInfoTick, divide their difference by _Point, and reject new entries when that spread exceeds your limit. Apply this check after position management so a wide spread does not accidentally disable your EA's exits or trailing stops.
What a spread filter actually controls
The spread is the difference between the current Ask and Bid. A market buy normally opens at Ask; a market sell normally opens at Bid. A wider spread increases the price gap a trade must overcome, before considering commission, swaps, or execution slippage.
A spread filter is an entry condition, not a trading signal. It can prevent an EA from opening during expensive quotes, but it cannot make an unprofitable strategy profitable. It also cannot guarantee the execution price: the quote can change between your check and the broker processing an order.
This guide supplies an integration helper rather than a complete trading strategy. There are no backtest performance numbers because no particular entry rule, exit rule, or historical test is being presented.
Calculate spread in points, not guessed pips
For the chart symbol, calculate spread points as (tick.ask - tick.bid) / _Point. Both prices come from the same MqlTick snapshot. Checking the return value of SymbolInfoTick matters: unavailable quote data must block a new entry rather than silently allowing it.
For example, suppose a five-decimal EURUSD quote has Bid 1.10000 and Ask 1.10020, with a point size of 0.00001. The difference is 20 points, conventionally two pips for this quote format. A limit of 2 points would therefore be much tighter than a limit of two pips. These are arithmetic examples, not observed trading results.
Do not generalize that conversion to every instrument. Metals, indices, and broker-specific symbols have their own price conventions. Use a clearly labeled points input and inspect the actual symbol specification. A point is also not necessarily the minimum tradable price increment; tick size is a separate property relevant when constructing order prices.
MQL5 spread-filter helper
Add this input and function at global scope in your existing EA. It uses the current chart symbol only; if your EA trades another symbol, retrieve that symbol's point size instead of using _Point.
input double MaxSpreadPoints = 20.0; // Example, not a recommendation
bool SpreadAllowed(const double max_points)
{
if(max_points <= 0.0 || _Point <= 0.0)
return false;
MqlTick tick = {};
if(!SymbolInfoTick(_Symbol, tick))
return false;
if(tick.bid <= 0.0 || tick.ask <= 0.0 || tick.ask < tick.bid)
return false;
const double spread_points = (tick.ask - tick.bid) / _Point;
return spread_points <= max_points;
}
The helper fails closed for nonpositive limits, failed quote retrieval, nonpositive prices, and crossed quotes. Zero is deliberately not a magic value meaning “disable the filter.” If disabling is required, implement an explicit switch so a configuration mistake cannot remove this check unnoticed.
The comparison includes equality mathematically. Decimal prices are represented in floating point, however, so a computed boundary can differ by a tiny fraction. If precise equality handling matters, define and test an explicit numerical tolerance; avoid casually rounding the spread down, which can admit an above-limit quote.
Put the check immediately before new entries
Within OnTick, keep existing-position management first. After your signal and other entry checks, insert if(!SpreadAllowed(MaxSpreadPoints)) return; before the code that submits a new order. Do not place it above emergency exits, trailing-stop updates, or other management that must continue during wide spreads.
New-bar strategies need another decision: should a rejected entry expire, or remain eligible later in the same bar? If your new-bar marker is consumed before the filter, a high spread on the first tick can skip that bar entirely. That can be valid, but document it. Retrying later requires preserving signal state and preventing duplicate orders once an entry succeeds.
Pending orders need separate treatment. Filtering their placement does not prevent an already placed order from activating later during a wider spread. Define cancellation or expiry rules explicitly rather than assuming this helper controls future execution.
Verify behavior before trusting results
First compile the modified EA in MetaEditor. Then use the Strategy Tester to inspect both allowed and rejected entries. For spread-sensitive strategies, prefer “Every tick based on real ticks” where suitable broker history is available; coarse modeling can miss intrabar spread changes.
- Check a quote clearly below the threshold and one clearly above it.
- Confirm open-position management still runs when entries are blocked.
- Confirm the input is measured in points for the tested symbol.
- Record the symbol, timeframe, dates, tick model, commission settings, and threshold when comparing runs.
A filter changes which trades exist, not just their transaction costs. Compare trade count and drawdown alongside net results, and reserve an untouched period for evaluation instead of selecting the nicest historical threshold. Past performance does not guarantee future results.
Generate the surrounding EA from a written specification
Ranar Algo generates an EA from plain English, compile-checks it with MetaEditor, and can run a real MetaTrader 5 backtest. Specify the spread unit, threshold, entry timing, and which exits must remain active in your request. You keep your intellectual property and can download the generated source code. The tool is still improving; feedback is welcome, and generated logic and reports still need your review.
Official references and next step
The APIs and predefined variables above were checked against the locally mirrored official MQL5 reference: SymbolInfoTick, _Symbol, _Point, and OnTick. The official SymbolInfoTick reference is https://www.mql5.com/en/docs/marketinformation/symbolinfotick and the point definition is https://www.mql5.com/en/docs/predefined/_point.
Start with one explicit rule: block new entries above a documented points limit while leaving position management active. Confirm that behavior before changing the strategy or optimizing the threshold.
Build & backtest your own EA free →