chore: fix gitignore — remove mt5_batch_config.json from tracking
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"terminal_path": "C:\\Program Files\\MetaTrader 5\\terminal64.exe",
|
||||
"tester_folder": "C:\\Users\\pc\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\Tester",
|
||||
"terminal_label": "\ufffd\ufffdC\u0000:\u0000\\\u0000P\u0000r\u0000o\u0000g\u0000r\u0000a\u0000m\u0000 \u0000F\u0000i\u0000l\u0000e\u0000s\u0000\\\u0000M\u0000e\u0000t\u0000a\u0000T\u0000r\u0000a\u0000d\u0000e\u0000r\u0000 \u00005\u0000",
|
||||
"ea_name": "Market\\Ultimate Breakout System.ex5",
|
||||
"from_date": "2018.01.01",
|
||||
"to_date": "2026.04.01",
|
||||
"model": "1",
|
||||
"deposit": "10000",
|
||||
"currency": "USD",
|
||||
"leverage": "100",
|
||||
"suffix": ".a"
|
||||
}
|
||||
+74
-20
@@ -4,19 +4,38 @@ from pathlib import Path
|
||||
|
||||
def parse_set_file(file_bytes, filename):
|
||||
"""Parse a .set file and return dict of {param: value} and ordered param list"""
|
||||
text = file_bytes.decode('utf-16')
|
||||
# MT5 .set files can be UTF-16 LE (with BOM) or plain UTF-8 depending on MT5 version
|
||||
if file_bytes[:2] == b'\xff\xfe':
|
||||
text = file_bytes[2:].decode('utf-16-le')
|
||||
elif file_bytes[:2] == b'\xfe\xff':
|
||||
text = file_bytes[2:].decode('utf-16-be')
|
||||
else:
|
||||
# No BOM — try UTF-8 first, fall back to latin-1
|
||||
try:
|
||||
text = file_bytes.decode('utf-8')
|
||||
except Exception:
|
||||
text = file_bytes.decode('latin-1')
|
||||
params = {}
|
||||
raw_lines = {} # preserve full line for export
|
||||
order = []
|
||||
|
||||
# Detect format: Ultimate Breakout .set files use || delimiter
|
||||
# Other EA formats (plain key=value with comma-suffixed metadata) are not fully supported
|
||||
is_ubs_format = any('||' in line for line in text.splitlines() if '=' in line)
|
||||
|
||||
all_raw_lines = [] # all lines in order for round-trip export
|
||||
for line in text.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith(';'):
|
||||
stripped = line.strip()
|
||||
all_raw_lines.append(line)
|
||||
if not stripped or stripped.startswith(';'):
|
||||
continue
|
||||
if '=' not in line:
|
||||
if '=' not in stripped:
|
||||
continue
|
||||
key, _, rest = line.partition('=')
|
||||
key, _, rest = stripped.partition('=')
|
||||
key = key.strip()
|
||||
# Skip optimisation metadata lines (ParamName,F / ParamName,1 etc.)
|
||||
if ',' in key:
|
||||
continue
|
||||
# Value is first field before ||
|
||||
parts = rest.split('||')
|
||||
value = parts[0].strip()
|
||||
@@ -24,7 +43,10 @@ def parse_set_file(file_bytes, filename):
|
||||
raw_lines[key] = rest # preserve everything after =
|
||||
order.append(key)
|
||||
|
||||
return params, raw_lines, order
|
||||
# Store full original lines for round-trip (preserves metadata lines)
|
||||
raw_lines['__all_lines__'] = all_raw_lines
|
||||
|
||||
return params, raw_lines, order, is_ubs_format
|
||||
|
||||
def build_comparison_df(files_data):
|
||||
"""
|
||||
@@ -58,7 +80,15 @@ def export_set_file(filename, params_edited, raw_lines, order, original_bytes):
|
||||
Returns bytes (utf-16 encoded)
|
||||
"""
|
||||
# Get original header comments
|
||||
text = original_bytes.decode('utf-16')
|
||||
if original_bytes[:2] == b'\xff\xfe':
|
||||
text = original_bytes[2:].decode('utf-16-le')
|
||||
elif original_bytes[:2] == b'\xfe\xff':
|
||||
text = original_bytes[2:].decode('utf-16-be')
|
||||
else:
|
||||
try:
|
||||
text = original_bytes.decode('utf-8')
|
||||
except Exception:
|
||||
text = original_bytes.decode('latin-1')
|
||||
lines = text.splitlines()
|
||||
header_lines = []
|
||||
for line in lines:
|
||||
@@ -67,19 +97,43 @@ def export_set_file(filename, params_edited, raw_lines, order, original_bytes):
|
||||
else:
|
||||
break
|
||||
|
||||
output_lines = header_lines.copy()
|
||||
|
||||
for key in order:
|
||||
if key not in params_edited:
|
||||
continue
|
||||
new_value = params_edited[key]
|
||||
rest = raw_lines.get(key, new_value)
|
||||
parts = rest.split('||')
|
||||
parts[0] = str(new_value)
|
||||
output_lines.append(f"{key}={'||'.join(parts)}")
|
||||
|
||||
content = '\r\n'.join(output_lines) + '\r\n'
|
||||
return content.encode('utf-16')
|
||||
# Use the full original line list for round-trip, only updating real param values
|
||||
all_lines = raw_lines.get('__all_lines__', [])
|
||||
if all_lines:
|
||||
output_lines = []
|
||||
for line in all_lines:
|
||||
stripped = line.strip()
|
||||
if not stripped or stripped.startswith(';') or '=' not in stripped:
|
||||
output_lines.append(line)
|
||||
continue
|
||||
key, _, rest = stripped.partition('=')
|
||||
key = key.strip()
|
||||
if ',' in key or key not in params_edited:
|
||||
# Metadata line or unknown — preserve as-is
|
||||
output_lines.append(line)
|
||||
else:
|
||||
new_value = params_edited[key]
|
||||
parts = rest.split('||')
|
||||
parts[0] = str(new_value)
|
||||
output_lines.append(f"{key}={'||'.join(parts)}")
|
||||
content = '\r\n'.join(output_lines) + '\r\n'
|
||||
else:
|
||||
# Fallback: rebuild from order (original behaviour)
|
||||
output_lines = header_lines.copy()
|
||||
for key in order:
|
||||
if key not in params_edited:
|
||||
continue
|
||||
new_value = params_edited[key]
|
||||
rest = raw_lines.get(key, new_value)
|
||||
parts = rest.split('||')
|
||||
parts[0] = str(new_value)
|
||||
output_lines.append(f"{key}={'||'.join(parts)}")
|
||||
content = '\r\n'.join(output_lines) + '\r\n'
|
||||
# Preserve original encoding on export
|
||||
if original_bytes[:2] in (b'\xff\xfe', b'\xfe\xff'):
|
||||
return b'\xff\xfe' + content.encode('utf-16-le')
|
||||
else:
|
||||
return content.encode('utf-8')
|
||||
|
||||
def create_zip(files_export):
|
||||
"""
|
||||
|
||||
@@ -169,9 +169,11 @@ def render():
|
||||
key=f"ea_editor_{edit_file}"
|
||||
)
|
||||
|
||||
st.session_state['ea_edited'][edit_file] = dict(
|
||||
zip(edited['Parameter'], edited['Value'].astype(str))
|
||||
)
|
||||
# Guard against Streamlit returning edited df without expected columns
|
||||
if 'Parameter' in edited.columns and 'Value' in edited.columns:
|
||||
st.session_state['ea_edited'][edit_file] = dict(
|
||||
zip(edited['Parameter'], edited['Value'].astype(str))
|
||||
)
|
||||
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
|
||||
Reference in New Issue
Block a user