Trading

How to Backtest a Moving Average Strategy: The Cross Is the Easy Part

The crossover is the most backtested idea in retail trading and the one most often tested wrong. Four things decide the result: the warm-up a 200 MA needs before it exists, the price you can actually fill at, the resolution that settles your stop, and the parameter grid that moves the required sample from 216 trades to 486.

October 14, 202612 min readBy TradingSFX
Share:
Table of contents
  1. 01A Crossover Is a Trigger, Not a Strategy
  2. 02Your 200 MA Does Not Exist Yet
  3. 03The Cross Confirms at a Price You Cannot Trade
  4. 04One Candle Decides the Entry, Another Hides the Exit
  5. 05The Parameter Grid Is Where Most of These Tests Die
  6. 06The Bar-by-Bar Procedure
  7. 07Log the Conditions, Not the Parameter Set
  8. 08Three Checks Worth More Than Another Hundred Trades
  9. 09The Short Version

A moving average crossover is the first strategy almost everyone backtests, because it is the only one that is completely unambiguous to spot. Two lines touch. There is nothing to interpret.

That clarity is also why it is the strategy most often tested wrong. When the signal takes no judgement, every error moves into the four places nobody checks: how much history the average needed before it existed, which price you could actually have transacted at, what resolution settled your stop, and how many versions of the idea you quietly tried before keeping one. None of those produce an error message. They produce a flattering number.

This is how to run that test bar by bar so the result is worth something, with the arithmetic shown at each step.

A Crossover Is a Trigger, Not a Strategy

"The 50/200 cross" is not testable as written. It specifies when to be interested and nothing else. Before bar one, five things have to exist on paper:

  1. The trigger. Which average crosses which, and on what timeframe.
  2. The fill. The price you are allowed to transact at once the trigger is confirmed. See the next section but one; this is the decision that moves results most.
  3. The stop. Where the trade is wrong, and crucially how far that is from entry, because that distance is the denominator of every number you will report.
  4. The exit. Fixed target, opposite cross, time stop, structure. The same entries with different exits are different strategies with different distributions.
  5. The filter, if any. Price above the 200, a session window, a trend condition. Each filter is another thing you tested.

Point 3 catches more tests than the rest combined, because the classic crossover system has no stop: it is always in the market and reverses on the opposite cross. That is a legitimate design, but it leaves R undefined, and once R is undefined, expectancy, profit factor and average win cannot be compared to anything. If you are testing an always-in system, define a reference risk anyway (a multiple of average true range at entry is the usual choice) and record it on every trade. That is what makes a crossover test comparable to the rest of your trading. The full argument for measuring in R rather than dollars applies here more than anywhere, because crossover trades vary wildly in size.

Write all five down before you load the chart. Anything you decide after seeing price is not a rule, it is a result.

Your 200 MA Does Not Exist Yet

A 200-period average has no value until 200 candles have closed. Obvious written down, routinely ignored in practice, because the test usually starts at the beginning of the file.

In calendar terms the warm-up is longer than it feels. Forex quotes roughly 120 hourly candles a week (24 hours, five days):

AverageTimeframeClosed candles neededMarket time that covers
50H150about 2 trading days
200M15200about 2 trading days
200H1200about 8 trading days
200H4200about 6 and a half weeks
200D1200about 9 months

So a daily 200 MA study that starts on the first row of a one-year file spends three quarters of that year without the line it is built on.

There is a second, softer version of the same problem. An exponential average is recursive, so it has to be started from something, and the starting value keeps influencing the line for a while. The weight of that seed after m further candles is (1 minus k) to the power m, where k is 2 divided by (period plus 1). For a 50-period EMA, k is about 0.039, so the seed still carries roughly 13% of the value 50 candles later, under 2% after 100, and a quarter of a percent after 150. Practical rule: two periods before you read the line, three before you trade it.

In our replay backtester the averages simply do not draw until they have enough closed candles, rather than drawing a wrong line that converges into place. That is the safer behaviour but it is easy to misread as the indicator not working, so the fix is the same either way: set the replay start date far enough into your file that every average on the chart is warm, or import extra history ahead of your test window and treat it as context rather than sample.

The Cross Confirms at a Price You Cannot Trade

Here is the step that separates a tested crossover from a drawn one.

Mid-candle, a cross can appear and then un-cross before the close. So the signal is only real when the signal candle has closed, and at that instant the close has already happened. The earliest price you can honestly transact at is the open of the next candle.

Most published crossover backtests fill at the signal candle's close. That price is real, which is why the error survives review, but it was available only to someone who knew in advance that the candle would close where it did.

The distance between those two prices is not a cost in the way spread is, because it can fall either way. It is simply unmeasured, and on a momentum trigger it deserves measuring. Do it on your own data: for the first 20 signals, note the signal candle's close next to your actual fill, average the difference, and convert it to R by dividing by your stop distance.

