参数优化报告自动保存

This commit is contained in:
2026-07-06 04:55:21 +08:00
parent 04be8aee9a
commit e49bdb1116
2 changed files with 70 additions and 26 deletions
+42 -12
View File
@@ -168,6 +168,31 @@ def _launch_mt5(mt5_path, ini_path, data_dir, log_lines: list = None):
return process
def _find_latest_optimizer_xml(search_dirs, ea_name):
"""在多个候选目录里找最新的优化 XML 结果。"""
patterns = [
f'{ea_name}_optimization.xml',
f'{ea_name}_optimization[1].xml',
f'{ea_name}_optimization[2].xml',
]
latest = None
latest_mtime = 0
for base in search_dirs:
if not base or not os.path.isdir(base):
continue
for pattern in patterns:
p = os.path.join(base, pattern)
if os.path.exists(p):
try:
mt = os.path.getmtime(p)
except OSError:
continue
if mt > latest_mtime:
latest_mtime = mt
latest = p
return latest
class MT5BacktestGUI:
_CONFIG_FILE = "config/ea_configs.yaml" # 仅给"回测配置"标签页用
_MT5_STATE_FILE = "optimizer/mt5_state.json" # 优化器用的 MT5 路径,独立小文件
@@ -2175,16 +2200,17 @@ class MT5BacktestGUI:
self.opt_log.insert('end', "启动失败,跳过该EA\n")
continue
xml_name = ea_name + '_optimization.xml'
xml_path = os.path.join(mt5_data_dir, xml_name)
mt5_install_dir = os.path.dirname(mt5_path)
xml_path = _find_latest_optimizer_xml([mt5_data_dir, mt5_install_dir], ea_name)
self.opt_log.insert('end', f"等待XML结果: {xml_path}\n")
self.opt_log.insert('end', f"等待XML结果,候选目录: {mt5_data_dir} | {mt5_install_dir}\n")
self.opt_log.update()
wait_timeout = 600
start_time = time.time()
while time.time() - start_time < wait_timeout:
if os.path.exists(xml_path):
xml_path = _find_latest_optimizer_xml([mt5_data_dir, mt5_install_dir], ea_name)
if xml_path and os.path.exists(xml_path):
time.sleep(2)
try:
with open(xml_path, 'r', encoding='utf-8') as f:
@@ -2197,14 +2223,16 @@ class MT5BacktestGUI:
time.sleep(5)
if process.poll() is not None:
if os.path.exists(xml_path):
xml_path = _find_latest_optimizer_xml([mt5_data_dir, mt5_install_dir], ea_name)
if xml_path and os.path.exists(xml_path):
self.opt_log.insert('end', "MT5已退出,结果文件存在\n")
self.opt_log.update()
break
self.opt_log.insert('end', "MT5已退出,等待结果文件...\n")
self.opt_log.update()
time.sleep(3)
if os.path.exists(xml_path):
xml_path = _find_latest_optimizer_xml([mt5_data_dir, mt5_install_dir], ea_name)
if xml_path and os.path.exists(xml_path):
break
if process.poll() is None:
@@ -2216,11 +2244,13 @@ class MT5BacktestGUI:
except:
pass
dst_xml = os.path.join(reports_dir, ea_name, xml_name)
if os.path.exists(xml_path):
dst_xml = os.path.join(reports_dir, ea_name, ea_name + '_optimization.xml')
if xml_path and os.path.exists(xml_path):
os.makedirs(os.path.dirname(dst_xml), exist_ok=True)
shutil.copy2(xml_path, dst_xml)
self.opt_log.insert('end', f"已保存结果: {dst_xml}\n")
else:
self.opt_log.insert('end', f"未找到优化 XML,已检查: {mt5_data_dir}{mt5_install_dir}\n")
self.opt_log.insert('end', f"{ea_name} 优化完成\n")
self.opt_log.update()
@@ -2237,17 +2267,17 @@ class MT5BacktestGUI:
from ea_batch_optimizer import EABatchOptimizer
from analyze_results import ResultAnalyzer
optimizer = EABatchOptimizer(self.opt_dir.get(), mt5_data_dir=self.data_dir.get())
mt5_terminal_dir = self.data_dir.get()
mt5_search_dirs = [self.data_dir.get(), os.path.dirname(self.mt5_path.get())]
self.opt_log.insert('end', "正在分析结果...\n")
self.opt_log.update()
results = []
if mt5_terminal_dir:
if any(mt5_search_dirs):
reports_dir = os.path.join(self.opt_dir.get(), 'reports', ea_name)
analyzer = ResultAnalyzer(reports_dir)
xml_path = analyzer.copy_xml_results_to_reports(mt5_terminal_dir, ea_name, reports_dir)
xml_path = analyzer.copy_xml_results_to_reports(mt5_search_dirs, ea_name, reports_dir)
if xml_path:
self.opt_log.insert('end', f"从MT5复制结果: {xml_path}\n")
xml_results = analyzer.parse_mt5_xml_optimization(xml_path)
@@ -2311,7 +2341,7 @@ class MT5BacktestGUI:
ea_cfg = json.load(f)
wf = ea_cfg.get('walk_forward', {})
if wf.get('enabled'):
wf_result = analyzer.analyze_walk_forward(mt5_terminal_dir, ea_name, reports_dir)
wf_result = analyzer.analyze_walk_forward(mt5_search_dirs, ea_name, reports_dir)
is_pf = wf_result.get('in_sample', {}).get('profit_factor', 0)
oos_pf = wf_result.get('out_of_sample', {}).get('profit_factor', 0)
self.opt_log.insert('end', f"In-Sample PF: {is_pf}\n")