How to backtest an EA on real tick data in MetaTrader 5
Switching MT5's Strategy Tester to real ticks is one dropdown. Making that dropdown mean something is harder — the terminal will happily serve you ticks it invented on the fly, and the report looks identical either way. Here is the routine: confirm the data exists, import it if it does not, configure the tester honestly, then verify what actually got replayed.
Generated ticks are not real ticks
MT5's plain "Every tick" mode builds an intrabar path from M1 OHLC. For each minute it places roughly four synthetic ticks and guesses the order of high and low within the bar. For a daily or H4 strategy that barely matters. For anything with tight stops, trailing logic, grid entries or multiple orders per minute, the guess *is* the test — you are measuring your EA against a price sequence that never existed.
"Every tick based on real ticks" replays the ticks the broker recorded, spread changes included. That is what you want, provided the data is there.
Step 1: Find out what your broker keeps
Open Market Watch, right-click the symbol, choose Symbols, go to the Ticks tab and press Request. Note the earliest date returned. Brokers commonly keep weeks or months of ticks, not years, and the window differs per symbol. If you only have two months, no tester setting fixes that — you need to import your own data.
Step 2: Import longer history as a custom symbol
In the Symbols dialog, use Custom Symbols → Create Custom Symbol, then open its Ticks tab and import a CSV of time, bid and ask. Free sources exist (Dukascopy's historical tick downloads are the usual starting point); commercial vendors sell cleaner files.
Two things bite people here. First, timestamps must match your broker's server time zone, or every session-based rule in your EA fires at the wrong hour. Second, a custom symbol carries its own specification — contract size, tick size, digits, swap and commission. Set them by hand. A mismatch on tick value alone can scale your entire result by a factor of ten.
Step 3: Configure the tester
1. Pick the custom symbol in the tester's Symbol field; it appears below the broker's symbols.
2. Modelling: Every tick based on real ticks.
3. Dates: cover the full tick window, but reserve the last stretch as out-of-sample.
4. Deposit and leverage: match what you will actually trade with.
5. Delays: 0 for a best case, Random for something closer to live. Execution: Market for most retail brokers.
6. Spread: check what the tester applies. It can override the bid/ask in your imported data, so verify rather than assume.
7. Optimisation: leave it off for a single run. Real-tick optimisation is slow.
Step 4: Watch for synthetic-tick fallback
Where your tick data has gaps — broker outages, holidays, thin Sunday opens — MT5 fills them with generated ticks. The journal warns you. A backtest that is 97% real ticks is fine; one that is 60% real is not, and the equity curve will not tell you which you got.
Step 5: Compare the two runs
Run the same EA over the same dates twice: once on generated ticks, once on real ticks. If the curves are close, the strategy is not path-dependent and the cheap run is a fair approximation. If they diverge badly, only the real-tick run carries information. This single comparison tells you more about your EA's fragility than any optimisation.
Costs are still your job
The tester does not invent commission. Put it in the custom symbol specification, along with swap. But real ticks will not rescue a strategy with no edge. [See a real backtest](https://mql.ranartech.com/r/OHlBaejJDIbk) of a USDJPY H4 EA: 220 trades, 55% win rate, and still −$155. A high win rate with negative expectancy looks exactly like a good strategy until you run the numbers.
Audit the tick data before you trust it
Run this script on the symbol's chart first. It reports per-day tick counts and average spread, so you can see where the holes are before the tester starts papering over them.
//+------------------------------------------------------------------+
//| TickAudit.mq5 |
//| Checks per-day real tick coverage and spread |
//+------------------------------------------------------------------+
#property script_show_inputs
#property version "1.00"
#property description "Audits real tick coverage day by day so you know where MT5 will synthesise ticks."
input int DaysBack = 30; // Calendar days to audit
input int MinTicks = 200; // Days below this tick count are flagged
void OnStart()
{
string sym = _Symbol;
datetime now = TimeCurrent();
datetime dayStart = now - (now % 86400); // start of the current server day
int audited = 0;
int missing = 0;
int thin = 0;
long tickTotal = 0;
double spreadSum = 0.0;
MqlTick ticks[];
for(int d = DaysBack; d >= 1; d--)
{
datetime from = dayStart - (datetime)(d * 86400);
datetime to = from + 86400;
MqlDateTime parts;
TimeToStruct(from, parts);
if(parts.day_of_week == 0 || parts.day_of_week == 6)
continue; // skip weekends
int n = CopyTicksRange(sym, ticks, COPY_TICKS_ALL,
(ulong)from * 1000, (ulong)to * 1000);
if(n <= 0)
{
PrintFormat("%s %s : NO TICKS", sym, TimeToString(from, TIME_DATE));
missing++;
continue;
}
double spreadTotal = 0.0;
int spreadCount = 0;
for(int i = 0; i < n; i++)
{
if(ticks[i].ask > 0.0 && ticks[i].bid > 0.0)
{
spreadTotal += ticks[i].ask - ticks[i].bid;
spreadCount++;
}
}
double avgSpread = (spreadCount > 0) ? spreadTotal / spreadCount : 0.0;
if(n < MinTicks)
{
thin++;
PrintFormat("%s %s : %d ticks (thin), avg spread %.1f points",
sym, TimeToString(from, TIME_DATE), n, avgSpread / _Point);
}
spreadSum += avgSpread;
tickTotal += n;
audited++;
}
PrintFormat("--- %s: %d days audited, %d with no ticks, %d thin",
sym, audited, missing, thin);
PrintFormat("--- %s: %I64d ticks total, average spread %.1f points",
sym, tickTotal,
(audited > 0) ? spreadSum / audited / _Point : 0.0);
}
Run it on a live chart, not in the tester — inside the tester, CopyTicksRange returns the modelled series, which defeats the purpose. Weekends are skipped on purpose; a Saturday with zero ticks is not a data gap.
When the output shows a run of thin days, that is exactly where the tester will invent prices. Either accept it and note it in your log, or narrow the backtest window to the clean stretch and be honest about the shorter sample.
Build & backtest your own EA free →