Then add it to the costs the price file never contained. The conversion is one division, and the consequences are not linear, because the sample needed scales with the square of the ratio between outcome spread and edge. Taking a 1:2 setup at a 40% win rate (0.20R average, 1.47R spread):

Gross edgeAll-in drag per tradeNet edgeTrades to clear zero
0.20Rnone0.20R216
0.20R0.05R0.15R384
0.20R0.10R0.10R864
0.20R0.15R0.05R3,456

Half the edge costs four times the trades. A tenth of an R looks like a rounding error on a trade and moves proof out of reach across a sample. That is the whole reason this section exists, and it bites crossover systems harder than most, because they trade often and their stops are frequently tight relative to the move they are trying to catch.

Two of those numbers are yours to supply rather than guess at. The Simulation section of the chart settings panel takes a spread in price points and a per-trade commission in dollars: the spread is applied to fills (a long enters at the ask and exits at the bid, shorts mirrored, and stop checks on shorts use the ask), and the commission comes off the dollar result. Nothing is invented for you, because a spread we made up would make the result look more precise than it is. Put your own broker's numbers in before the first trade, not after you have a curve you like.

One Candle Decides the Entry, Another Hides the Exit

Your fill is settled by the candle after the signal. Your exit is often settled inside a single candle, and that is where the crossover test can swing by more than its entire result.

When one candle's range contains both your stop and your target, the candle does not say which printed first, so whoever resolves it decides the trade. The size of that effect is not small: on 100 trades of a 1:2 setup, the 18 ambiguous ones can swing the total between +44R and -10R on identical entries, which is worked out in full in the CSV walkthrough.

There are two honest answers, and you should use both:

  • Import the finest resolution you can get. Our replay plays a candle from its sub-candles when a finer base is armed as Play res, and when it does, a stop or target fills on the sub-candle that touched it rather than waiting for the display candle to close. That turns the ambiguity into an answer, but only up to the resolution in your file: if you imported hourly data, hourly is all the order anyone has.
  • Until then, count every ambiguous trade as a loss. The test then reports a floor rather than a guess, and a crossover system that survives that convention is one you can size with some confidence.

The Parameter Grid Is Where Most of These Tests Die

Everything above is mechanical. This part is about honesty, and it is the reason most crossover results do not survive contact with live money.

Nobody tests one crossover. A fast length from a handful of candidates, a slow length from a handful more, that is already forty combinations. Run them over three timeframes and it is one hundred and twenty variants. Add a 200 MA trend filter as an on-off switch and it is two hundred and forty. Report the best one and you have reported the maximum of two hundred and forty noisy measurements as though it were a single measurement.

The usual two-standard-error bar assumes one test. Harvey, Liu and Zhu's point is that once many candidates have been tried, a t-statistic of 2 stops meaning what it appears to mean, because the best of twenty coin flips also looks skilled. Their threshold is 3, which multiplies the required sample by 2.25. For the same 1:2 setup at 40%:

What you actually testedBarTrades needed
One rule set, fixed before the runt = 2216
One rule set, 80% chance of seeing a real edget = 2.8424
The best of several you triedt = 3486

The full sample-size derivation and a calculator for your own inputs sits in its own post. What matters here is the behaviour it implies, and it is almost the opposite of what grid search feels like:

Pick one parameter set from how you trade, not from the data. If you watch an hourly chart twice a day, the lengths that matter are the ones that produce a tradeable number of signals at that cadence. Test that one set properly. A clean 216-trade result on a set you chose in advance tells you more than the best of 120 variants on the same data ever can.

If you genuinely want to compare, hold back the last third of your file and never look at it during selection. Choose on the first two thirds, confirm on the slice you have not seen. That is the one procedure that makes a comparison mean something, and it costs you nothing but patience.

The Bar-by-Bar Procedure

Concretely, in replay:

  1. Import the finest candles you have for the instrument, in one file. Higher timeframes build from the import; nothing recovers anything finer later.
  2. Set spread and commission in the Simulation section of the settings panel, from your own broker's numbers.
  3. Add the averages. Up to eight indicators sit on the chart at once, with three oscillator panes under it, which is more than a crossover test needs. Keep it to the two lines and one filter you wrote down.
  4. Set the start date past the warm-up, so every average is warm on the first candle you judge. Confirm by eye: if a line is missing, it is not warm.
  5. Arm the finest Play res available, so stops and targets fill on sub-candles rather than at the close of a display candle.
  6. Step forward one candle at a time with the right arrow key, or play with Space and pause on anything interesting. R jumps to a random start date, which is a useful habit: it stops you replaying the same memorised stretch of chart.
  7. Judge only closed candles. When the signal candle closes, place the order and take the fill on the next candle's open. B and S take market entries, Shift with either places a limit, and the stop and target are draggable lines on the chart with their R value on the label.
  8. Record the trade when it closes, with its R, its exit reason, and the conditions that were true at entry. The close form runs on every plan and the R outcome comes from the stop distance captured at entry, so trailing the stop later cannot inflate it.
  9. Stop at the sample you decided in advance, not at a round number and not at a drawdown. Write the number down before you start or the run ends wherever your patience does.

