Files
mt_mt5_backertest/scripts/optimizer/ea_config_parser.py
T
2026-07-06 03:32:12 +08:00

136 lines
5.1 KiB
Python

import os
import json
from dataclasses import dataclass, field
from typing import Dict, List, Any
@dataclass
class ParameterDef:
name: str
param_type: str
default: Any = None
min_value: Any = None
max_value: Any = None
step: Any = None
precision: int = 0
optimize: bool = True
enum_options: List[Any] = field(default_factory=list)
description: str = ''
condition: str = ''
def expand_values(self) -> List[Any]:
if self.param_type == 'bool':
return [True, False]
elif self.param_type == 'enum':
return self.enum_options
elif self.param_type in ('int', 'double'):
if self.min_value is None or self.max_value is None:
return [self.default] if self.default is not None else []
values = []
current = self.min_value
while current <= self.max_value:
values.append(round(current, self.precision) if self.precision > 0 else int(current))
current += self.step
return values
return [self.default]
def is_valid_value(self, value: Any) -> bool:
if self.param_type == 'bool':
return isinstance(value, bool)
elif self.param_type == 'enum':
return value in self.enum_options
elif self.param_type in ('int', 'double'):
if self.min_value is not None and value < self.min_value:
return False
if self.max_value is not None and value > self.max_value:
return False
return True
return True
@dataclass
class EAConfig:
ea_name: str
ea_path: str
parameters: Dict[str, ParameterDef] = field(default_factory=dict)
search_strategy: str = 'auto'
optimization_criterion: str = 'profit_factor'
test_config: Dict[str, Any] = field(default_factory=dict)
walk_forward: Dict[str, Any] = field(default_factory=dict)
description: str = ''
def get_total_combinations(self) -> int:
total = 1
for param in self.parameters.values():
values = param.expand_values()
total *= len(values) if values else 1
return total
def estimate_search_time(self, tests_per_minute: float = 10) -> str:
total = self.get_total_combinations()
minutes = total / tests_per_minute
if minutes < 60:
return str(round(minutes, 1)) + ' minutes'
elif minutes < 1440:
return str(round(minutes/60, 1)) + ' hours'
else:
return str(round(minutes/1440, 1)) + ' days'
def is_complex(self) -> bool:
return len(self.parameters) > 6 or self.get_total_combinations() > 1_000_000
def load_ea_config(config_path: str) -> EAConfig:
with open(config_path, 'r', encoding='utf-8') as f:
config_data = json.load(f)
ea_name = config_data.get('ea_name', 'Unknown')
ea_path = config_data.get('ea_path', '')
description = config_data.get('description', '')
search_strategy = config_data.get('search_strategy', 'auto')
criterion = config_data.get('optimization_criterion', 'profit_factor')
test_config = config_data.get('test_config', {})
walk_forward = config_data.get('walk_forward', {})
parameters = {}
for param_name, param_data in config_data.get('parameters', {}).items():
param_type = param_data.get('type', 'int')
if param_type == 'enum':
param = ParameterDef(
name=param_name,
param_type='enum',
default=param_data.get('default'),
enum_options=param_data.get('options', []),
description=param_data.get('description', ''),
condition=param_data.get('condition', '')
)
else:
param = ParameterDef(
name=param_name,
param_type=param_type,
default=param_data.get('default'),
min_value=param_data.get('min'),
max_value=param_data.get('max'),
step=param_data.get('step', 1),
precision=param_data.get('precision', 0),
optimize=param_data.get('optimize', True),
description=param_data.get('description', ''),
condition=param_data.get('condition', '')
)
parameters[param_name] = param
return EAConfig(
ea_name=ea_name, ea_path=ea_path, parameters=parameters,
search_strategy=search_strategy, optimization_criterion=criterion,
test_config=test_config, walk_forward=walk_forward, description=description
)
def load_all_ea_configs(configs_dir: str) -> Dict[str, EAConfig]:
configs = {}
if not os.path.exists(configs_dir):
return configs
for filename in os.listdir(configs_dir):
if filename.endswith('.json'):
config_path = os.path.join(configs_dir, filename)
try:
config = load_ea_config(config_path)
configs[config.ea_name] = config
except Exception as e:
print('Error loading ' + config_path + ': ' + str(e))
return configs