Profit factor, drawdown, expected payoff, trade count — and how to spot a curve-fit.
Intermediate11 min readBeginner → AdvancedLesson 12 / 17
Try it in MetaEditor
Print the tester's own statistics
Save as MQL5/Scripts/Lesson12TesterStats.mq5. Run it from inside the Strategy Tester (not on a live chart) to dump the key report figures.
//+------------------------------------------------------------------+
//| Lesson 12 - Dump Strategy Tester statistics |
//| Run this FROM INSIDE the Strategy Tester, not on a live chart. |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version "1.00"
void OnStart()
{
if(!MQLInfoInteger(MQL_TESTER))
{
Print("This script only reports inside the Strategy Tester. ");
Print("Open the tester, pick this script, and run it.");
return;
}
Print("========== Strategy Tester report ==========");
Print("Initial deposit: ", DoubleToString(TesterStatistics(STAT_INITIAL_DEPOSIT), 2));
Print("Net profit: ", DoubleToString(TesterStatistics(STAT_PROFIT), 2));
Print("Gross profit: ", DoubleToString(TesterStatistics(STAT_GROSS_PROFIT), 2));
Print("Gross loss: ", DoubleToString(TesterStatistics(STAT_GROSS_LOSS), 2));
Print("Profit factor: ", DoubleToString(TesterStatistics(STAT_PROFIT_FACTOR), 3));
Print("Expected payoff: ", DoubleToString(TesterStatistics(STAT_EXPECTED_PAYOFF), 2));
Print("Recovery factor: ", DoubleToString(TesterStatistics(STAT_RECOVERY_FACTOR), 3));
Print("Sharpe ratio: ", DoubleToString(TesterStatistics(STAT_SHARPE_RATIO), 3));
Print("");
Print("Max drawdown: ", DoubleToString(TesterStatistics(STAT_EQUITY_DD), 2),
" (", DoubleToString(TesterStatistics(STAT_EQUITY_DDREL_PERCENT), 2), "%)");
Print("");
Print("Total trades: ", (int)TesterStatistics(STAT_TRADES));
Print("Win rate: ", DoubleToString(TesterStatistics(STAT_PROFIT_TRADES) /
MathMax(1.0, TesterStatistics(STAT_TRADES)) * 100.0, 1), "%");
Print("Largest win: ", DoubleToString(TesterStatistics(STAT_LARGEST_PROFIT_TRADE), 2));
Print("Largest loss: ", DoubleToString(TesterStatistics(STAT_LARGEST_LOSS_TRADE), 2));
Print("Average bars held: ", DoubleToString(TesterStatistics(STAT_BARS_HOLD_TOTAL) /
MathMax(1.0, TesterStatistics(STAT_TRADES)), 1));
Print("===========================================");
Print("Sanity checks:");
Print(" - Fewer than ~100 trades? Treat every figure above as noise.");
Print(" - Profit factor under 1.2? Costs will likely erase it live.");
Print(" - Equity curve too smooth? Suspect a curve-fit.");
}
To run it
1. Open MetaEditor from MT5 (press F4), and pick the folder this program belongs in — Experts, Indicators, or Scripts.
2. Create a new file, paste this over it, then press F7 to compile. Fix anything the Errors tab reports.
3. Back in MT5, drag it onto a chart — or open the Strategy Tester if it is an Expert Advisor.
Pick the right modelling mode first
The Strategy Tester offers several modes. Every tick based on real ticks is the only one you should trust for intraday CFD systems; the faster modes interpolate and will flatter anything that leans on stop placement. If your broker does not supply real ticks, treat the result as indicative only.
The numbers that matter
Expected payoff — average money per trade after costs. If it is not clearly positive, nothing else saves you.
Profit factor — gross profit divided by gross loss. Above about 1.5 with a decent sample is interesting; below 1.2 is noise territory.
Maximal and relative drawdown — the pain you must survive. Compare it to your account, not to the profit.
Recovery factor — net profit divided by max drawdown. Rewards systems that earn without deep holes.
Trade count — the one beginners skip. Fifty trades tells you almost nothing; a few hundred starts to mean something.
How a curve-fit looks
A curve-fit has a smooth equity curve, a suspiciously high profit factor, and a parameter set sitting on a sharp spike: nudge the period by one and the result collapses. A real effect sits on a plateau — neighbouring parameter values also work, just slightly less well.
Walk forward, always
Split your history. Optimise on the first section, test on the section the optimiser never saw. Then move the window forward and repeat. A system that only performs on the window it was tuned to is not a system; it is a memory.
Costs are not optional
For CFD, commission, swap, and slippage are not rounding errors. A system that makes 40 pips per trade can be unprofitable after overnight swap on a position held for a week. Enter realistic costs in the tester and re-check: if the edge disappears, it was never an edge.
This lesson's script
Run it inside the Strategy Tester and it prints the report's key figures straight into the journal — the same numbers you should be looking at in the Results tab.
What you just did
Lesson 12 of 17 in MetaTrader 5 MQL5 for CFD Traders. When you have run the examples or read the section, tick it off and move to the next lesson.