linetrades

Precision signals for systematic traders.

A column by Kyle Donnelly

Kyle Donnelly, Algorithmic Trader & Market Technician

August 31, 2026 · 19 min read

FX backtesting: overcoming the broker spread objection

A backtest can produce an attractive equity curve and still be asking a question the live market never answers.

FX backtesting: overcoming the broker spread objection

The usual failure is easy to miss. A strategy is tested against mid-prices or candle closes, entries and exits are assumed to happen at the same reference price, and the resulting performance is treated as evidence of an edge. Once the code reaches a broker feed, the entry happens on one side of the quote and the exit on the other. The signal may be unchanged, but the trade is no longer free.

That difference is the spread. In a short-term system, it can determine whether the strategy has an edge at all. In a slower system, it can quietly reduce the margin of safety until a promising backtest becomes an ordinary, expensive way to lose money.

The point is not to make every backtest pessimistic. It is to make the simulation answer the same execution problem that the live strategy will face.

The Fallacy of Mid-Market Pricing in OTC Environments

Spot FX is an over-the-counter market rather than a single exchange with one central order book. There is no consolidated quote that all participants must use, and there is no universal best bid and offer comparable to the NBBO in US equities. Banks, prime brokers, liquidity providers and retail brokers may stream different prices and different spreads at the same moment.

A price feed used for research is therefore not automatically a tradable record. A data vendor may construct bars from multiple contributors, while a broker presents quotes from its own liquidity arrangement. The candle can be useful for studying direction and volatility, but it does not tell you exactly where a particular account could have been filled.

That distinction matters immediately when a strategy trades.

  • A market buy is executed at the ask.
  • A market sell is executed at the bid.
  • A long position is normally closed at the bid.
  • A short position is normally closed at the ask.

The midpoint sits between those prices. It is useful as a reference, but it is not the price at which both sides of a round trip can be executed.

Suppose EUR/USD is quoted with a spread of 1.2 pips. A long position opened at the ask begins with an unrealized cost relative to the mid-price, and it must later be sold at the bid. For a standard lot, that spread is roughly twelve US dollars before commission and slippage, assuming the usual pip value for EUR/USD. The exact cost changes with position size, quote currency and exchange rate, but the mechanism does not.

A backtest that fills both the entry and the exit at the midpoint removes that cost from every trade. One trade may not reveal the mistake. A strategy that turns over frequently can accumulate it across thousands of entries and exits.

A midpoint is a useful analytical reference, not a guaranteed execution price. If both sides of a trade are filled there, the backtest is granting the strategy a privilege the live market does not.

The problem becomes more complicated because there is no single FX spread. EUR/USD may be relatively tight during the most liquid part of the European and US trading day and materially wider during quieter hours. A broker offering a raw-spread account may charge a separate commission; another broker may embed more of the cost in the quote. Two brokers can show different results even when the strategy logic and market period are identical.

For that reason, a historical dataset should be connected to the execution environment it is meant to represent. If the intended deployment is with a particular broker, that broker’s tick history is usually more relevant than a convenient composite feed. It may still be incomplete, filtered or subject to changes in liquidity sourcing, but it at least reflects a coherent quoting environment.

The right question is not whether a backtest uses “real” prices in the abstract. It is whether the tested prices, spread assumptions and fill rules resemble the account that will trade the strategy.

Modeling Dynamic Spreads: From Session Volatility to News Events

A fixed spread is better than no spread, but it is still a weak description of FX execution. Spreads respond to liquidity, volatility, market hours, rollover, news and the broker’s own risk controls. They can widen just when a strategy is most active.

A session map is a practical starting point. It does not need to pretend that every hour has one permanent spread. Its purpose is to stop the backtest from applying the tightest observed conditions to every trade.

