Develop Custom MT5 Backtesting Indicators: A Step-by-Step Guide

Table of Contents

#property indicator_buffers 2
#property indicator_plots 2 (Source: the U.S. Securities and Exchange Commission’s (SEC) regulations)

double Buffer1[];
double Buffer2[];

input int FastPeriod = 10;
input int SlowPeriod = 20;

int OnInit()
{
SetIndexBuffer(0, Buffer1, INDICATOR_DATA);
SetIndexBuffer(1, Buffer2, INDICATOR_DATA);
return(INIT_SUCCEEDED);
}

void OnCalculate(int rates_total, int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[])
{
for(int i = prev_calculated; i < rates_total; i++)
{
Buffer1[i] = iMA(NULL, 0, FastPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
Buffer2[i] = iMA(NULL, 0, SlowPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
}
}
This example uses two moving average buffers as part of custom MT5 backtesting indicators. The #property lines tell MT5 how many buffers and plots exist. The OnInit() function runs once when the indicator loads. The OnCalculate() function runs for each bar.

Key MQL5 indicator buffer concepts:

  • Buffers store values, each bar gets a calculated value stored in the buffer
  • Input parameters let you adjust behavior, change FastPeriod without recompiling
  • SetIndexBuffer links buffers to display, tells MT5 which buffer to show on the chart
  • OnCalculate loops through bars, processes historical data efficiently

The loop structure matters for backtesting. You calculate from prev_calculated to rates_total. This avoids recalculating bars you’ve already processed.

Compile your code (F5). If you see errors, check the Errors tab. Most errors come from typos or missing semicolons. Fix them and recompile.

Using the MT5 Strategy Tester for Indicator Testing

The MT5 Strategy Tester runs your indicator against historical data. It’s how you validate whether your signals actually work.

Diagram of the development workflow for creating custom MT5 backtesting indicators in the MetaEditor IDE.
Diagram of the development workflow for creating custom MT5 backtesting indicators in the MetaEditor IDE.

Open the Strategy Tester (View > Strategy Tester, or Ctrl+R). You’ll see options for:

  • Expert Advisor, select your test EA (we’ll cover this next)
  • Symbol, the currency pair or asset you’re testing
  • Timeframe, the chart period (M5, H1, D1, etc.)
  • From/To dates, the historical period to test
  • Modeling quality, how detailed the simulation is

Set these before testing:

  1. Choose your symbol (EURUSD, GBPUSD, or whatever you trade)
  2. Pick a timeframe (start with daily or hourly)
  3. Set test dates (at least 1-2 years of data)
  4. Set modeling quality to “Every tick” or “Control points” for accuracy
  5. Check the “Visual mode” box to watch trades execute

Visual mode shows you exactly what happened. You see each trade entry and exit in real time on the chart. This reveals problems that numbers alone miss, like entries that happen after the signal bar closes, or exits that ignore slippage.

Run the test. The tester generates a report showing profit, drawdown, win rate, and other metrics. These numbers mean nothing if your indicator has look-ahead bias (using future data) or repainting (changing past values). We’ll address those next.

Creating an MT5 Indicator Backtest EA for Signal Validation

Here’s where most traders get stuck: indicators alone don’t backtest properly. An Expert Advisor (EA) reads your indicator signals and executes trades. This is how you validate whether those signals actually produce profit. (Source: Statista’s comprehensive data on financial market trends)

Build an EA that reads your custom MT5 backtesting indicators:

#include <Trade\Trade.mqh>

CTrade trade;
int indicatorHandle;

int OnInit()
{
indicatorHandle = iCustom(NULL, 0, “MySignalIndicator”);
if(indicatorHandle == INVALID_HANDLE)
{
Print(“Failed to load indicator”);
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}

void OnTick()
{
double buffer1[], buffer2[];

CopyBuffer(indicatorHandle, 0, 0, 3, buffer1);
CopyBuffer(indicatorHandle, 1, 0, 3, buffer2);

Signup Now →

if(buffer1[1] > buffer2[1] && buffer1[2] <= buffer2[2])
{
trade.Buy(0.1, NULL, 0, 0, 0);
}

if(buffer1[1] < buffer2[1] && buffer1[2] >= buffer2[2])
{
trade.Sell(0.1, NULL, 0, 0, 0);
}
}
This EA loads your custom indicator. It reads the last three bars of both buffers. When the first buffer crosses above the second, it buys. When it crosses below, it sells.

The key line is iCustom(), this loads your indicator file by name. If the file doesn’t exist or won’t compile, iCustom() returns INVALID_HANDLE and the EA fails.

Use CopyBuffer() to pull indicator values into arrays (Technical Indicators – MQL5 functions – MQL5 features). Index 0 is the current bar, index 1 is the previous bar, index 2 is two bars ago. Always check at least two bars to detect crossovers.

The CTrade class handles order execution. It’s cleaner than raw OrderSend() calls and includes built-in error handling.

Test this EA in the Strategy Tester using the same symbol and timeframe as your indicator. The tester runs the EA on historical data. Every time the EA detects a signal, it opens a trade. The report shows whether those trades were profitable.

This is your MT5 indicator backtest EA, the bridge between theory and proof.

Detecting and Preventing MT5 Indicator Repainting Issues

Repainting is the silent killer of backtests. Your indicator looks perfect in testing but fails in live trading. Why? Because it’s changing past values.

An indicator repaints when it recalculates previous bars based on new data. A moving average that uses future bars is repainting. An oscillator that changes yesterday’s value when today’s close comes in is repainting.

Detect repainting:

  • Run a visual backtest and watch the chart closely
  • Look for signals that appear, then disappear, then reappear
  • Compare the indicator values on the chart to the backtest report
  • If they don’t match, you have repainting

Prevent repainting:

  • Use only closed bars in calculations
  • Never reference Close[0] (the current open bar)
  • Always use Close[1] or earlier (closed bars only)
  • Avoid functions that look ahead like iHighest() on the current bar
  • Test with “Every tick” modeling quality to catch repainting early

Here’s a safe approach:

void OnCalculate(int rates_total, int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[])
{
int start = (prev_calculated == 0) ? 0 : prev_calculated – 1;

for(int i = start; i < rates_total – 1; i++)
{
Buffer1[i] = iMA(NULL, 0, FastPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
Buffer2[i] = iMA(NULL, 0, SlowPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
}
}

Frequently Asked Questions

How do you backtest a custom indicator in MT5?

Backtesting a custom indicator requires compiling your MQL5 code into an .ex5 file, then using the MT5 Strategy Tester to load it on historical price data. You select your indicator symbol and timeframe, set test dates, and run the tester in visual mode to observe buy and sell signals across historical bars. The tester replays price action and shows how your indicator would have performed, though indicator-only testing has limitations, signals alone don’t account for order execution, spread costs, or slippage that live trading introduces.

Can you backtest an indicator without an Expert Advisor in MT5?

Yes, you can load a custom indicator directly in the Strategy Tester’s visual mode to observe signals on historical data. However, this shows only the indicator’s visual output, it doesn’t execute trades or measure real performance metrics like win rate, drawdown, or profit factor. For quantitative backtesting that measures actual trading outcomes, you need to wrap your indicator signals inside an Expert Advisor (EA) that reads the indicator’s buffers and executes orders. This EA-based approach gives you reliable performance statistics and accounts for real trading costs.

What is the difference between testing an MT5 indicator and an Expert Advisor?

Indicator testing in visual mode shows you the signals your indicator generates on a historical chart, useful for visual validation but no trade execution. Expert Advisor backtesting actually simulates order placement, fills, and exit logic based on those signals, producing real performance metrics: profit, drawdown, win rate, and profit factor. An EA reads your indicator’s buffers using iCustom() and executes trades with entry and exit rules, giving you realistic performance data. For serious strategy validation, always use an EA-based backtest rather than relying on indicator signals alone.

How can you tell if an MT5 indicator repaints?

Repainting occurs when an indicator changes its previous signal values as new bars form, a major red flag for strategy reliability. To test for repainting, run your indicator in visual mode and observe whether signals on completed bars stay constant as new bars arrive. Use the Strategy Tester’s visual tester to step through bars manually and check if earlier signals shift. Better yet, log indicator values to a file at each bar close and compare them to values recalculated later. Indicators using future data (like close prices before the bar closes) or current bid/ask prices will repaint. Always validate that your indicator’s signals are locked in at bar close, not recalculated afterward.