From c4b5fe0ad0b9f2fb944920fc1a62667bb4a00829 Mon Sep 17 00:00:00 2001 From: LEGSTECH Optimizer Date: Mon, 13 Apr 2026 20:08:39 +0000 Subject: [PATCH] fix: restore ea: bridge in config + wire optimizer_loop to EARegistry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: Removing ea: from config.yaml broke 4 call sites in optimizer_loop.py (_execute_run, _build_components) and main.py that still read cfg['ea']. Server started but MT5 never launched. Fixes: config.yaml - Restored ea: block as bridge for legacy callers optimizer_loop.py - _build_components: loads EARegistry, creates IniBuilder(schema=schema) instead of manifest path _execute_run: uses self._profile.{name,symbol,tf} instead of cfg['ea']; passes profile to runner.run() mt5/runner.py - Validation + TradeLog now use EAProfile data when profile is provided (legacy fallback preserved) Tested: 7/7 pre-flight checks pass (config, registry, schema, IniBuilder, runner, MutationEngine, OptimizerLoop._build_components) Live browser test: Start clicked → MT5 launched → logs appeared → Reports page loaded (9 cards) → Back to dashboard navigated in-tab System fully operational --- config.yaml | 10 +++++++-- optimizer.db-shm | Bin 32768 -> 0 bytes optimizer.db-wal | Bin 8272 -> 0 bytes optimizer_loop.py | 52 +++++++++++++++++++++++++++++++++++++++------- 4 files changed, 53 insertions(+), 9 deletions(-) delete mode 100644 optimizer.db-shm delete mode 100644 optimizer.db-wal diff --git a/config.yaml b/config.yaml index f41805f..c43ca34 100644 --- a/config.yaml +++ b/config.yaml @@ -1,8 +1,14 @@ # MT5 EA Strategy Optimizer — Master Configuration -# EA identity (name, symbol, timeframe, .set file) is now managed -# in ea_registry.yaml via the EA Registry. See ea/registry.py. +# EA identity is managed in ea_registry.yaml (source of truth for new code). +# The ea: block below is kept as a bridge for legacy code paths. # ───────────────────────────────────────────── +ea: + name: "LEGSTECH_EA_V2" + file: "LEGSTECH_EA_V2" + symbol: "XAUUSD" + timeframe: "H1" + periods: train_start: "2022.01.01" train_end: "2023.12.31" diff --git a/optimizer.db-shm b/optimizer.db-shm deleted file mode 100644 index 7e24b22237724759d40e63c2415db89f52377d32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI*u?fOJ6b4|mv9%DA!b-8s9;q@#s$>gS5NtwfS8xU^UBMA_0KKOoX)Oca507^o z$2<52xXW+FBr^TfVwUG+4|j&|fOEbHi4*a7X~pg33<{O(>$X=TH%*tER-jR97 zuG%N;SFD`qUEwRfgTu zmMV}ckSdTWkSdTWkSdTWkSdTWkSg&1R-k)U&rMQD-wy&x04PPcaJ9w&0)<`Thh!rF zjRQ~8m^uI$)-=$u$N}&?MYN)90|3`0EWoZ_4}dBiamndD03yl4hy~s{08#}ij$+&k zfX6ZCGSYVgAZAaqtA7^&SH*4+d30^E26IXX_0|CJgo>Fb)oK8YYbF@=vH+q;aqd&L z3P8Xk-xb}D3*5u(B`NS4`dGj$|6ct7_9)nh1Np((H#JyFv2?a z$Z`NOWG+(yza2nGU0-SHE=xvY?fFW?OB3LGaV%VX8vyEsOh+DD0)T|B8%8`{JU$Zm zf|5l5JRJMj_2XLsXyKBWQ+f*kHzbm&2rmR6V;vDc3TyyD7!vJ8p#?xOEC(|@H2lC_s0GwftjdooCgc2@g9-E&4v!%~mJr6(_vzRdHbtY?s=QAS3TmYJ= zK#G9O0iet`@5z|X1|Yc~aD!$6z}olxK=PXx%<7p>lp6{{0#kWe_-p=Nuz1DJKQ5h$ z&Sp&KoH_S)WKMN&pWm1_-+WA4sz9nhsz9p1^%Xd_gLL=YxAur!(%IQ~;j!k;9?F_7 z70bFnG4(Jftbmy-%pHE9QLGOaRHHhmAF4FU5%N%}QmY|VYSikw+FM(PDlxk7(g%nk zRVmlBYSfE^I+>(v4tlaut<_PjUe$769&uE!np@oT@2S*fsmU@vJCD}nNDu^0f3dIs z{@+;AHotx3glQ)aWw)0H9+d~T$YN>u5fj2LRnO)Tb?^o>KC~y{-leNsM$9|rPHu-SixTF;yOU_FWA$jWNncprSc6iJ95kU0jrPmxJ|xImNb7pPM({nN z-gS8(AuJ`{i3X2FO<@RZh; zb4=$M=5g)_@T_S)V_GJcIG#5pKCrtMtd~2-w5*&u)EL`DYkBG`{bO2II5nN%#Q55* zQ(PoFV*F#T13BIFkLEwHt#f*29fQoIW5ky_cOKumd!`%%3-Exe9RqTpm19g^g_k+T z(I;|~j`94&F9H+llB*qq|HrQj#^{)1{BrKqr+fc8xB2z22HyX!Ytzg)22@_VuM3ET z!1dX-W3>Ccn66wH4IFXpiyt1!gntXMQznz#64u+&_#U#vI O4B;TpygV0Bw*La!{02Dy diff --git a/optimizer_loop.py b/optimizer_loop.py index 7a4e771..30bdcb0 100644 --- a/optimizer_loop.py +++ b/optimizer_loop.py @@ -34,11 +34,13 @@ from reports.writer import ReportWriter import pandas as pd BASE_DIR = Path(__file__).parent -MANIFEST_PATH = BASE_DIR / "mutation" / "param_manifest.yaml" KB_PATH = BASE_DIR / "mutation" / "knowledge_base.yaml" DB_PATH = BASE_DIR / "optimizer.db" RUNS_DIR = BASE_DIR / "runs" +# Keep MANIFEST_PATH for MutationEngine (still uses it for advanced mode) +MANIFEST_PATH = BASE_DIR / "mutation" / "param_manifest.yaml" + class OptimizerLoop: """ @@ -394,11 +396,16 @@ class OptimizerLoop: run_id=run_id, params=params, period_start=period_start, period_end=period_end, output_dir=run_dir, phase=phase, + ea_file=self._profile.ex5_file, + ea_symbol=self._profile.symbol, + ea_timeframe=self._profile.timeframe, ) run = Run( - run_id=run_id, ea_name=cfg["ea"]["name"], - symbol=cfg["ea"]["symbol"], timeframe=cfg["ea"]["timeframe"], + run_id=run_id, + ea_name=self._profile.name, + symbol=self._profile.symbol, + timeframe=self._profile.timeframe, period_start=period_start, period_end=period_end, params=params, phase=phase, hypothesis_id=hypothesis_id, tester_model=cfg["mt5"]["tester_model"], @@ -407,8 +414,11 @@ class OptimizerLoop: store.save_run(run) self._emit("log", {"level": "info", "msg": f"⏳ MT5 running: {run_id}"}) - result = runner.run(run_id, ini_path, run_dir / "report", - log_csv_search_dir=Path(cfg["mt5"]["mql5_files_path"])) + result = runner.run( + run_id, ini_path, run_dir / "report", + log_csv_search_dir=Path(cfg["mt5"]["mql5_files_path"]), + profile=self._profile, + ) if not result.success: self._emit("run_failed", {"run_id": run_id, "error": result.error_message}) @@ -492,8 +502,36 @@ class OptimizerLoop: def _build_components(self): cfg = self.cfg - store = DataStore(DB_PATH, RUNS_DIR) - builder = IniBuilder(self.config_path, str(MANIFEST_PATH)) + + # ── EA Registry: load profile + schema ──────────────────────────────── + from ea.registry import EARegistry + reg = EARegistry(self.config_path) + ea_name = cfg.get("ea", {}).get("name", "LEGSTECH_EA_V2") + try: + self._profile = reg.get(ea_name) + schema = reg.get_schema(self._profile) + logger.info(f"Using EA profile from registry: {ea_name} (mode={self._profile.mode})") + except KeyError: + # Profile not in registry — fall back to legacy manifest + logger.warning(f"EA {ea_name!r} not in registry, using legacy manifest") + from ea.registry import EAProfile + self._profile = EAProfile( + name=ea_name, + ex5_file=cfg["ea"]["file"], + set_template="", + symbol=cfg["ea"]["symbol"], + timeframe=cfg["ea"]["timeframe"], + ) + schema = None # builder will use manifest + + # ── Component construction ───────────────────────────────────────────── + store = DataStore(DB_PATH, RUNS_DIR) + + if schema is not None: + builder = IniBuilder(self.config_path, schema=schema) + else: + builder = IniBuilder(self.config_path, str(MANIFEST_PATH)) + runner = MT5Runner(self.config_path) parser = ReportParser() log_rdr = TradeLogReader(