A useful model can distinguish between:

  • The quieter parts of the Asian session, when activity and available liquidity may be lower.
  • The London session, including the transition into European liquidity.
  • The London–New York overlap, which often has deeper activity in major pairs.
  • The New York afternoon and the hours leading into daily rollover.
  • The rollover window itself, when financing and settlement processes can coincide with thinner quoting.
  • Scheduled releases such as employment data, inflation reports and central-bank decisions.

The model can be as simple or detailed as the available data allows. With broker tick history, the spread can be measured directly from bid and ask quotes. With bar data, the researcher may need a session-specific assumption and a separate event multiplier. Neither approach creates information that is absent from the data, so the limitations should remain visible in the results.

For an intraday strategy, the spread model should be time-aware. At minimum, each simulated fill should know the trading session and whether the timestamp falls inside a predefined event window. The event window should not be treated as a magical period in which every pair widens in exactly the same way. A US inflation release can affect USD pairs differently from a European central-bank decision, and the response can vary according to market expectations and liquidity conditions.

The following structure is often more realistic than one spread applied across the entire test:

1. Establish a baseline spread by instrument and trading session.

2. Add a wider assumption for rollover and other recurring liquidity gaps.

3. Apply a separate event multiplier around scheduled releases.

4. Add slippage as a distinct cost rather than hiding it inside the spread.

5. Record how many trades were affected by each assumption.

That last step is important. A strategy may look robust after a cost adjustment, but if most of its profit comes from a small number of trades during news windows, the result deserves closer scrutiny. The issue is not only the average cost. It is the interaction between the cost and the strategy’s timing.

A breakout system that enters after a sudden move may be paying the widest spread of the day. A mean-reversion system may be trying to capture a small retracement while the market is still dislocated. A trend-following strategy with low turnover may be less sensitive to a few pips of entry cost but still vulnerable to stop execution during a fast move.

Spread assumptions should follow the instrument

Major pairs, crosses and emerging-market pairs should not be given the same cost profile. Even within one broker, EUR/USD, GBP/JPY and USD/MXN can behave very differently across sessions. A spread table should therefore be indexed by symbol as well as time.

It is also worth separating quoted spread from total transaction cost. Depending on the account, the strategy may pay:

  • The bid-ask spread.
  • A commission charged per side or per round turn.
  • Slippage between the requested and executed price.
  • Financing or swap for positions held through rollover.
  • Conversion costs when the account currency differs from the instrument’s profit currency.

A backtest that models only the visible spread can still be optimistic. Conversely, adding a large blanket penalty to every trade can obscure where the real weakness lies. Keeping the components separate makes the sensitivity analysis more useful.

Quantifying Execution Costs with the Roll and Corwin-Schultz Models

Historical bid-ask data is the preferred input for intraday backtesting, but it is not always available. Many datasets provide only OHLC bars, and some older archives contain a single price stream with no quote-side information. In that situation, spread estimators can provide a baseline assumption.

They are not substitutes for native bid and ask history. They infer a cost from price behavior, and the inference can be distorted by volatility, trends, price discreteness and market-specific microstructure. Their value is diagnostic: they help reveal whether a strategy’s apparent edge is large enough to survive a plausible transaction cost.

The Roll estimator

The Roll model is generally associated with Richard Roll’s 1984 paper on bid-ask spreads and transaction prices. Its intuition is straightforward. If trades alternate between the bid and the ask while the underlying value changes less, observed returns can show negative serial covariance. That covariance can be used to estimate an effective spread.

A common simplified expression is:

c = sqrt(−Cov(rₜ, rₜ₋₁))

Here, \(rₜ\) is the return at time \(t\), and \(c\) represents a spread-related estimate under the model’s assumptions. The notation should not be mistaken for a complete execution model. The estimate is meaningful only when the covariance is negative and the data behaves sufficiently like the process the model describes.

FX data often violates those assumptions. Prices can trend, quotes can update asynchronously, and the observed return may include jumps or filtering effects that have nothing to do with bid-ask bounce. If the estimated covariance is positive, the simple Roll calculation is not merely inconvenient; it is telling you that the model is not identifying a spread in that sample.

