优化修改正常
This commit is contained in:
+16
-17
@@ -1,35 +1,34 @@
|
||||
backtest_settings:
|
||||
currency: USD
|
||||
date_range:
|
||||
from: 2018.01.01
|
||||
to: 2026.06.04
|
||||
deposit: 1000.0
|
||||
execution_delay: 100
|
||||
from: 2024.01.01
|
||||
to: 2025.12.31
|
||||
deposit: 10000
|
||||
execution_delay: 0
|
||||
forward_date: ''
|
||||
forward_mode: 2
|
||||
leverage: 1:500
|
||||
forward_mode: 0
|
||||
leverage: 1:100
|
||||
model: 0
|
||||
optimization: 0
|
||||
replace_report: true
|
||||
shutdown_terminal: true
|
||||
symbols:
|
||||
- EURUSD
|
||||
- XAUUSD
|
||||
timeframes:
|
||||
- M5
|
||||
- H1
|
||||
visual: 0
|
||||
eas:
|
||||
- filename: MY-EA\without source code\The Gold Reaper MT5_4.3_fix.ex5
|
||||
name: The Gold Reaper MT5_4.3_fix
|
||||
eas: []
|
||||
execution:
|
||||
kill_between: true
|
||||
skip_existing: true
|
||||
timeout_per_test: 300000
|
||||
# mt5_settings: 路径支持占位符与自动检测(见 scripts/mt5_paths.py)
|
||||
# {PROJECT_ROOT} → 项目根目录绝对路径(推荐,确保项目拷到任意位置都能跑)
|
||||
# 留空字符串 → 启动时自动扫描常见位置(Program Files / %APPDATA%/MetaQuotes/Terminal)
|
||||
# 绝对路径 → 直接使用(适配定制安装或便携版)
|
||||
timeout_per_test: 600
|
||||
|
||||
# MT5 路径说明:
|
||||
# 这部分会被 GUI 接管(启动时从 optimizer/mt5_state.json 读取;失焦时写回 mt5_state.json)。
|
||||
# 留空也没事,GUI 自己会用上次保存的值。
|
||||
mt5_settings:
|
||||
terminal_path: "" # 留空=自动检测; 或填 "C:\\Program Files\\MetaTrader 5 EXNESS\\terminal64.exe"
|
||||
data_dir: "" # 留空=自动检测; 或填 "%APPDATA%\\MetaQuotes\\Terminal\\<hash>"
|
||||
terminal_path: ""
|
||||
data_dir: ""
|
||||
ini_dir: "{PROJECT_ROOT}/config/generated"
|
||||
reports_dir: "{PROJECT_ROOT}/reports"
|
||||
|
||||
@@ -121,22 +121,56 @@ def _clear_mt5_chart_workspace(data_dir):
|
||||
pass
|
||||
|
||||
|
||||
def _launch_mt5(mt5_path, ini_path, data_dir):
|
||||
def _launch_mt5(mt5_path, ini_path, data_dir, log_lines: list = None):
|
||||
"""启动 MT5 终端跑测试。同步等 5 秒检查进程还活着,活着就让它跑。"""
|
||||
if log_lines is None:
|
||||
log_lines = []
|
||||
_clear_mt5_chart_workspace(data_dir)
|
||||
process = subprocess.Popen(
|
||||
[mt5_path, "/config:" + os.path.abspath(ini_path)],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
startupinfo=_mt5_startupinfo(),
|
||||
)
|
||||
threading.Thread(
|
||||
target=_minimize_mt5_windows, args=(process.pid,), daemon=True
|
||||
).start()
|
||||
|
||||
cmd = [mt5_path, "/config:" + os.path.abspath(ini_path)]
|
||||
log_lines.append(f" 命令: {' '.join(cmd)!s}")
|
||||
|
||||
if not os.path.isfile(mt5_path):
|
||||
log_lines.append(f" [ERR] terminal64.exe 不存在: {mt5_path!r}")
|
||||
return None
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
startupinfo=_mt5_startupinfo(),
|
||||
)
|
||||
except OSError as e:
|
||||
log_lines.append(f" [ERR] 启动失败: {e!r}")
|
||||
return None
|
||||
except Exception as e:
|
||||
log_lines.append(f" [ERR] 异常: {e!r}")
|
||||
return None
|
||||
|
||||
log_lines.append(f" pid={process.pid}")
|
||||
|
||||
# 同步短等待(5s),检查是否启动后立即挂掉
|
||||
try:
|
||||
process.wait(timeout=5.0)
|
||||
log_lines.append(f" [WARN] MT5 进程在 5s 内退出, returncode={process.returncode}")
|
||||
try:
|
||||
err = (process.stderr.read() or b"").decode('utf-8', 'replace')
|
||||
if err.strip():
|
||||
log_lines.append(f" stderr: {err[:500]}")
|
||||
except Exception:
|
||||
pass
|
||||
return process
|
||||
except subprocess.TimeoutExpired:
|
||||
log_lines.append(" MT5 正常运行中(5s 后仍在跑)")
|
||||
|
||||
threading.Thread(target=_minimize_mt5_windows, args=(process.pid,), daemon=True).start()
|
||||
return process
|
||||
|
||||
|
||||
class MT5BacktestGUI:
|
||||
_CONFIG_FILE = "config/ea_configs.yaml"
|
||||
_CONFIG_FILE = "config/ea_configs.yaml" # 仅给"回测配置"标签页用
|
||||
_MT5_STATE_FILE = "optimizer/mt5_state.json" # 优化器用的 MT5 路径,独立小文件
|
||||
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
@@ -152,26 +186,40 @@ class MT5BacktestGUI:
|
||||
self._load_config_to_gui()
|
||||
|
||||
def _load_or_default_config(self):
|
||||
"""已保存过配置就读 YAML;第一次用走默认(终端路径留空让用户填)。"""
|
||||
"""回测配置(yaml) + MT5 路径(optimizer/mt5_state.json 优先,缺失字段从 yaml 兜底)。"""
|
||||
default = self._load_default_config()
|
||||
# 1) 优先读 mt5_state.json(路径专用小文件)
|
||||
if os.path.isfile(self._MT5_STATE_FILE):
|
||||
try:
|
||||
with open(self._MT5_STATE_FILE, "r", encoding="utf-8") as f:
|
||||
state = json.load(f)
|
||||
for k in ("terminal_path", "data_dir", "reports_dir", "ini_dir"):
|
||||
if k in state and state[k]:
|
||||
default["mt5_settings"][k] = state[k]
|
||||
_gui_log(f"已加载 MT5 路径: {self._MT5_STATE_FILE}")
|
||||
except Exception as e:
|
||||
_gui_log(f"读 mt5_state 失败 ({e})")
|
||||
# 2) 用 yaml 兜底(老数据 / 用户编辑过的字段;mt5_state 已有的路径字段不覆盖)
|
||||
if os.path.isfile(self._CONFIG_FILE):
|
||||
try:
|
||||
with open(self._CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
saved = yaml.safe_load(f) or {}
|
||||
default = self._load_default_config()
|
||||
# 浅合并:saved 覆盖 default;缺失字段用 default 补全
|
||||
for k in ("backtest_settings", "mt5_settings", "execution"):
|
||||
if k in saved:
|
||||
default[k].update(saved[k])
|
||||
if "eas" in saved:
|
||||
if k in saved and isinstance(saved.get(k), dict):
|
||||
for kk, vv in saved[k].items():
|
||||
if vv in (None, "", []):
|
||||
continue
|
||||
# mt5_state 已经填了相同字段,跳过 yaml 的(避免覆盖最新值)
|
||||
if k == "mt5_settings" and kk in ("terminal_path", "data_dir", "reports_dir", "ini_dir"):
|
||||
if default["mt5_settings"].get(kk):
|
||||
continue
|
||||
default[k][kk] = vv
|
||||
if "eas" in saved and saved["eas"]:
|
||||
default["eas"] = saved["eas"]
|
||||
# 占位符解析(仅做 {PROJECT_ROOT} 展开,无自动探测)
|
||||
if resolve_mt5_settings:
|
||||
default["mt5_settings"] = resolve_mt5_settings(default["mt5_settings"])
|
||||
_gui_log(f"已加载保存的配置: {self._CONFIG_FILE}")
|
||||
return default
|
||||
_gui_log(f"已加载配置: {self._CONFIG_FILE}")
|
||||
except Exception as e:
|
||||
_gui_log(f"读配置失败 ({e}),使用默认")
|
||||
return self._load_default_config()
|
||||
_gui_log(f"读 yaml 失败 ({e}),使用默认")
|
||||
return default
|
||||
|
||||
def _load_default_config(self):
|
||||
return {
|
||||
@@ -433,18 +481,21 @@ class MT5BacktestGUI:
|
||||
self.mt5_path = ttk.Entry(path_frame, width=50)
|
||||
self.mt5_path.insert(0, self.config["mt5_settings"].get("terminal_path", ""))
|
||||
self.mt5_path.grid(row=0, column=1, padx=5, pady=3, sticky='ew')
|
||||
self.mt5_path.bind('<FocusOut>', lambda e: self._persist_path_settings())
|
||||
ttk.Button(path_frame, text="浏览...", command=self._browse_mt5).grid(row=0, column=2, padx=5)
|
||||
|
||||
ttk.Label(path_frame, text="MT5数据目录 (含 MQL5/Experts 的那一层):").grid(row=1, column=0, sticky='w', padx=5, pady=3)
|
||||
self.data_dir = ttk.Entry(path_frame, width=50)
|
||||
self.data_dir.insert(0, self.config["mt5_settings"].get("data_dir", ""))
|
||||
self.data_dir.grid(row=1, column=1, padx=5, pady=3, sticky='ew')
|
||||
self.data_dir.bind('<FocusOut>', lambda e: self._persist_path_settings())
|
||||
ttk.Button(path_frame, text="浏览...", command=self._browse_data).grid(row=1, column=2, padx=5)
|
||||
|
||||
ttk.Label(path_frame, text="报告输出目录:").grid(row=2, column=0, sticky='w', padx=5, pady=3)
|
||||
self.reports_dir = ttk.Entry(path_frame, width=50)
|
||||
self.reports_dir.insert(0, self.config["mt5_settings"].get("reports_dir", ""))
|
||||
self.reports_dir.grid(row=2, column=1, padx=5, pady=3, sticky='ew')
|
||||
self.reports_dir.bind('<FocusOut>', lambda e: self._persist_path_settings())
|
||||
ttk.Button(path_frame, text="浏览...", command=self._browse_reports).grid(row=2, column=2, padx=5)
|
||||
|
||||
path_hint = ttk.Label(path_frame,
|
||||
@@ -591,6 +642,24 @@ class MT5BacktestGUI:
|
||||
yaml.dump(config, f, allow_unicode=True)
|
||||
messagebox.showinfo("保存成功", "配置已保存到 config/ea_configs.yaml")
|
||||
|
||||
def _persist_path_settings(self):
|
||||
"""三个路径输入框失焦时调用:写到 optimizer/mt5_state.json(不写 yaml)。"""
|
||||
try:
|
||||
self.config.setdefault("mt5_settings", {})
|
||||
self.config["mt5_settings"]["terminal_path"] = self.mt5_path.get()
|
||||
self.config["mt5_settings"]["data_dir"] = self.data_dir.get()
|
||||
self.config["mt5_settings"]["reports_dir"] = self.reports_dir.get()
|
||||
reports_parent = os.path.dirname(self.reports_dir.get() or ".") or "."
|
||||
self.config["mt5_settings"]["ini_dir"] = os.path.join(reports_parent, "config", "generated")
|
||||
|
||||
os.makedirs(os.path.dirname(self._MT5_STATE_FILE) or ".", exist_ok=True)
|
||||
state = {k: self.config["mt5_settings"][k] for k in ("terminal_path", "data_dir", "reports_dir", "ini_dir")}
|
||||
with open(self._MT5_STATE_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(state, f, ensure_ascii=False, indent=2)
|
||||
_gui_log(f"已保存 MT5 路径: {self._MT5_STATE_FILE}")
|
||||
except Exception as e:
|
||||
_gui_log(f"自动保存失败: {e}")
|
||||
|
||||
def _on_start_backtest(self):
|
||||
_gui_log("开始回测 button clicked")
|
||||
if _IMPORT_ERRORS:
|
||||
@@ -1477,15 +1546,23 @@ class MT5BacktestGUI:
|
||||
def _refresh_opt_ea_list(self):
|
||||
configs_dir = os.path.join(self.opt_dir.get(), 'configs')
|
||||
if not os.path.exists(configs_dir):
|
||||
self.opt_log.insert('end', f"配置目录不存在: {configs_dir}\n")
|
||||
self.opt_log.insert('end', f" [ERR] 配置目录不存在: {configs_dir}\n")
|
||||
self.opt_log.insert('end', f" 创建方法: mkdir {configs_dir}\n")
|
||||
return
|
||||
sys.path.insert(0, os.path.join(os.getcwd(), 'scripts', 'optimizer'))
|
||||
from ea_config_parser import load_all_ea_configs
|
||||
configs = load_all_ea_configs(configs_dir)
|
||||
if not configs:
|
||||
self.opt_log.insert('end', f" [WARN] {configs_dir} 下没有 JSON 配置\n")
|
||||
self.opt_log.insert('end', f" 请把 EA 的参数配置 .json 放进该目录\n")
|
||||
self.opt_ea_combo['values'] = []
|
||||
return
|
||||
|
||||
installed_names = None
|
||||
mt5_data = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
if mt5_data:
|
||||
mt5_data = self.data_dir.get()
|
||||
if not mt5_data:
|
||||
self.opt_log.insert('end', f" [WARN] '回测配置' 里 MT5 数据目录为空,跳过 EA 存在性校验\n")
|
||||
else:
|
||||
try:
|
||||
from ea_auto_scanner import EAAutoScanner
|
||||
scanner = EAAutoScanner(mt5_data)
|
||||
@@ -1494,9 +1571,13 @@ class MT5BacktestGUI:
|
||||
installed_names = {e['name'] for e in experts}
|
||||
for e in experts:
|
||||
self.opt_ea_paths[e['name']] = e['path']
|
||||
else:
|
||||
self.opt_log.insert('end', f" [WARN] {mt5_data}\\MQL5\\Experts 下没有 .ex5 文件\n")
|
||||
except Exception as e:
|
||||
self.opt_log.insert('end', f"扫描MT5失败,跳过校验: {e}\n")
|
||||
installed_names = None
|
||||
import traceback
|
||||
self.opt_log.insert('end', f" [ERR] 扫描MT5失败: {e}\n")
|
||||
self.opt_log.insert('end', f" 请确认 '回测配置' 里的 MT5 数据目录正确\n")
|
||||
self.opt_log.insert('end', f" 目录应包含 MQL5\\Experts 子目录\n")
|
||||
|
||||
filtered_names = []
|
||||
removed_names = []
|
||||
@@ -1520,7 +1601,7 @@ class MT5BacktestGUI:
|
||||
self.opt_log.insert('end', f"已加载 {len(configs)} 个EA配置\n")
|
||||
|
||||
def _auto_scan_eas(self):
|
||||
mt5_data = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
mt5_data = self.data_dir.get()
|
||||
if not mt5_data:
|
||||
messagebox.showwarning('警告', '请先在回测配置中设置MT5数据目录')
|
||||
return
|
||||
@@ -1563,7 +1644,9 @@ class MT5BacktestGUI:
|
||||
self.opt_ea_var.set(ea_list[0])
|
||||
self._auto_load_ea_with_set(mt5_data, ea_list[0])
|
||||
|
||||
def _auto_load_ea_with_set(self, mt5_data, ea_name):
|
||||
def _auto_load_ea_with_set(self, mt5_data, ea_name=None):
|
||||
if ea_name is None:
|
||||
ea_name = self.opt_ea_var.get()
|
||||
for item in self.param_tree.get_children():
|
||||
self.param_tree.delete(item)
|
||||
|
||||
@@ -1596,7 +1679,7 @@ class MT5BacktestGUI:
|
||||
def _on_ea_selected(self, event=None):
|
||||
ea_name = self.opt_ea_var.get()
|
||||
if ea_name:
|
||||
mt5_data = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
mt5_data = self.data_dir.get()
|
||||
self._auto_load_ea_with_set(mt5_data, ea_name)
|
||||
|
||||
def _load_ea_params(self, ea_name):
|
||||
@@ -1605,7 +1688,7 @@ class MT5BacktestGUI:
|
||||
configs_dir = os.path.join(self.opt_dir.get(), 'configs')
|
||||
sys.path.insert(0, os.path.join(os.getcwd(), 'scripts', 'optimizer'))
|
||||
from ea_config_parser import load_ea_config
|
||||
mt5_data = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
mt5_data = self.data_dir.get()
|
||||
|
||||
config_path = os.path.join(configs_dir, ea_name + '.json')
|
||||
if os.path.exists(config_path):
|
||||
@@ -1894,9 +1977,9 @@ class MT5BacktestGUI:
|
||||
if not ea_name:
|
||||
messagebox.showwarning('警告', '请先选择一个EA')
|
||||
return
|
||||
mt5_path = self.config.get('mt5_settings', {}).get('terminal_path', '')
|
||||
if not mt5_path or not os.path.exists(mt5_path):
|
||||
messagebox.showerror('错误', 'MT5终端路径无效')
|
||||
mt5_path = self.mt5_path.get()
|
||||
if not mt5_path or not os.path.isfile(mt5_path):
|
||||
messagebox.showerror('错误', f'MT5终端路径无效: {mt5_path!r}\n请在"回测配置"标签页用"浏览..."按钮设置 terminal64.exe')
|
||||
return
|
||||
sys.path.insert(0, os.path.join(os.getcwd(), 'scripts', 'optimizer'))
|
||||
from ea_batch_optimizer import EABatchOptimizer
|
||||
@@ -1908,7 +1991,7 @@ class MT5BacktestGUI:
|
||||
return
|
||||
try:
|
||||
config = load_ea_config(config_path)
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get())
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get(), mt5_data_dir=self.data_dir.get())
|
||||
self.opt_log.insert('end', f"正在生成优化配置...\n")
|
||||
self.opt_log.update()
|
||||
ini_path = optimizer.generate_ini_for_ea(config, None)
|
||||
@@ -1917,9 +2000,12 @@ class MT5BacktestGUI:
|
||||
abs_ini_path = os.path.abspath(ini_path)
|
||||
self.opt_log.insert('end', "正在启动MT5优化器...\n")
|
||||
self.opt_log.update()
|
||||
mt5_data_dir = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
_launch_mt5(mt5_path, abs_ini_path, mt5_data_dir)
|
||||
self.opt_log.insert('end', "MT5已启动\n")
|
||||
mt5_data_dir = self.data_dir.get()
|
||||
log_lines: list = []
|
||||
_launch_mt5(mt5_path, abs_ini_path, mt5_data_dir, log_lines=log_lines)
|
||||
for line in log_lines:
|
||||
self.opt_log.insert('end', line + "\n")
|
||||
self.opt_log.update()
|
||||
mode = self.opt_optimization_mode.get().split('(')[0] if '(' in self.opt_optimization_mode.get() else '遗传算法'
|
||||
self.opt_log.insert('end', f"MT5优化器运行中({mode})\n")
|
||||
self.opt_log.insert('end', "优化完成后点击'分析结果'查看\n")
|
||||
@@ -1927,9 +2013,14 @@ class MT5BacktestGUI:
|
||||
self.opt_log.insert('end', f"错误: {str(e)}\n")
|
||||
|
||||
def _run_batch_optimize(self):
|
||||
mt5_path = self.config.get('mt5_settings', {}).get('terminal_path', '')
|
||||
if not mt5_path or not os.path.exists(mt5_path):
|
||||
messagebox.showerror('错误', 'MT5终端路径无效')
|
||||
_gui_log("点击: 批量执行优化")
|
||||
mt5_path = self.mt5_path.get()
|
||||
if not mt5_path or not os.path.isfile(mt5_path):
|
||||
messagebox.showerror('错误', f'MT5终端路径无效: {mt5_path!r}\n请在"回测配置"标签页用"浏览..."按钮设置 terminal64.exe')
|
||||
return
|
||||
mt5_data_dir = self.data_dir.get()
|
||||
if not mt5_data_dir or not os.path.isdir(mt5_data_dir):
|
||||
messagebox.showerror('错误', f'MT5数据目录无效: {mt5_data_dir!r}\n请在"回测配置"标签页设置 MT5 数据目录')
|
||||
return
|
||||
sys.path.insert(0, os.path.join(os.getcwd(), 'scripts', 'optimizer'))
|
||||
from ea_batch_optimizer import EABatchOptimizer
|
||||
@@ -1945,16 +2036,12 @@ class MT5BacktestGUI:
|
||||
messagebox.showwarning('警告', '没有找到EA配置')
|
||||
return
|
||||
|
||||
result = messagebox.askyesno('确认', f'将对 {len(configs)} 个EA进行批量优化\n优化完成后自动进入下一个\n\n是否继续?')
|
||||
if not result:
|
||||
return
|
||||
|
||||
self.opt_log.insert('end', f"开始批量优化,共 {len(configs)} 个EA\n")
|
||||
self.opt_log.insert('end', "每个EA优化完成后会自动关闭MT5并启动下一个\n")
|
||||
self.opt_log.update()
|
||||
_gui_log(f"开始批量优化,共 {len(configs)} 个EA")
|
||||
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get())
|
||||
mt5_data_dir = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get(), mt5_data_dir=self.data_dir.get())
|
||||
reports_dir = os.path.join(self.opt_dir.get(), 'reports')
|
||||
os.makedirs(reports_dir, exist_ok=True)
|
||||
|
||||
@@ -1967,8 +2054,17 @@ class MT5BacktestGUI:
|
||||
abs_ini_path = os.path.abspath(ini_path)
|
||||
self.opt_log.insert('end', f"启动MT5: {ea_name}\n")
|
||||
self.opt_log.update()
|
||||
_gui_log(f"启动MT5: {ea_name}, ini={abs_ini_path}")
|
||||
|
||||
process = _launch_mt5(mt5_path, abs_ini_path, mt5_data_dir)
|
||||
log_lines: list = []
|
||||
process = _launch_mt5(mt5_path, abs_ini_path, mt5_data_dir, log_lines=log_lines)
|
||||
for line in log_lines:
|
||||
self.opt_log.insert('end', line + "\n")
|
||||
_gui_log(line)
|
||||
self.opt_log.update()
|
||||
if process is None:
|
||||
self.opt_log.insert('end', "启动失败,跳过该EA\n")
|
||||
continue
|
||||
|
||||
xml_name = ea_name + '_optimization.xml'
|
||||
xml_path = os.path.join(mt5_data_dir, xml_name)
|
||||
@@ -2031,8 +2127,8 @@ class MT5BacktestGUI:
|
||||
sys.path.insert(0, os.path.join(os.getcwd(), 'scripts', 'optimizer'))
|
||||
from ea_batch_optimizer import EABatchOptimizer
|
||||
from analyze_results import ResultAnalyzer
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get())
|
||||
mt5_terminal_dir = self.config.get('mt5_settings', {}).get('data_dir', '')
|
||||
optimizer = EABatchOptimizer(self.opt_dir.get(), mt5_data_dir=self.data_dir.get())
|
||||
mt5_terminal_dir = self.data_dir.get()
|
||||
|
||||
self.opt_log.insert('end', "正在分析结果...\n")
|
||||
self.opt_log.update()
|
||||
@@ -2127,4 +2223,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[04:15:21] 已加载配置: config/ea_configs.yaml
|
||||
[04:15:39] 已加载配置: config/ea_configs.yaml
|
||||
[04:15:39] 已加载 MT5 路径: optimizer/mt5_state.json
|
||||
[04:15:39] 已加载配置: config/ea_configs.yaml
|
||||
[04:15:39] 已加载 MT5 路径: optimizer/mt5_state.json
|
||||
[04:15:39] 已加载配置: config/ea_configs.yaml
|
||||
@@ -13,12 +13,12 @@ from ea_config_parser import load_ea_config, load_all_ea_configs, EAConfig
|
||||
from parameter_constraint import create_constraint_engine
|
||||
from smart_search import SmartSearch
|
||||
from analyze_results import ResultAnalyzer
|
||||
from mt5_paths import auto_detect_data_dir
|
||||
|
||||
|
||||
class EABatchOptimizer:
|
||||
def __init__(self, base_dir: str = 'optimizer'):
|
||||
def __init__(self, base_dir: str = 'optimizer', mt5_data_dir: str = ''):
|
||||
self.base_dir = base_dir
|
||||
self.mt5_data_dir = mt5_data_dir
|
||||
self.configs_dir = os.path.join(base_dir, 'configs')
|
||||
self.set_files_dir = os.path.join(base_dir, 'set_files')
|
||||
self.reports_dir = os.path.join(base_dir, 'reports')
|
||||
@@ -97,8 +97,11 @@ class EABatchOptimizer:
|
||||
ini_path = os.path.join(self.configs_dir, ini_filename)
|
||||
set_filename = ea_config.ea_name + '_optimization.set'
|
||||
|
||||
data_dir = auto_detect_data_dir() or r'C:\Users\Administrator\AppData\Roaming\MetaQuotes\Terminal\010E047102812FC0C18890992854220E'
|
||||
mt5_tester_dir = os.path.join(data_dir, 'MQL5', 'Profiles', 'Tester')
|
||||
if not self.mt5_data_dir:
|
||||
raise FileNotFoundError(
|
||||
"EABatchOptimizer: mt5_data_dir 未设置。请在 GUI '回测配置' 里设置 MT5 数据目录"
|
||||
)
|
||||
mt5_tester_dir = os.path.join(self.mt5_data_dir, 'MQL5', 'Profiles', 'Tester')
|
||||
set_path = os.path.join(mt5_tester_dir, set_filename)
|
||||
|
||||
date_from = test_config.get('from_date', '2025.01.01')
|
||||
|
||||
Reference in New Issue
Block a user