A session like this produces far more decisions than live trading does. Live gives most traders about ten trades a month; an afternoon of replay produces dozens, and they feed the same statistics as the real ones. That is the entire case for doing it this way rather than scrolling a chart and forming an impression, and the mechanics of running a replay session without hindsight covers the discipline side.

Log the Conditions, Not the Parameter Set

One more thing, and it is the part that makes the next test cheaper than this one.

The grid problem above comes from asking the chart the same question a hundred ways. There is a better place to ask it: on trades you have already logged. If every crossover trade carries tags for the conditions that were true at entry (above or below the 200, which session, which direction, whether the filter was on), then the question "does the trend filter actually pay?" is a query over your sample rather than another hundred runs.

That is what the confluence tags in the close form are for, and what the Confluence Report does with them: every tagged condition is scored both on its own and in the context of every other condition, and the best lift found is compared against 400 shuffles of the same outcomes over the same condition matrix, so a finding has to beat chance before it is reported. A report needs 30 trades on a setup before it will say anything, and a specific combination needs 10. Those floors are the point. The Confluence Report is a Pro feature; the free plan sees it blurred.

The same logic in a lighter form applies to rules you can state in words ("skip the ones below the 200"), which can be tested against your own logged trades with a random-skip control rather than another backtest.

Three Checks Worth More Than Another Hundred Trades

When the run is done, before you believe the total:

Delete your best trade and recompute. Crossover systems catch the occasional very large trend move, and one of those can supply most of the expectancy in a few hundred trades. If the edge dies without it, the edge is that one move.

Split the sample by date and compare halves. A set of lengths that fits one regime usually earns its whole result in the stretch you replayed first.

Count conditions, not rows. Two hundred trades from one trending year on one pair is one observation repeated two hundred times. A crossover is a trend-following idea, so this check matters more here than for any other strategy shape: the question is how many distinct trends the sample contains.

The Short Version

The cross is the one part of a crossover test that cannot go wrong. Everything else can, quietly.

Warm the averages before you judge a single candle. Fill at the next open, not the signal close, and measure what that costs you in R. Put your own spread and commission in before bar one, because a tenth of an R multiplies the sample you need by four. Let resolution settle the ambiguous candles, or count them as losses and report a floor. And pick your lengths before you look, because the best of a hundred and twenty variants needs nearly five hundred trades to mean what twenty looks like it means.

You can run all of it on your own candles in the replay backtester on any plan, or try the workflow on sample data in the free demo without an account.

Published October 14, 2026. Every figure here is arithmetic worked openly from the stated inputs: sample sizes from n = (2s / E) squared, exponential seed decay from (1 - k) to the power m with k = 2 / (period + 1), and warm-up calendar time from a 120-hour forex trading week. Wilder's smoothing factor of 1 / period, its equivalence to an exponential average of 2 x period - 1, and its names across platforms (RMA, SMMA, Wilder's Smoothing) verified 14 October 2026 across independent technical-analysis library documentation and platform references; implementation seeding conventions are stated as a mechanism that varies by platform rather than as a claim about any one vendor, because no vendor documents its own seed. The multiple-testing threshold of t = 3 is Harvey, Liu and Zhu, "... and the Cross-Section of Expected Returns", Review of Financial Studies 29(1), 2016. No competitor pricing is quoted. Plan and product facts (replay on every plan, saving a backtest trade and custom timeframes on Pro, the spread and commission fields, intrabar fills at the imported resolution, indicator and pane caps, Confluence Report thresholds) verified against the code the same day.

Free to start

Turn your trades into a real edge

Stop guessing what works. Log your trades, track confluences, and let the AI Coach surface the patterns you keep missing across every prop firm rule and strategy.

No credit card required · Start for free

Not financial advice. This article is for educational and informational purposes only and does not constitute financial, investment, or trading advice. Trading forex, indices, crypto, and other leveraged instruments carries a high level of risk and can result in the loss of all your capital. Past performance is not indicative of future results. Always do your own research and consider consulting a licensed financial advisor before making any trading decision.
All third-party names and trademarks mentioned in this article are the property of their respective owners. References are made for descriptive and comparative purposes only. TradingSFX is not affiliated with, endorsed by, or sponsored by any third party mentioned. See our Terms of Service for the full trademark disclaimer.

    We use cookies for analytics to improve your experience. Privacy Policy