The Roll estimate can still be useful as a lower-bound diagnostic for a liquid instrument or as one input in a broader sensitivity range. It should not be presented as the broker’s actual historical spread.

The Corwin–Schultz estimator

The Corwin–Schultz approach uses high and low prices over consecutive periods to infer a spread-related measure from the relationship between daily ranges. It is designed for situations where quote data is unavailable and standard OHLC observations are all that remain.

That makes it attractive for end-of-day research, but the trade-off is resolution. A daily high and low do not reveal when the range occurred, which side of the market was quoted at the time, or how a specific entry order would have interacted with the spread. The estimate can provide a broad cost assumption for a low-turnover strategy; it is much less persuasive as a reconstruction of execution for scalping or event-driven trading.

A practical comparison looks like this:

Estimator or inputData requiredWhat it can supportMain limitation
Native bid/ask tick feedTime-stamped bid and ask quotesIntraday and short-horizon execution analysisRequires suitable broker or vendor history
Session-specific spread modelOHLC or trade data plus a time-of-day mapIntraday testing when quote history is incompleteAverages away within-session variation
Roll estimatorA return series with suitable samplingA first-pass effective-cost diagnosticSensitive to trends, jumps and model assumptions
Corwin–Schultz estimatorHigh-low observations over consecutive periodsBaseline costs for slower, OHLC-based systemsDoes not reconstruct the timing of actual fills

The estimates should be compared with whatever live or recent broker observations are available. If a model implies a cost that is obviously inconsistent with the instrument and account, the correct response is not to force the number into the backtest. It is to investigate the sampling, quote construction and estimator assumptions.

Neither Roll nor Corwin–Schultz captures a sudden event-driven spread spike particularly well. For a news-sensitive strategy, a baseline estimate can be combined with a separate stress case around scheduled releases. That stress case is a scenario, not a claim that the estimator has measured the event accurately.

A spread estimator can expose a fragile strategy, but it cannot recreate a missing quote tape. Treat the result as a cost assumption with uncertainty around it.

Stress-Testing Strategies Against Worst-Case Liquidity Scenarios

A single “realistic” backtest is still only one interpretation of execution. Even native tick data may reflect a period in which liquidity was unusually favorable, or a feed whose quotes do not match the broker selected for deployment.

This is where stress testing earns its place. A simple and transparent method is to rerun the strategy with the baseline spread multiplied by two and three. These are heuristic scenarios, not universal descriptions of the market and not a statistical statement about how often such conditions occur. Their purpose is to measure how much execution deterioration the strategy can absorb before its behavior changes.

The result should be read in more than one dimension:

  • Does the total return decline gradually or disappear immediately?
  • Does the maximum drawdown expand disproportionately?
  • Does the strategy’s trade frequency change because entries no longer clear their minimum profit threshold?
  • Are losses concentrated in one session, one pair or one event type?
  • Does the strategy remain profitable because of a broad signal, or because a handful of low-cost trades dominate the sample?
  • Do the same market regimes still produce the gains?

If a system fails when the spread assumption is doubled, that does not prove the signal is worthless. It does show that the signal has a narrow execution margin. A strategy with a small average target, frequent entries or many trades around volatile releases may simply be incompatible with the account’s actual trading conditions.

Slippage should be stressed separately. Spread is the quoted distance between bid and ask. Slippage is the difference between the modeled price and the eventual fill. A stop order can experience adverse slippage during a fast market even when the quoted spread looks ordinary immediately before the move.

Position size also matters. There is no universal percentage of volume at which a retail FX order begins moving the market, because the relevant liquidity depends on the broker, venue, aggregation and time of day. Instead of hard-coding a supposedly universal threshold, run scenarios in which fills worsen as size increases and liquidity falls. The exercise is more informative when tied to the strategy’s actual order sizes and trading windows.

