# MT5-Quant **The MCP server for MT5 strategy development — not live trading.** Most MT5 MCP servers let an AI place orders. MT5-Quant lets an AI *build the strategy*: compile an Expert Advisor, run a backtest, parse the report, analyze every deal, and optimize parameters — all in one conversation, on **macOS or Linux**, without a Windows machine. ``` You: "Run a backtest from Jan to March and tell me what caused the drawdown spike in February" Claude: [compile → clean cache → backtest → parse XML report → analyze 1,847 deals] Worst DD event: Feb 14, BUY grid at L6. Locking hedge placed into a trending adverse move. Locking lot 1.75× base. Cutloss fired 17 price points later. Recommendation: cap locking lot multiplier to ≤1.2× to prevent cascade on adverse trend. ``` ### How MT5-Quant is different | | MT5-Quant | Other MT5 MCPs¹ | QuantConnect MCP | ai-trader | |---|---|---|---|---| | **Backtest via MCP** | ✅ full pipeline | ❌ | ✅ cloud only | ✅ Python only | | **EA optimization via MCP** | ✅ genetic, background | ❌ | ✅ cloud only | ❌ | | **Deal-level analytics** | ✅ 15+ dimensions | ❌ | ❌ | ❌ | | **MQL5 EA compilation** | ✅ | ❌ | ❌ | ❌ | | **macOS + Linux** | ✅ | ❌ Windows only | ❌ cloud | ✅ | | **Headless / CI-CD** | ✅ Xvfb | ❌ | ❌ | ✅ | | **Offline / no subscription** | ✅ | ✅ | ❌ paid cloud | ✅ | | **MT5 .set file tooling** | ✅ 8 tools | ❌ | ❌ | ❌ | | **Backtest history ledger** | ✅ JSON archive | ❌ | ✅ | ❌ | ¹ *ariadng/metatrader-mcp-server, Qoyyuum/mcp-metatrader5-server, Cloudmeru/MetaTrader-5-MCP-Server — all live-trading execution bridges, Windows-only.* ### What it covers 43 MCP tools across the full EA development loop: ``` list_set_files / describe_sweep / patch_set_file / set_from_optimization ↓ prepare parameters compile_ea ↓ build .ex5 run_backtest (compile → clean cache → MT5 tester → extract HTML/XML → analyze deals) ↓ fresh results analyze_report / compare_baseline / get_history ↓ evaluate and record archive_report(delete_after=true) → promote_to_baseline ↓ clean up, lock in new production reference run_optimization (background, nohup — takes hours) ↓ when MT5 finishes get_optimization_results → set_from_optimization → run_backtest (verify) ``` The AI drives every step. You watch and approve. --- ## Quickstart ### Option 1: Download Prebuilt Binary (Recommended) ```bash # macOS (Apple Silicon) curl -L -o mt5-quant.tar.gz https://github.com/masdevid/mt5-mcp/releases/latest/download/mt5-quant-macos-arm64.tar.gz tar -xzf mt5-quant.tar.gz cd mt5-quant-macos-arm64 ./mt5-quant --help # Linux (x64) curl -L -o mt5-quant.tar.gz https://github.com/masdevid/mt5-mcp/releases/latest/download/mt5-quant-linux-x64.tar.gz tar -xzf mt5-quant.tar.gz cd mt5-quant-linux-x64 ./mt5-quant --help ``` ### Option 2: Build from Source ```bash git clone https://github.com/masdevid/mt5-mcp cd mt5-mcp bash scripts/build-rust.sh ``` > **Rust** required. Install from [rustup.rs](https://rustup.rs/) ### 2. Install MetaTrader 5 MT5 runs under Wine on both macOS and Linux. Two supported paths: **macOS — MetaTrader 5.app (recommended, free)** Download from [metatrader5.com](https://www.metatrader5.com/en/download) and install to `/Applications`. Launch it once so it initializes the Wine prefix (~30 s), then quit. Wine binary auto-detected at: ``` /Applications/MetaTrader 5.app/Contents/SharedSupport/wine/bin/wine64 ``` MT5 prefix auto-detected at: ``` ~/Library/Application Support/net.metaquotes.wine.metatrader5/drive_c/Program Files/MetaTrader 5 ``` **macOS — CrossOver (paid, better Wine compatibility)** Install [CrossOver](https://www.codeweavers.com/), create a bottle named `MetaTrader5`, install MT5 inside it. Wine binary: ``` /Applications/CrossOver.app/Contents/SharedSupport/CrossOver/bin/wine64 ``` MT5 prefix (CrossOver 24+): ``` ~/Library/Application Support/MetaQuotes//drive_c/Program Files/MetaTrader 5 ``` > **Apple Silicon (M1/M2/M3):** `setup.sh` automatically prepends `arch -x86_64` to all Wine calls. No manual action needed. **Linux** ```bash sudo apt install wine64 xvfb # Debian/Ubuntu # or sudo dnf install wine xorg-x11-server-Xvfb # Fedora/RHEL # Install MT5 under Wine wine64 MetaTrader5Setup.exe ``` MT5 prefix auto-detected at: ``` ~/.wine/drive_c/Program Files/MetaTrader 5 ``` ### 3. Configure ```bash bash scripts/setup.sh # auto-detects paths and writes config bash scripts/setup.sh --yes # non-interactive (CI / fresh machine) ``` `setup.sh` writes `config/mt5-quant.yaml`. To configure manually, copy the example: ```bash cp config/mt5-quant.example.yaml config/mt5-quant.yaml ``` Minimum required fields: ```yaml # macOS (MetaTrader 5.app) wine_executable: "/Applications/MetaTrader 5.app/Contents/SharedSupport/wine/bin/wine64" terminal_dir: "~/Library/Application Support/net.metaquotes.wine.metatrader5/drive_c/Program Files/MetaTrader 5" # Linux # wine_executable: "/usr/bin/wine64" # terminal_dir: "~/.wine/drive_c/Program Files/MetaTrader 5" ``` ### 4. Register the MCP server ```bash # Add to Claude Code (adjust path to where you cloned the repo) claude mcp add MT5-Quant -- /path/to/mt5-quant/target/release/mt5-quant ``` `setup.sh` runs this automatically. To check registration: ```bash claude mcp list ``` Expected output: ``` MT5-Quant: /path/to/mt5-quant/target/release/mt5-quant ``` **Claude Code integration files** (CLAUDE.md template + baseline hook): ```bash bash scripts/setup.sh --claude-code ``` ### 5. Verify ```bash bash scripts/platform_detect.sh ``` Expected output (macOS): ``` Wine: /Applications/MetaTrader 5.app/Contents/SharedSupport/wine/bin/wine64 MT5 dir: ~/Library/Application Support/net.metaquotes.wine.metatrader5/.../MetaTrader 5 Display: gui Arch: arch -x86_64 ← Apple Silicon only ``` Or from Claude: *"Run verify_setup"* ### 6. Run a backtest ``` Run a backtest on MyEA from 2025.01.01 to 2025.06.30 ``` --- ## Headless Support | Platform | `display.mode` | Notes | |----------|---------------|-------| | macOS (MT5.app or CrossOver) | `auto` | Wine handles display internally — no Xvfb needed | | Linux with `$DISPLAY` set | `auto` | Uses existing X11 session | | Linux VPS / CI (no monitor) | `headless` | Auto-starts Xvfb on `:99` | **Linux headless setup:** ```bash sudo apt install xvfb ``` Then set in `config/mt5-quant.yaml`: ```yaml display: mode: headless xvfb_display: ":99" xvfb_screen: "1024x768x16" ``` `platform_detect.sh` starts Xvfb automatically before each backtest run. To test manually: ```bash Xvfb :99 -screen 0 1024x768x16 & DISPLAY=:99 xdpyinfo | grep dimensions ``` --- ## MCP Tools (43) ### Core workflow | Tool | Description | |------|-------------| | `run_backtest` | Full pipeline: compile → clean → backtest → extract → analyze | | `run_optimization` | Genetic optimization (background, returns immediately) | | `get_optimization_results` | Parse optimization results after MT5 finishes | | `analyze_report` | Read `analysis.json` from any report directory | | `compare_baseline` | Compare report vs baseline, return winner/loser verdict | | `compile_ea` | Compile MQL5 EA via MetaEditor | | `list_experts` | List all EAs in MQL5/Experts directory | | `list_indicators` | List all indicators in MQL5/Indicators directory | | `list_scripts` | List all scripts in MQL5/Scripts directory | | `healthcheck` | Quick server health check | ### Granular Analytics (individual analysis) | Tool | Description | |------|-------------| | `analyze_monthly_pnl` | Monthly P/L breakdown only | | `analyze_drawdown_events` | Drawdown events and causes only | | `analyze_top_losses` | Worst losing deals only | | `analyze_loss_sequences` | Consecutive loss patterns only | | `analyze_position_pairs` | Position hold time and P/L pairs | | `analyze_direction_bias` | Buy vs Sell performance | | `analyze_streaks` | Win/loss streak analysis | | `analyze_concurrent_peak` | Peak simultaneous positions | Use these for targeted analysis, or `analyze_report` to run all at once. ### Monitoring | Tool | Description | |------|-------------| | `verify_setup` | Check Wine/MT5 paths, Wine version, and EA/set file counts | | `get_backtest_status` | Check live progress of a running backtest pipeline | | `get_optimization_status` | Check live state of a background optimization job | | `list_jobs` | All optimization jobs with compact status in one call | ### Reports & logs | Tool | Description | |------|-------------| | `list_reports` | Compact table of all runs with key metrics — no full analysis needed | | `get_latest_report` | Get most recent report with optional equity chart | | `search_reports` | Find reports by EA, symbol, date range, or profit criteria | | `tail_log` | Read last N lines of any log; `filter=errors` to see only failures | | `prune_reports` | Delete old report directories, keep last N (skips `_opt` dirs) | ### History & baseline | Tool | Description | |------|-------------| | `archive_report` | Convert one report dir → compact JSON entry in `backtest_history.json`, optionally delete source | | `archive_all_reports` | Bulk-archive all report dirs then optionally delete them; keeps N newest safe | | `get_history` | Query history with filters (EA, symbol, verdict, profit, DD) and sort options | | `annotate_history` | Attach verdict / notes / tags to any history entry | | `promote_to_baseline` | Write a history entry or report to `baseline.json` for compare_baseline | ### Cache management | Tool | Description | |------|-------------| | `cache_status` | MT5 tester cache size breakdown by symbol — check before cleaning | | `clean_cache` | Delete tester cache files; supports per-symbol and `dry_run` | ### .set file — read / write | Tool | Description | |------|-------------| | `list_set_files` | All .set files in tester profiles dir with sweep stats and combination counts | | `read_set_file` | Parse UTF-16LE `.set` file → structured JSON params | | `write_set_file` | Write full params dict → UTF-16LE `.set` with `chmod 444` | | `patch_set_file` | Update specific params in-place, return diff — replaces read→edit→write | | `clone_set_file` | Copy `.set` to new path with optional overrides in one call | ### .set file — analysis & generation | Tool | Description | |------|-------------| | `describe_sweep` | Swept params, value counts, and total optimization combinations | | `diff_set_files` | Side-by-side diff of two `.set` files — only changed params returned | | `set_from_optimization` | Generate a clean backtest `.set` from `get_optimization_results` params; optionally narrow sweep | Full schema: [docs/MCP_TOOLS.md](docs/MCP_TOOLS.md) --- ## Architecture ``` AI Agent (Claude / Cursor) │ MCP protocol (stdio) MT5-Quant server (Rust) │ subprocess Wine/CrossOver │ MetaTrader 5 (Windows/Wine) │ analysis.json ← AI reads this ``` Every backtest produces `analysis.json` — a stable, AI-readable artifact. The analysis engine is **strategy-agnostic**: a `PROFILES` system drives keyword matching, depth extraction, and cycle grouping so the same pipeline works for any EA type. | Strategy | CLI / entry point | Depth tracking | Exit keywords | Cycle grouping | |----------|------------------|----------------|---------------|----------------| | `grid` (default) | `mt5-analyze-grid` | `Layer #N` → L1–L8+ | locking / cutloss / zombie / timeout | magic + direction, 60 min gap | | `scalper` | `mt5-analyze-scalper` | — | tp / sl / manual / trailing | magic, 10 min gap | | `trend` | `mt5-analyze-trend` | — | tp / sl / trailing / breakeven / partial | magic, 4 h gap | | `hedge` | `mt5-analyze-hedge` | — | tp / sl / net_close / partial | magic + direction, 2 h gap | | `generic` | `mt5-analyze` | — | tp / sl (profit-sign) | magic, 60 min gap | **`analysis.json` fields** (strategy name controls what each field contains): | Field | All strategies | Grid only | |-------|---------------|-----------| | `strategy` | Active profile name | — | | `summary` | KPIs + streaks + cycle win rate + dominant exit | — | | `monthly_pnl` | P/L, trade count, green flag per month | — | | `dd_events` | DD events; `cause` uses profile keywords | Cause = locking_cascade / cutloss / zombie_exit | | `top_losses` | Worst closing deals | `grid_depth_at_close` populated | | `loss_sequences` | Consecutive losing runs | — | | `position_pairs` | Hold time, layer, P/L per closed position | — | | `depth_histogram` | Profile-driven depth counts | L1–L8+ (empty for other strategies) | | `cycle_stats` | Cycle win rate; grouping + gap from profile | win_rate_by_depth populated | | `exit_reason_breakdown` | Profile-specific exit reasons | locking / cutloss / zombie / timeout | | `direction_bias` | Buy vs sell win rate and P/L | — | | `streak_analysis` | Max win/loss streaks, current streak | — | | `session_breakdown` | Asian / London / London-NY / New York P/L | — | | `weekday_pnl` | Mon–Sun P/L and win rate | — | | `concurrent_peak` | Peak simultaneous open positions | — | | `hourly_pnl` | Hour 0–23 (`--deep` only) | — | | `volume_profile` | P/L by lot tier (`--deep` only) | — | This is what makes AI reasoning over backtest results possible — across any EA type. Full architecture: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) --- ## Backtest History Every experiment can be archived into a single JSON ledger at `config/backtest_history.json` — a permanent, queryable record of every run. This lets you delete raw report directories (which can be GBs of tick data) while keeping all results as compact JSON. ``` [workflow] run_backtest → archive_report(delete_after=true) # disk reclaimed ↓ backtest_history.json (grows forever, tiny) ↓ get_history(min_profit=5000, max_dd_pct=15) # query past runs ↓ promote_to_baseline # set new production reference ``` **Files** (both gitignored, live in `config/`): | File | Purpose | |------|---------| | `config/backtest_history.json` | Ledger of all archived backtest runs with full metrics, analysis summary, monthly P/L, and verdict | | `config/baseline.json` | Current production reference — used by `compare_baseline` and the Claude Code hook | Each history entry captures: all `metrics.json` fields + `analysis.json` summary + monthly P/L array + worst DD event. The raw report directory can be safely deleted after archiving. **Typical session:** ``` 1. run_backtest(expert, from, to) 2. archive_report(delete_after=true, verdict="winner", notes="tight SL test") 3. promote_to_baseline() ← if this is the new production config 4. get_history(ea="MyEA", verdict="winner") ← survey all winners later ``` --- ## .set File Workflow ```ini ; param=current||start||step||stop||Y (Y=sweep, N=fixed) Min_Entry_Confidence=0.610||0.580||0.010||0.650||Y TP_Pips=400||300||50||500||Y Max_DD_Percent=15.0||N ``` MT5-Quant handles the undocumented requirements automatically: UTF-16LE encoding, `chmod 444`, OptMode reset, SpreadsheetML XML result parsing. **Common .set patterns:** ``` # Find and inspect list_set_files(ea="MyEA") → see all variants with combination counts describe_sweep(path=MyEA_opt.set) → verify 240 combinations before launching diff_set_files(path_a=v1.2.set, path_b=v1.3.set) → what changed between versions # Edit patch_set_file(path, patches={TP_Pips: 350}) → change one param, keep rest intact clone_set_file(source, dest, overrides={...}) → new variant from a base in one call # Post-optimization get_optimization_results(job_id=X) → results[0].params = {TP:400, Conf:0.61, ...} set_from_optimization( → write clean backtest .set from those params path=MyEA_v1.3.set, params=results[0].params, template=MyEA_base.set → fill non-swept params from existing .set ) ``` --- ## Remote Agents (Linux server farm) Scale optimization throughput by connecting a Linux server as an MT5 agent farm. Linear speedup with agent count. Setup guide: [docs/REMOTE_AGENTS.md](docs/REMOTE_AGENTS.md) --- ## Claude Code Integration `--claude-code` generates two files that make Claude aware of your trading context: ```bash bash scripts/setup.sh --claude-code ``` | File | Purpose | |------|---------| | `config/CLAUDE.template.md` | Copy to your EA project root as `CLAUDE.md`. Encodes MT5-Quant rules, baseline tracking policy, and symbol name reminders. | | `.claude/hooks/user-prompt-submit.sh` | Runs before every Claude prompt. Reads `config/baseline.json` and injects your production metrics as context. | **Production baseline** (`config/baseline.json`, gitignored): ```json { "symbol": "XAUUSD.cent", "period": "2024-01-01/2024-12-31", "net_profit": 1250.50, "profit_factor": 1.43, "max_drawdown_pct": 18.2, "sharpe_ratio": 0.87, "total_trades": 342, "notes": "Best config as of 2024-12-15" } ``` Update this file whenever a new version is promoted to production — either by running `promote_to_baseline` from Claude, or by editing it manually. Every subsequent Claude prompt will automatically include these metrics so Claude can tell you whether a new backtest is actually an improvement without you having to paste the numbers. **Why this matters:** Without the baseline hook, you have to manually remind Claude what the production numbers are at the start of every session. With it, that context is always present. --- ## Troubleshooting Run `verify_setup` from Claude first — it checks all paths and returns actionable hints. ### Wine not found **macOS:** Confirm `/Applications/MetaTrader 5.app` exists and has been launched at least once. If using CrossOver, confirm the bottle is named correctly. ```bash # Check what setup.sh found: bash scripts/platform_detect.sh ``` **Linux:** ```bash sudo apt install wine64 # Debian/Ubuntu sudo dnf install wine # Fedora/RHEL which wine64 # confirm it's on PATH ``` ### terminal64.exe missing MT5 unpacks `terminal64.exe` only after its first launch. Open MetaTrader 5.app, wait for initialization (~30 s), then quit. Re-run setup: ```bash bash scripts/setup.sh --yes ``` ### MCP server not appearing in Claude ```bash claude mcp list # should show MT5-Quant claude mcp remove MT5-Quant # remove stale entry if needed claude mcp add MT5-Quant -- /absolute/path/to/mt5-quant/target/release/mt5-quant ``` Use an **absolute path** — relative paths break when Claude starts from a different working directory. ### Report not found after backtest 1. **Wrong symbol name** — brokers use custom names (`XAUUSDm`, `XAUUSD.cent`). Check `verify_setup` → `experts_dir`, or look in `/history/` for available symbols. 2. **No history data** — open MT5, open the symbol's chart, wait for history to download, then retry. 3. **EA crash at startup** — check `/MQL5/Logs/` for `OnInit` errors. 4. **Date range has no trades** — try a wider range or confirm the symbol was active during that period. ### MetaEditor compile errors Log at `/MQL5/Logs/`. Common causes: - Missing `#include` files — copy dependencies into `Experts/` alongside the `.mq5` - Stale `.ex5` from a different MT5 build — delete it and recompile ### No deals in backtest report - Use `model=0` (every tick) — models 1 and 2 skip intra-bar movement, producing zero deals for grid/martingale EAs - Check the `.set` file has values appropriate for the symbol/broker - Confirm `OnInit()` returns `INIT_SUCCEEDED` (MT5 Journal tab) ### Optimization never finishes / no report ```bash # From Claude: tail_log(job_id=X, filter=errors) get_optimization_status(job_id=X) ``` If MT5 crashed mid-run, open `/terminal.ini` and remove the line containing `OptMode=-1`, then retry. --- ## License MIT --- *Built from battle-tested production infrastructure. Every edge case in the pipeline was hit in production.*