# MT5 EA Optimizer β€” Full Project Handoff Document **Last Updated:** 2026-04-13 **Status:** βœ… Phase 1 (Backend Engine) + βœ… Phase 2 (Live Web Dashboard) β€” BOTH COMPLETE **GitHub:** https://github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer **Primary EA:** LEGSTECH_EA_V2 | Symbol: XAUUSD | Timeframe: H1 | Broker TZ: UTC+2 --- ## 🎯 Project Goal Build an automated, iterative backtesting and analysis system for MT5 Expert Advisors. It is NOT a trading bot. It is an **optimization engine** that: - Runs MT5 strategy tester automatically with different parameter sets - Extracts rich trade-level data (MAE/MFE) after each run - Analyzes results to find failure patterns using statistical methods - Proposes and tests parameter mutations based on findings - Validates improvements before accepting them (IS β†’ WFV β†’ OOS) - Prevents overfitting via Walk-Forward + Out-of-Sample testing - Displays everything live in a beautiful browser dashboard - Writes human-readable reports to a visible `Reports\` folder **End user:** Traders (non-technical). Double-click app, no terminal needed. --- ## πŸ—οΈ Architecture Overview ``` [Trader double-clicks "Launch Optimizer.bat"] ↓ [Browser auto-opens http://localhost:5000] ↓ [Flask + SocketIO Dashboard] ↓ [Trader clicks β–Ά Start] ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ OPTIMIZATION LOOP β”‚ β”‚ β”‚ β”‚ 1. Kill any running MT5 process (psutil) β”‚ β”‚ 2. Clear stale report files β”‚ β”‚ 3. Validate environment (EA exists, paths valid) β”‚ β”‚ 4. Build INI file (Period=H1, Report=relative) β”‚ β”‚ 5. Launch fresh MT5 via subprocess /config: β”‚ β”‚ 6. Wait 10s for data readiness β”‚ β”‚ 7. Poll MT5 appdata root for Optimizer_*.htm β”‚ β”‚ 8. Parse report (UTF-16 LE HTML β†’ metrics+trades) β”‚ β”‚ 9. Run 4 analyzers on trade data β”‚ β”‚ 10. Score composite (Calmar-primary) β”‚ β”‚ 11. Mutate parameters β†’ Hypotheses β”‚ β”‚ 12. Test each hypothesis (steps 1-10 repeated) β”‚ β”‚ 13. Validate: IS check β†’ WFV β†’ promote candidate β”‚ β”‚ 14. Write Reports\run_XXX\ (HTML + CSV + JSON) β”‚ β”‚ 15. Repeat until converged or max_iterations β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ [Dashboard updates live via WebSocket events] [Reports\ folder has all results] ``` --- ## πŸ“ Complete File Structure ``` C:\Users\DELL\Desktop\MT5_Optimizer\ β”‚ β”œβ”€β”€ app.py ← Flask + SocketIO app entry point β”‚ Auto-opens browser at localhost:5000 β”‚ Routes: /, /api/start, /api/pause, β”‚ /api/stop, /api/skip, /reports β”‚ β”œβ”€β”€ optimizer_loop.py ← Background thread: full optimization pipeline β”‚ Emits SocketIO events for every phase/run/finding β”‚ β”œβ”€β”€ config.yaml ← ALL settings (see section below) β”œβ”€β”€ requirements.txt ← Python dependencies β”œβ”€β”€ PROJECT_HANDOFF.md ← THIS DOCUMENT β”œβ”€β”€ "Launch Optimizer.bat" ← Double-click to start (opens browser automatically) β”‚ Uses Python 3.11 at hardcoded path β”‚ β”œβ”€β”€ mql5/ β”‚ └── TradeLogger.mqh ← MQL5 include: per-trade MAE/MFE logger β”‚ DEPLOYED to: ...Terminal\...\MQL5\Include\ β”‚ INTEGRATED in: LEGSTECH_EA_V2.mq5 via TL_OnTick() β”‚ β”œβ”€β”€ data/ β”‚ β”œβ”€β”€ models.py ← Pydantic v2: Trade, RunMetrics, Run, Finding, β”‚ β”‚ Hypothesis, Candidate, RunResult β”‚ └── store.py ← DataStore: SQLite metadata + Parquet trade arrays β”‚ β”œβ”€β”€ mt5/ β”‚ β”œβ”€β”€ ini_builder.py ← Builds MT5 tester .ini files β”‚ β”‚ CRITICAL: Period=H1 (string), Report=relative name β”‚ β”‚ Model=4 (OHLC M1), ShutdownTerminal=1 β”‚ β”œβ”€β”€ runner.py ← Full MT5 process control: β”‚ β”‚ kill_mt5() β†’ clear_stale() β†’ validate() β†’ β”‚ β”‚ launch() β†’ wait_data() β†’ poll_report() β†’ retry β”‚ β”‚ Report location: appdata_path\ root (NOT /reports/) β”‚ β”œβ”€β”€ report_parser.py ← Parses MT5 HTML report β”‚ β”‚ CRITICAL: MT5 reports are UTF-16 LE encoded! β”‚ β”‚ Uses lhtml.document_fromstring(raw_bytes) β”‚ β”‚ Pairs in/out deals β†’ complete Trade objects β”‚ └── log_reader.py ← Merges TradeLogger CSV (MAE/MFE) into trades β”‚ β”œβ”€β”€ analysis/ β”‚ β”œβ”€β”€ base.py ← BaseAnalyzer ABC + statistical helpers β”‚ β”œβ”€β”€ reversal.py ← Trades that went to MFE then reversed (permutation test) β”‚ β”œβ”€β”€ time_performance.py ← Bad sessions/hours/days (Z-score) β”‚ β”œβ”€β”€ entry_exit_quality.py ← MAE/MFE quality matrix (4-case diagnosis) β”‚ └── equity_curve.py ← Flatness, loss clusters, RΒ² of equity curve β”‚ β”œβ”€β”€ scoring/ β”‚ └── composite.py ← Weighted scorer: Calmar(35%) + PF(20%) + β”‚ MFE capture(20%) + stability(15%) + recovery(10%) β”‚ β”œβ”€β”€ mutation/ β”‚ β”œβ”€β”€ engine.py ← Findings β†’ Hypothesis objects (dedup, cascade) β”‚ β”œβ”€β”€ knowledge_base.yaml ← 13 rules: finding_type β†’ param_delta β”‚ └── param_manifest.yaml ← Full EA parameter space: types, bounds, defaults β”‚ β”œβ”€β”€ validation/ β”‚ └── gate.py ← IS check β†’ Walk-Forward (2 folds) β†’ OOS β”‚ β”œβ”€β”€ reports/ β”‚ └── writer.py ← Writes per-run: summary.json, summary.html, β”‚ trades.csv, findings.csv, parameters.json β”‚ β”œβ”€β”€ ui/ β”‚ β”œβ”€β”€ templates/ β”‚ β”‚ β”œβ”€β”€ index.html ← Live dashboard (dark premium design) β”‚ β”‚ β”œβ”€β”€ report.html ← Per-run report template β”‚ β”‚ └── reports_index.html ← Reports browser page (card grid) β”‚ └── static/ β”‚ β”œβ”€β”€ css/style.css ← Full dark theme CSS (glassmorphism, animations) β”‚ └── js/dashboard.js ← SocketIO events + Chart.js + live metrics β”‚ β”œβ”€β”€ tests/ β”‚ └── test_analyzers.py ← 10 unit tests (all passing βœ…) β”‚ └── runs/ ← Generated INI + local run folders (gitignored) └── baseline_YYYYMMDD_.../ └── run.ini ``` --- ## βš™οΈ Configuration (config.yaml) ```yaml ea: name: "LEGSTECH_EA_V2" file: "LEGSTECH_EA_V2" # no extension β€” MT5 adds .ex5 symbol: "XAUUSD" timeframe: "H1" periods: train_start: "2022.01.01" train_end: "2023.12.31" validate_start: "2024.01.01" validate_end: "2024.06.30" oos_start: "2024.07.01" # SACRED β€” never optimize against this oos_end: "2024.12.31" mt5: terminal_exe: "C:/Program Files/MetaTrader 5/terminal64.exe" appdata_path: "C:/Users/DELL/AppData/Roaming/MetaQuotes/Terminal/D0E8209F77C8CF37AD8BF550E51FF075" mql5_files_path: "C:/Users/DELL/AppData/Roaming/MetaQuotes/Tester/D0E8209F77C8CF37AD8BF550E51FF075/Agent-127.0.0.1-3000/MQL5/Files" tester_model: 4 # 4=OHLC M1 (fast). 0=Every Tick (slow, needs tick data) tester_timeout_seconds: 1800 shutdown_terminal: 1 # MT5 closes itself after each test data_readiness_wait_seconds: 10 kill_on_start: true # Always kill existing MT5 before each run broker: timezone_offset_hours: 2 # UTC+2 (HFMarkets) deposit: 10000.0 currency: "USD" leverage: 100 ``` --- ## βœ… What Is Complete ### Phase 1 β€” Backend Engine | Component | Status | Notes | |---|---|---| | TradeLogger.mqh | βœ… Deployed | In MT5 Include folder, integrated in EA | | data/models.py | βœ… | All Pydantic v2 models | | data/store.py | βœ… | SQLite + Parquet | | mt5/ini_builder.py | βœ… | Period=H1 string, relative Report path | | mt5/runner.py | βœ… | Killβ†’validateβ†’launchβ†’waitβ†’pollβ†’retry | | mt5/report_parser.py | βœ… | UTF-16 LE HTML, pairs 597 trades | | mt5/log_reader.py | βœ… | MAE/MFE merge + session labelling | | analysis/reversal.py | βœ… | Permutation-tested | | analysis/time_performance.py | βœ… | Z-score per hour/session/day | | analysis/entry_exit_quality.py | βœ… | 4-case diagnosis matrix | | analysis/equity_curve.py | βœ… | Flatness + RΒ² + loss clusters | | scoring/composite.py | βœ… | Calmar-primary (0-1 score) | | mutation/engine.py | βœ… | 13 KB rules, dedup, cascade | | validation/gate.py | βœ… | IS β†’ WFV β†’ OOS β†’ sensitivity | | tests/ | βœ… 10/10 | Pure Python, no MT5 needed | ### Phase 2 β€” Live Web Dashboard | Component | Status | Notes | |---|---|---| | app.py | βœ… | Flask + SocketIO, all API routes | | optimizer_loop.py | βœ… | Background thread, live event emitter | | ui/templates/index.html | βœ… | Score chart, metrics, findings, log, candidates | | ui/templates/report.html | βœ… | Per-run full report with trade table | | ui/templates/reports_index.html | βœ… | Card grid browser page | | ui/static/css/style.css | βœ… | Premium dark theme | | ui/static/js/dashboard.js | βœ… | SocketIO + Chart.js + live updates | | reports/writer.py | βœ… | HTML + CSV + JSON per run | | Launch Optimizer.bat | βœ… | Double-click launcher | | GitHub | βœ… | https://github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer | --- ## πŸ› Critical Bugs Found & Fixed (Important for Future AI) ### 1. MT5 Report Encoding β€” UTF-16 LE **Problem:** MT5 HTML reports (`.htm`) are UTF-16 LE encoded (BOM: `\xFF\xFE`). Standard `decode('utf-8')` silently failed, lxml returned a single `

