fix: restore ea: bridge in config + wire optimizer_loop to EARegistry

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
This commit is contained in:
LEGSTECH Optimizer
2026-04-13 20:08:39 +00:00
parent d5a8973c05
commit c4b5fe0ad0
4 changed files with 53 additions and 9 deletions
+45 -7
View File
@@ -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(