One useful stress matrix includes:

1. Baseline broker spread with the selected commission.

2. Baseline spread plus a modest adverse-slippage assumption.

3. Twice the baseline spread.

4. Three times the baseline spread during selected stress windows.

5. Wider spreads and adverse slippage together.

6. Delayed or missed fills for a small portion of trades during fast markets.

The final scenario should not be mistaken for a forecast. It is a test of failure modes. If every reasonable deterioration destroys the result, the strategy may still be worth researching, but it is not ready to be treated as an executable system.

The same principle applies to stops and take-profits. A backtest must specify what happens when both a stop and a target fall inside the same candle, when the market gaps between ticks, and when the requested price is not available. The more compressed the holding period, the less acceptable it is to let the bar engine choose a convenient sequence after the fact.

If the edge disappears as soon as execution becomes moderately worse, the backtest has measured an execution assumption more than a trading signal.

Implementing Tick-Level Data and Slippage Buffers in MT5

MetaTrader 5 can test strategies with real-tick data when an appropriate history is available, but the phrase “real tick” does not remove every modeling problem. The quality, origin and coverage of the tick archive still matter. The tester also needs explicit rules for spread, commissions, order types and execution behavior.

A robust MT5 workflow begins with the data rather than the optimization report.

Start with a coherent quote history

Use the broker’s own historical archive where possible, or a third-party feed whose construction is understood. Check for missing periods, duplicate ticks, suspiciously constant spreads and abrupt changes in quote behavior. A dataset that contains only trade-like prices cannot reliably reproduce bid/ask execution.

The test period should include the sessions in which the strategy is intended to operate. If the algorithm trades through major releases, the history must contain enough relevant event windows to make that choice meaningful. If it does not, the safest approach is to test a separate event-stress scenario rather than imply that the missing behavior has been observed.

Make the fill logic explicit

The code and tester configuration should distinguish the side of the quote used for each operation. Long entries and short exits interact with the ask; short entries and long exits interact with the bid. Limit orders, stop orders and market orders should not be treated as interchangeable. Their fill assumptions differ, especially when the market moves through a requested price.

Commissions should be represented separately from spread where the account charges them separately. Swap should be included for strategies that hold positions through the broker’s rollover process. Currency conversion and contract specifications also need to match the intended symbol.

Add session and event rules

A session map can alter the spread assumption according to the timestamp of each tick. Event rules can widen the simulated spread or add an adverse slippage allowance around scheduled releases. The exact multiplier should be documented as a scenario parameter, not hidden in the strategy.

It is useful to run at least three versions:

  • A broker-history baseline.
  • A wider-spread stress test.
  • A wider-spread test combined with adverse slippage.

The objective is not to find one impressive optimization result. It is to see whether the signal, ranking of trades and drawdown profile remain recognizable as costs change.

Validate outside the tester

A demo run is not proof of profitability, but it can reveal implementation errors that a historical test cannot. Compare timestamps, order direction, requested prices, actual fills, spread at entry and exit, and slippage. Pay particular attention to the first live trading sessions around rollover and scheduled news if the strategy is permitted to operate then.

A divergence between demo execution and the backtest does not automatically mean the historical model is wrong. The two environments may have different liquidity, commissions or quote aggregation. It does mean the model needs another explanation before capital is increased.

For a serious validation process, keep the backtest, stress scenarios and demo comparison in separate records. Do not overwrite the baseline every time a more pessimistic assumption is introduced. Reproducibility is part of execution research: another run should be able to show exactly which costs were used and why.

The same discipline applies beyond FX

The execution lesson extends to other instruments, but the market structure does not remain identical.

Gold and many retail CFD products may be quoted over the counter by a broker or liquidity provider, with spreads that vary around sessions and economic events. A CFD can also include financing, contract-specific tick values and broker rules that are not present in the underlying market.