` element. **Fix:** Detect BOM and use `lhtml.document_fromstring(raw_bytes)` directly. ```python if raw[:2] == b'\xff\xfe': tree = lhtml.document_fromstring(raw) # handles UTF-16 internally ``` ### 2. MT5 Report Location **Problem:** Runner was looking in `appdata_path/reports/` β€” folder doesn't exist. **Reality:** MT5 writes reports to the **root** of `appdata_path\` directly. ``` C:\Users\DELL\AppData\Roaming\MetaQuotes\Terminal\D0E8209F...\Optimizer_baseline_*.htm ``` **Fix:** `self.mt5_reports_dir = self.appdata_path` (not `/ "reports"`) ### 3. INI Period Format **Problem:** Code used `Period=16385` (ENUM integer) β€” MT5 CLI ignores this. **Fix:** `Period=H1` (string name). `TIMEFRAME_NAMES = {"H1": "H1", ...}` ### 4. INI Report Path **Problem:** `Report=C:/absolute/path/...` β€” MT5 ignores absolute paths in CLI mode. **Fix:** `Report=Optimizer_{run_id}` (relative name only β€” MT5 writes to appdata root). ### 5. MQL5 Reference Syntax **Problem:** `TL_Positions[idx]&.fieldname` β€” C++ reference syntax, invalid in MQL5. **Fix:** `TL_Positions[idx].fieldname` β€” direct array index access. ### 6. Stale Report Detection **Problem:** Old `Optimizer_*.htm` files from previous runs triggered false-positive detection. **Fix:** `_clear_stale_reports()` deletes old files before each new run. --- ## πŸ–₯️ How to Run (For Any User) ### Prerequisites 1. MT5 installed at `C:\Program Files\MetaTrader 5\terminal64.exe` 2. LEGSTECH_EA_V2 compiled in MetaEditor (`.ex5` file must exist) 3. Python 3.11 installed at `C:\Users\DELL\AppData\Local\Programs\Python\Python311\` 4. Dependencies installed: `python.exe -m pip install -r requirements.txt` ### Starting the App 1. **Close MT5** if it's open (the optimizer kills and relaunches it automatically from the next run, but first run needs it clean) 2. **Double-click** `Launch Optimizer.bat` on Desktop 3. Browser opens at `http://localhost:5000` 4. Click **β–Ά Start Optimizer** 5. Watch it run live β€” MT5 launches automatically, results appear in real-time 6. Reports saved to `MT5_Optimizer\Reports\run_XXX\` ### Save Changes to GitHub ```powershell cd "C:\Users\DELL\Desktop\MT5_Optimizer" git add . git commit -m "describe what changed" git push ``` --- ## πŸ”§ Environment Details | Item | Value | |---|---| | Python | 3.11 β€” `C:\Users\DELL\AppData\Local\Programs\Python\Python311\python.exe` | | GitHub | https://github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer | | MT5 Terminal ID | `D0E8209F77C8CF37AD8BF550E51FF075` | | MT5 Broker | HFMarketsGlobal-Live3 (Build 5660) | | Tester Agent | `Agent-127.0.0.1-3000` | | OS | Windows 11 | **Install all dependencies:** ```powershell C:\Users\DELL\AppData\Local\Programs\Python\Python311\python.exe -m pip install -r requirements.txt ``` **Key dependencies:** ``` flask, flask-socketio, eventlet ← Web dashboard pydantic>=2.5, pandas>=2.1, pyarrow ← Data layer lxml>=4.9, beautifulsoup4 ← Report parsing psutil ← MT5 process control loguru, rich, scipy, pyyaml ← Utilities ``` --- ## 🧠 Key Design Decisions 1. **Hypothesis-driven, not brute-force** β€” Detect failure patterns β†’ hypothesize fix β†’ test β†’ validate. Not grid search. 2. **Calmar ratio = primary score** β€” Return/MaxDrawdown most relevant for live trading. 3. **Three validation gates** β€” IS β†’ WFV (2 folds) β†’ OOS. No candidate promoted unless all pass. 4. **OOS is sacred** β€” `2024.07.01 β†’ 2024.12.31` is NEVER used during optimization. Final check only. 5. **MT5 process control** β€” Always kill existing instance, launch clean, retry once on failure. 6. **UTF-16 LE** β€” ALL MT5 HTML reports are UTF-16 LE. Always use `document_fromstring(raw_bytes)`. 7. **Report location** β€” Always `appdata_path\Optimizer_{run_id}.htm` (root, not subfolder). 8. **Python 3.11 required** β€” System Python on this machine is 3.13 which is missing packages. 9. **Broker TZ = UTC+2** β€” Session analysis normalizes to UTC. London=07-16, NY=13-22. --- ## πŸ“‹ Live Dashboard Events (SocketIO) The optimizer emits these events to the browser in real-time: | Event | Payload | When | |---|---|---| | `status_change` | `{state, phase}` | Phase transitions | | `run_started` | `{run_id, phase, period, params}` | MT5 launches | | `run_complete` | `{score, calmar, pf, dd, trades, ...}` | Report parsed | | `run_failed` | `{run_id, error}` | MT5 failed | | `finding` | `{analyzer, severity, description, confidence}` | Each finding | | `hypotheses` | `{items: [{id, desc, delta}]}` | Mutations proposed | | `score_update` | `{iteration, score, calmar, pf}` | Chart data point | | `candidate_promoted` | `{score, delta, params}` | Validation passed | | `optimization_complete` | `{candidates, best_score, iterations}` | Loop done | | `log` | `{level, msg}` | Live log feed | --- ## πŸš€ Next Steps (Phase 3 β€” Packaging) 1. **PyInstaller EXE** β€” Bundle everything into `MT5_Optimizer.exe` ```bat pyinstaller --onefile --noconsole --name MT5_Optimizer app.py ``` Note: Need `--add-data` flags for templates, static, config, yaml files 2. **Auto `.set` file export** β€” When a candidate is promoted, export its params as a valid MT5 `.set` file the trader can load directly into the EA 3. **Email/Telegram notification** β€” Alert the trader when a candidate is promoted 4. **Multi-symbol support** β€” Run optimization across EURUSD, GBPUSD alongside XAUUSD 5. **Monte Carlo simulation** β€” Test robustness of promoted candidates --- ## ⚠️ Known Issues & Watch Points 1. **First run needs MT5 closed manually** β€” From the second run onward, the system kills MT5 automatically via psutil. 2. **Tester Agent path** β€” `Agent-127.0.0.1-3000` may change if MT5 port changes. If TradeLog CSV not found, check Tester folder for new agent subfolder. 3. **WFV fold count** β€” Currently 2 folds (hardcoded in `validation/gate.py`). Easy to increase. 4. **XAUUSD data** β€” If the date range 2022-2023 gives errors, ensure XAUUSD H1 history is downloaded in MT5 (Tools β†’ History Center). 5. **Model 4 vs 0** β€” `tester_model: 4` (OHLC M1) is fast and reliable. `tester_model: 0` (Every Tick) is more accurate but requires full tick data download and takes ~10x longer. 6. **ShutdownTerminal=1** β€” MT5 closes itself after each test. Cannot be used for live trading simultaneously. --- ## πŸ“Š Baseline Run Results (Confirmed Working) First successful parser test on real MT5 report (2026-04-13): | Metric | Value | |---|---| | Net Profit | -$621.15 | | Profit Factor | 0.95 | | Max Drawdown | 19.25% | | Calmar Ratio | -0.32 | | Sharpe Ratio | -1.60 | | Total Trades | 597 | | Win Rate | 77.7% | | Test Period | 2022.01.01 β†’ 2023.12.31 | | Model | OHLC M1 (Model 4) | | Duration | ~56 seconds | > This is the baseline β€” the optimizer's job is to improve these numbers over iterations. --- *Last updated by Antigravity AI β€” 2026-04-13* *GitHub: https://github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer* *Both Phase 1 and Phase 2 are complete. Continue from Phase 3 (packaging).*