How to backtest a forex strategy without fooling yourself
A complete forex backtesting workflow: freeze the rules, count every eligible event, model trading costs, protect unseen data and make a decision.
Write one question that can fail.
Start with a directional claim and a baseline. For example: “After an H4 EMA(20) and EMA(50) crossover on EUR/USD, entering at the next bar open has positive net expectancy after costs.” Then state a rejection gate, such as net expectancy at or below zero in the untouched sample.
Eligibility is decided using only information available at the decision time. Freeze the pair, timeframe, date range, indicator definitions, minimum history, session or event exclusions, spread ceiling, one-position rule and duplicate-signal handling. Record every eligible event, including the ones you would rather skip after seeing the next candle.
- Hypothesis and baseline
- Pair, timeframe and clock
- Eligibility and no-trade rules
- Minimum acceptable result
- Version name and freeze date
Make the backtest executable by another reader.
A long rule must name the completed signal candle, the entry price and timing, the initial stop, the exit and what happens if entry gaps or two signals overlap. Write the short side separately rather than assuming “the opposite”; asymmetrical markets, spread and event filters can make that phrase ambiguous.
One frozen example is: long when EMA(20) was at or below EMA(50) on the prior completed H4 bar and closes above it on the signal bar; short for the reverse. Enter once at the next H4 open. Set the initial stop 1.5 × ATR(14) from the filled entry. Exit at 2R or the stop, whichever is touched first. If both are touched inside one OHLC bar and lower-timeframe evidence is unavailable, record the conservative stop-first result. Cancel if the entry gap exceeds 0.5 × ATR or spread exceeds the frozen ceiling.
Move from chart result to net R.
Define whether historical bars are bid, ask or midpoint and model the executable side. Spread affects entry and exit; commission is charged according to the account schedule; slippage moves the assumed fill; rollover or financing applies when the position crosses the provider’s cutoff. Convert the complete cash cost to R using the original planned risk so results remain comparable.
Store both gross and net result, but make decisions from net. Use dated broker cost records if available. When reliable historical costs are missing, disclose the proxy and rerun the sample with a plausible base and stressed cost instead of treating zero friction as fact.
The denominator is every eligible event.
Give each eligible event an ID before assigning its outcome. Record signals that were cancelled by the frozen gap, spread or overlap rule as no-trades with a reason. Record ambiguous bars with the pre-declared conservative rule. Do not count only completed trades and quietly discard valid signals that could not be filled.
There is no magic trade count that proves an edge. Report the number of eligible events and completed trades, calendar span, number of pairs, long/short split and observations by year and regime. Clustered signals are not the same as many independent repetitions, so a larger count can still carry substantial uncertainty.
Develop first, confirm later.
Split time chronologically before inspecting results: an earlier in-sample period for defining or selecting the rule and a later out-of-sample period for one honest confirmation. Never shuffle future and past bars together, and never let a future swing label, revised indicator value or later event classification leak into an earlier decision.
If market change makes one split too fragile, use walk-forward windows: freeze on window one, test on the next window, then move forward and repeat. Choices for each test window must use only earlier information. If you alter a parameter after seeing confirmation, rename the version and give it new untouched data.
- No future bars or final swing labels
- No repeated optimisation on confirmation data
- Keep discarded variants in the research record
- Run parameter, start-date and cost sensitivity checks
Read expectancy beside risk and consistency.
Calculate net expectancy in R as (win rate × average win) − (loss rate × average loss magnitude). Show win rate, average win, average loss and payoff ratio together: a low-win-rate method can still have positive expectancy, while a high win rate can hide occasional large losses.
Build the equity sequence in chronological order. Maximum drawdown is the largest peak-to-later-trough fall; longest losing streak counts consecutive losing trades. Also report total net R, profit factor where defined, holding time, long/short split and results by year, pair and declared regime. Averages without their sequence can hide whether the loss path is tolerable.
A valid loss is not a testing mistake.
Give every row a process grade. A means the event, inputs, entry, costs and exit followed the frozen rule with complete evidence. B means the rule was followed but a documented data or execution assumption is weaker. C means the outcome is usable only for sensitivity analysis. D means a rule breach or missing evidence excludes it from the primary result—but the row remains visible.
Do not remove D rows to improve performance. Report the frozen-rule result and a separate implementation-quality count. This distinguishes whether the idea failed, the test record failed, or both.
Reject, revise, observe or demo-test.
Reject when the pre-declared confirmation gate fails. Revise only when you can state a new mechanism and obtain new untouched data. Observe further when the estimate is promising but the sample, event coverage or cost data is too weak. Consider a versioned demo forward test only when the frozen rule survives its confirmation and sensitivity checks.
A backtest never proves future profitability or personal suitability. Keep the hypothetical label beside the result, write the known limitations, and pre-declare the forward-test pause rule before watching live candles.
A result that reconciles—and still needs caution
This is arithmetic for learning, not evidence for the EMA crossover. Imagine the frozen H4 method above produced 40 completed out-of-sample trades: 17 wins and 23 losses. After spread, commission, slippage and rollover, the average win was +1.62R and the average loss was −1.04R.
- Win rate = 17 ÷ 40 = 42.5%
- Loss rate = 23 ÷ 40 = 57.5%
- Payoff ratio = 1.62 ÷ 1.04 = 1.56
- Expectancy = (0.425 × 1.62) − (0.575 × 1.04) = +0.0905R per trade
- Total net result = (17 × 1.62R) − (23 × 1.04R) = +3.62R
- Profit factor = 27.54R ÷ 23.92R = 1.15
In the fictional chronological sequence, the largest peak-to-trough fall was 5.42R and the longest losing streak was five trades. Of 44 eligible events, four were correctly cancelled by the frozen gap or spread rules, leaving the 40 completed trades. Process grades were 35 A, three B and two C; no row was deleted.
To make the path statistics auditable, assign +1.62R to each W and −1.04R to each L in this sequence:
W L L W L W L L L W W L W L L W L W W L L L L W L W L W L L W W L L L L L W W W
The numbers reconcile: 40 × 0.0905R = 3.62R. They do not establish a durable edge. With only 40 completed trades, small positive expectancy and meaningful drawdown, the sensible decision would be “observe further” rather than move to live capital.
Start from a frozen strategy card
Each checklist supplies a specific timeframe, settings, long and short trigger, stop, management rule, costs and no-trade filters. Print or save one before opening the chart so the outcome cannot rewrite the method.