Crude-oil futures are different. They are exchange-traded contracts with a central marketplace, published contract specifications and exchange-linked order-book liquidity. They still face bid-ask spread, queue position, market impact, slippage, trading halts or limit rules, and changes in liquidity around reports and contract rolls. But calling their structure “dealer-quoted” in the same sense as spot FX is inaccurate. A futures backtest should use futures-specific data and execution assumptions rather than simply porting an OTC FX spread table into the symbol.

The same applies to futures rolls, CFD pricing and spot-metal feeds. Before transferring a cost model, identify:

  • Whether the instrument is exchange-traded or OTC.
  • Which price series the broker actually uses for execution.
  • How contract rolls, expiries or CFD adjustments are handled.
  • Whether the quoted spread is separate from commission and financing.
  • Which sessions and events produce the largest liquidity changes.

For traders building strategies around macro releases, the relationship between instruments is also part of the problem. US labor data and Federal Reserve decisions can move the dollar, metals and futures markets at the same time, but each market expresses the move through its own quoting and execution structure. The commodity framing on how US labor data and Fed policy actually move gold and silver is useful context when a USD-pair strategy is tested alongside metals exposure.

A cross-asset backtest should therefore preserve the common principle—model the price at which an order can actually be filled—without pretending that the venues operate in the same way.

The constraint test, not the forecast

A backtest is not a forecast of the next sequence of trades. It is a constraint test for a proposed rule set. Spread, slippage, commission, rollover and liquidity assumptions define the conditions under which the strategy is supposed to function.

For FX, that means avoiding mid-market fills, using broker-specific bid and ask history when possible, and modeling spread behavior by session and event rather than applying one attractive average to every timestamp. When quote history is incomplete, Roll or Corwin–Schultz can provide a diagnostic baseline, but the uncertainty around the estimate should be tested rather than hidden.

The stress test is equally important. Running the strategy at two or three times its baseline spread is a useful heuristic for measuring fragility. It is not a claim about a particular percentile of trading days, and it does not guarantee that a passing strategy will behave well in live deployment. It simply answers a hard question: how much execution deterioration can the signal withstand?

Finally, the asset class matters. Spot FX, broker-quoted CFDs, metals and exchange-traded crude-oil futures may all suffer from execution costs, but they do not share one market structure. The cost model has to follow the instrument.

If the strategy survives only when every trade receives a midpoint fill and a narrow spread, the broker is not the obstacle. The backtest is. If the edge remains visible after realistic costs, wider-spread scenarios and adverse fills, it has earned the right to be tested further—first in a controlled environment, then with position sizing that respects what the market can actually provide.

FAQ

Why are midpoint fills unrealistic in an FX backtest?
A market buy is executed at the ask, while a market sell is executed at the bid. Long positions are normally closed at the bid and short positions at the ask, so filling both sides at the midpoint removes the spread cost from the trade.
How should dynamic FX spreads be modeled?
A model can use baseline spreads by instrument and trading session, wider assumptions for rollover and recurring liquidity gaps, and a separate event multiplier around scheduled releases. Slippage should be modeled as a distinct cost rather than hidden inside the spread.
What can the Roll and Corwin–Schultz estimators tell me?
They can provide baseline or diagnostic transaction-cost assumptions when bid-ask history is unavailable. They do not replace native bid-and-ask data or reconstruct the timing of actual fills, and their estimates are affected by market conditions and model assumptions.
How can I stress-test an FX strategy against spread risk?
Rerun the strategy with the baseline spread multiplied by two and three, and test wider spreads together with adverse slippage or delayed and missed fills. These are heuristic scenarios used to measure fragility, not forecasts of how often such conditions occur.
What should be checked when backtesting an FX strategy in MT5?
Use the broker’s historical archive where possible, check the quote history for gaps and suspicious spread behavior, and make fill rules explicit for each order type. Model commissions, swap, currency conversion and contract specifications separately where applicable, then compare the backtest with demo execution.

Kyle Donnelly