MT5 Batch File Automation: Advanced Backtesting Scripts
Running individual backtests in MT5 Strategy Tester is fine for quick checks. But when you need to test 5 EAs across 10 symbols on 3 timeframes — that's 150 tests. Doing that manually would take days. Batch file automation turns it into a single command.
This guide builds on our MT5 CLI Optimization guide with advanced batch scripting techniques.
Prerequisites
- MetaTrader 5 installed (terminal64.exe)
- At least one compiled EA (.ex5 file)
- Basic familiarity with
.iniconfig files (see our CLI guide)
Project Structure
Organize your automation workspace:
D:\MT5_Automation\
├── Configs\ # Base .ini templates
│ ├── base_backtest.ini
│ └── base_optimize.ini
├── Scripts\ # Batch and Python scripts
│ ├── run_all.bat
│ ├── run_parallel.bat
│ └── parse_results.py
├── Reports\ # Output directory for .htm and .xml
├── Params\ # EA parameter .set files
│ ├── trend_follower.set
│ └── scalper_pro.set
└── Logs\ # Execution logs
Base Config Templates
base_backtest.ini (Single Test)
[Tester]
Expert=MyEAs\__EA_NAME__
ExpertParameters=__PARAM_FILE__
Symbol=__SYMBOL__
Period=__TIMEFRAME__
Deposit=10000
Currency=USD
Leverage=1:100
Model=4
Optimization=0
FromDate=2023.01.01
ToDate=2025.01.01
Report=D:\MT5_Automation\Reports\__REPORT_NAME__
ReplaceReport=1
ShutdownTerminal=1
UseLocal=1
Visual=0
Port=__PORT__
base_optimize.ini (Optimization)
[Tester]
Expert=MyEAs\__EA_NAME__
ExpertParameters=__PARAM_FILE__
Symbol=__SYMBOL__
Period=__TIMEFRAME__
Deposit=10000
Currency=USD
Leverage=1:100
Model=4
Optimization=2
OptimizationCriterion=5
FromDate=2023.01.01
ToDate=2025.01.01
ForwardMode=2
Report=D:\MT5_Automation\Reports\__REPORT_NAME__
ReplaceReport=1
ShutdownTerminal=1
UseLocal=1
UseCloud=0
Visual=0
Port=__PORT__
Advanced Batch Scripts
1. Sequential Multi-EA Testing
@echo off
setlocal enabledelayedexpansion
set MT5="C:\Program Files\MetaTrader 5\terminal64.exe"
set BASE_DIR=D:\MT5_Automation
set CONFIG_DIR=%BASE_DIR%\Configs
set REPORT_DIR=%BASE_DIR%\Reports
set LOG_DIR=%BASE_DIR%\Logs
:: Define test matrix
set EAS=TrendFollower GridMaster ScalperPro BreakoutHunter
set SYMBOLS=EURUSD GBPUSD USDJPY AUDUSD USDCAD
set TIMEFRAMES=M15 H1 H4
set PORT=2000
set TOTAL=0
set PASSED=0
set FAILED=0
for %%E in (%EAS%) do (
for %%S in (%SYMBOLS%) do (
for %%T in (%TIMEFRAMES%) do (
set /a TOTAL+=1
set REPORT_NAME=%%E_%%S_%%T
set CONFIG_OUT=%CONFIG_DIR%\run_!REPORT_NAME!.ini
:: Generate config from template
powershell -Command "(Get-Content %CONFIG_DIR%\base_backtest.ini) `
-replace '__EA_NAME__', '%%E' `
-replace '__PARAM_FILE__', '%%E.set' `
-replace '__SYMBOL__', '%%S' `
-replace '__TIMEFRAME__', '%%T' `
-replace '__REPORT_NAME__', '!REPORT_NAME!' `
-replace '__PORT__', '!PORT!' `
| Set-Content '!CONFIG_OUT!'"
echo [!TOTAL!] Testing %%E on %%S %%T ...
:: Run test with timeout (1 hour max)
%MT5% /config:"!CONFIG_OUT!" 2>%LOG_DIR%\!REPORT_NAME!.log
if exist "%REPORT_DIR%\!REPORT_NAME!.htm" (
echo ✓ Report generated
set /a PASSED+=1
) else (
echo ✗ No report found
set /a FAILED+=1
)
set /a PORT+=1
)
)
)
echo.
echo ==========================================
echo Results: %PASSED%/%TOTAL% passed, %FAILED% failed
echo Reports: %REPORT_DIR%
echo ==========================================
2. Parallel Optimization (4 Agents)
@echo off
set MT5="C:\Program Files\MetaTrader 5\terminal64.exe"
set CONFIG_DIR=D:\MT5_Automation\Configs
:: Launch 4 parallel optimizations
start "MT5-EURUSD" %MT5% /config:%CONFIG_DIR%\optimize_eurusd.ini /port:2000
start "MT5-GBPUSD" %MT5% /config:%CONFIG_DIR%\optimize_gbpusd.ini /port:2001
start "MT5-USDJPY" %MT5% /config:%CONFIG_DIR%\optimize_usdjpy.ini /port:2002
start "MT5-AUDUSD" %MT5% /config:%CONFIG_DIR%\optimize_audusd.ini /port:2003
echo 4 parallel optimizations launched.
echo Waiting for all to complete...
:: Wait for all MT5 instances to close
:waitloop
tasklist /fi "imagename eq terminal64.exe" | find "terminal64.exe" >nul
if %errorlevel%==0 (
timeout /t 10 /nobreak >nul
goto waitloop
)
echo All optimizations complete!
python D:\MT5_Automation\Scripts\parse_results.py
3. PowerShell Script (More Powerful)
# run_optimizations.ps1
$MT5 = "C:\Program Files\MetaTrader 5\terminal64.exe"
$ConfigDir = "D:\MT5_Automation\Configs"
$ReportDir = "D:\MT5_Automation\Reports"
$TestMatrix = @(
@{ EA = "TrendFollower"; Symbol = "EURUSD"; TF = "H1"; Port = 2000 }
@{ EA = "TrendFollower"; Symbol = "GBPUSD"; TF = "H1"; Port = 2001 }
@{ EA = "GridMaster"; Symbol = "EURUSD"; TF = "M15"; Port = 2002 }
@{ EA = "GridMaster"; Symbol = "USDJPY"; TF = "H4"; Port = 2003 }
)
foreach ($test in $TestMatrix) {
$configFile = Join-Path $ConfigDir "base_optimize.ini"
$outputConfig = Join-Path $ConfigDir "run_$($test.EA)_$($test.Symbol)_$($test.TF).ini"
# Generate config
$content = Get-Content $configFile
$content = $content -replace '__EA_NAME__', $test.EA
$content = $content -replace '__SYMBOL__', $test.Symbol
$content = $content -replace '__TIMEFRAME__', $test.TF
$content = $content -replace '__PORT__', $test.Port
$content | Set-Content $outputConfig
Write-Host "Starting $($test.EA) on $($test.Symbol) $($test.TF)..."
# Run in background
Start-Process -FilePath $MT5 -ArgumentList "/config:$outputConfig" -Wait
}
Write-Host "All optimizations complete!"
Python Results Parser
#!/usr/bin/env python3
"""Parse all MT5 backtest/optimization reports in a directory."""
import os
import glob
import xml.etree.ElementTree as ET
import pandas as pd
from datetime import datetime
def parse_backtest_htm(htm_path):
"""Parse single backtest .htm report using regex."""
import re
with open(htm_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Extract key metrics from HTML tables
metrics = {}
patterns = {
'total_net_profit': r'Total Net Profit[^0-9-]*([\d.,-]+)',
'profit_factor': r'Profit Factor[^0-9.]*([\d.]+)',
'max_drawdown': r'Equity Drawdown Max[^0-9.%]*([\d.]+)%?',
'total_trades': r'Total Trades[^0-9]*([\d]+)',
'sharpe_ratio': r'Sharpe Ratio[^0-9.-]*([\d.-]+)',
}
for key, pattern in patterns.items():
match = re.search(pattern, content)
if match:
val = match.group(1).replace(',', '').replace(' ', '')
try:
metrics[key] = float(val)
except ValueError:
metrics[key] = val
return metrics
def parse_optimization_xml(xml_path):
"""Parse optimization .xml report into DataFrame."""
tree = ET.parse(xml_path)
root = tree.getroot()
results = []
for item in root.findall('.//Item'):
row = {
'pass': int(item.get('Pass', 0)),
'profit': float(item.findtext('Profit', 0)),
'profit_factor': float(item.findtext('ProfitFactor', 0)),
'drawdown_pct': float(item.findtext('EquityDrawdown', 0)),
'sharpe': float(item.findtext('SharpeRatio', 0)),
'sortino': float(item.findtext('SortinoRatio', 0)),
'trades': int(item.findtext('TotalTrades', 0)),
'win_rate': float(item.findtext('WinRate', 0)),
'expected_payoff': float(item.findtext('ExpectedPayoff', 0)),
}
for inp in item.findall('.//Input'):
row[f'inp_{inp.get("Name")}'] = float(inp.text)
results.append(row)
return pd.DataFrame(results)
def analyze_all_reports(report_dir):
"""Parse all XML reports and combine into summary."""
all_dfs = []
for xml_file in glob.glob(os.path.join(report_dir, '*.xml')):
try:
df = parse_optimization_xml(xml_file)
df['source'] = os.path.basename(xml_file)
all_dfs.append(df)
except Exception as e:
print(f"Error parsing {xml_file}: {e}")
if not all_dfs:
print("No XML reports found!")
return None
combined = pd.concat(all_dfs, ignore_index=True)
# Quality filters
filtered = combined[
(combined['profit'] > 0) &
(combined['trades'] >= 50) &
(combined['drawdown_pct'] < 25) &
(combined['profit_factor'] > 1.2) &
(combined['sharpe'] > 0.5)
].sort_values('sharpe', ascending=False)
print(f"\n{'='*60}")
print(f"Total optimization passes: {len(combined)}")
print(f"Passing quality filters: {len(filtered)}")
print(f"{'='*60}\n")
if len(filtered) > 0:
print("Top 10 by Sharpe Ratio:")
print(filtered.head(10)[['source', 'profit', 'sharpe', 'drawdown_pct', 'trades', 'profit_factor']].to_string())
# Save to CSV
output_path = os.path.join(report_dir, f'analysis_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv')
filtered.to_csv(output_path, index=False)
print(f"\nFull results saved to: {output_path}")
return filtered
if __name__ == '__main__':
report_dir = r'D:\MT5_Automation\Reports'
analyze_all_reports(report_dir)
CI/CD Integration
GitHub Actions Example
name: EA Optimization CI
on:
push:
paths:
- 'eas/**'
- 'configs/**'
schedule:
- cron: '0 2 * * 0' # Weekly Sunday 2AM
jobs:
optimize:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install MT5
run: |
choco install metatrader5 -y
- name: Run Optimizations
run: |
./scripts/run_all.bat
- name: Parse Results
run: python ./scripts/parse_results.py
- name: Upload Reports
uses: actions/upload-artifact@v4
with:
name: optimization-reports
path: ./Reports/
IDE Integration for Batch Workflows
When running batch optimizations, you can integrate the workflow into your IDE:
VS Code: Run Batch Optimization as a Task
Add to .vscode/tasks.json:
{
"label": "Batch Optimize All EAs",
"type": "shell",
"command": "D:\\MT5_Automation\\Scripts\\run_all.bat",
"group": {"kind": "build", "isDefault": true},
"problemMatcher": []
}
Windsurf / Cursor: AI-Driven Batch Optimization
In AI-powered IDEs, you can ask the AI to manage the entire batch workflow:
"Read all .mq5 files in my EAs folder, compile each one with MetaEditor, then run optimization for each across EURUSD, GBPUSD, and USDJPY on H1 and H4. Parse all XML results and create a summary table showing the best parameters for each EA."
The AI will:
- List all
.mq5files in your Experts folder - Call
metaeditor64.exe /compilefor each - Generate
.iniconfigs for each EA/symbol/timeframe combination - Run
terminal64.exe /config:sequentially or in parallel - Parse all
.xmlreports with Python - Present a summary table with the best parameters
Git-Based EA Version Control
Store your EAs and configs in a Git repository for reproducibility:
my-ea-project/
├── EAs/
│ ├── TrendFollower.mq5
│ ├── GridMaster.mq5
│ └── ScalperPro.mq5
├── Configs/
│ ├── base_optimize.ini
│ └── base_backtest.ini
├── Params/
│ ├── trend_follower.set
│ └── grid_master.set
├── Scripts/
│ ├── run_all.bat
│ ├── run_parallel.bat
│ └── parse_results.py
└── Reports/ # .gitignore this folder
This way, every optimization run is reproducible from the repo. You can tag releases (e.g., v1.2-best-sharpe) and track which parameters produced the best results.
Windows Task Scheduler
Run optimizations automatically on a schedule:
Using Task Scheduler GUI
- Open Task Scheduler → Create Task
- Triggers → New → Weekly → Sunday 2:00 AM
- Actions → New → Start a program →
D:\MT5_Automation\Scripts\run_all.bat - Conditions → Start only if computer is idle for 10 minutes
- Settings → Run task as soon as possible after a scheduled start is missed
Using PowerShell (Command Line)
# Create a scheduled task for weekly optimization
$action = New-ScheduledTaskAction -Execute "D:\MT5_Automation\Scripts\run_all.bat"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 2am
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "MT5_Weekly_Optimization" `
-Action $action -Trigger $trigger -Settings $settings `
-Description "Weekly MT5 EA optimization across all symbols and timeframes"
Using schtasks (Command Line)
schtasks /create /tn "MT5_Weekly_Optimization" `
/tr "D:\MT5_Automation\Scripts\run_all.bat" `
/sc weekly /d SUN /st 02:00 /f
Common Issues & Solutions
| Problem | Solution |
|---|---|
| MT5 closes immediately | Check config file encoding (must be ANSI/UTF-8 without BOM) |
| No report generated | Ensure Report= path has write permissions |
| Agent port conflict | Use unique Port= values for parallel runs |
| Optimization too slow | Switch from Optimization=1 to Optimization=2 (genetic) |
| EA not found | Check Expert= path is relative to MQL5\Experts |
| Login fails | Remove Login= line or use valid credentials |
| .set file not found | Check ExpertParameters= path is in MQL5\\Profiles\\Tester\\ |
| Compilation produces no .ex5 | Check .log file for MQL5 syntax errors |
| Optimization results empty | Ensure .set file has Y flags on parameters to optimize |
FAQ
How many parallel optimizations can I run?
It depends on your CPU cores. Each MT5 agent uses one core. If you have an 8-core CPU, you can run 4-6 parallel optimizations (leave 2 cores for the OS). Use different Port= values for each instance.
Can I run batch automation on a VPS?
Yes. A Windows VPS is ideal for batch optimization — it runs 24/7, doesn't interrupt your work, and can be configured with Task Scheduler. Choose a VPS with at least 4 CPU cores and 8GB RAM.
How do I handle different EA versions?
Use Git for version control. Tag each release (e.g., v1.0-stable, v1.1-better-risk). Store .set files and .ini configs alongside the EA source. This makes every optimization run reproducible.
What if my optimization produces thousands of results?
Use the Python parser with quality filters: profit > 0, trades >= 50, drawdown < 25%, sharpe > 0.5. This typically narrows thousands of passes down to 10-50 viable parameter sets. Then manually review the top 10.
Can I automate the entire pipeline (compile → optimize → deploy)?
Yes. Create a master script that: (1) compiles the EA, (2) runs optimization, (3) parses results, (4) selects best parameters, (5) copies the best .set file to the live EA folder. See our CLI Optimization guide for the Python MT5Optimizer class that handles steps 1-3.
Related Guides
- MT5 Vibe Coding: AI-Assisted EA Optimization — Full AI IDE workflow from prompt to backtest
- MT5 Optimization CLI Automation — Config file reference
- MT5 EA Backtesting Tutorial — Manual backtesting
- AI Forex Trading with Python & ONNX — ML for EAs
- Python Forex Trading Tutorial — Python + MT5
- Best Forex EA 2026 — Top trading robots
Affiliate Disclosure: This page contains affiliate links. We may earn a commission when you click on certain links or sign up with brokers featured on this site, at no additional cost to you. Our reviews and recommendations are based on thorough research and remain unbiased.Learn more
Risk Warning: Trading forex and CFDs involves significant risk of loss. Past performance is not indicative of future results. CFDs are complex instruments and come with a high risk of losing money rapidly due to leverage. Ensure you understand the risks before trading. This content is for educational purposes only and does not constitute financial advice.
Pips Growth Team
Trading Education & Research Team
The Pips Growth Team is a group of experienced traders, financial analysts, and trading educators dedicated to providing accurate, actionable forex education. Our team combines decades of hands-on market experience with deep technical knowledge to create comprehensive guides, honest broker reviews, and proven trading strategies. Every article is thoroughly researched, fact-checked, and reviewed by multiple team members to ensure the highest quality and accuracy.