Files
zhutoutoutousan 605faf5310 Prepare source-only public release for develop.
Add cluster audit pipeline, united EA updates, brochure generators, and publication hygiene (gitignore, MT5 path desensitization, pre-upload scan). Remove tracked reports, models, and binary artifacts from the repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 15:03:43 +02:00

318 lines
13 KiB
Python

"""
Build cluster-latest SuperEA audit params from sequential JSON reports.
Usage:
python -m cluster_audit.sync_cluster
"""
from __future__ import annotations
import json
from datetime import datetime
from pathlib import Path
from cluster_audit.scoring import DEFAULT_TRADES_PER_DAY, acceptance, period_days, trades_per_day
from cluster_audit.strategy_registry import PERIODS, STRATEGIES
REPORTS = Path(__file__).parent / "reports" / "sequential"
OUT_MQH = Path(__file__).resolve().parents[3] / "frontline" / "cluster-latest" / "SuperEA_AuditParams.mqh"
OUT_JSON = Path(__file__).parent / "reports" / "cluster_manifest.json"
RSI_SCALP_IDS = [
"rsi_scalp_appl_unit", "rsi_scalp_appl_trail", "rsi_scalp_adbe_trail",
"rsi_scalp_btc_unit", "rsi_scalp_btc_trail", "rsi_scalp_mu",
"rsi_scalp_nvda_unit", "rsi_scalp_nvda_trail", "rsi_scalp_nvda_trail_v2",
"rsi_scalp_tsla_unit", "rsi_scalp_tsla_trail", "rsi_scalp_xau_trail",
]
RSI_INDEX = {sid: i for i, sid in enumerate(RSI_SCALP_IDS)}
MAGIC_MAP = {s["id"]: 401000 + i for i, s in enumerate(STRATEGIES, 1)}
def load_report(sid: str) -> dict | None:
p = REPORTS / f"{sid}_2021-2026.json"
if not p.exists():
return None
return json.loads(p.read_text(encoding="utf-8"))
def spec_defaults(sid: str) -> dict:
for s in STRATEGIES:
if s["id"] == sid:
return dict(s["defaults"])
return {}
def evaluate_report(r: dict, days: int) -> tuple[bool, list[str]]:
from cluster_audit.backtest_core import BacktestReport
o = r.get("optimized", {})
rep = BacktestReport(
strategy_id=r["id"],
symbol=r.get("symbol", ""),
timeframe=r.get("timeframe", "H1"),
period_label="2021-2026",
net_profit=float(o.get("net_profit", 0)),
total_trades=int(o.get("total_trades", 0)),
win_rate=float(o.get("win_rate", 0)),
profit_factor=float(o.get("profit_factor", 0)),
sharpe=float(o.get("sharpe", 0)),
max_drawdown_pct=float(o.get("max_drawdown_pct", 0)),
avg_win=float(o.get("avg_win", 0)),
avg_loss=float(o.get("avg_loss", 0)),
worst_trades=o.get("worst_trades", []),
losing_trades=o.get("losing_trades", []),
exit_reason_breakdown=o.get("exit_reason_breakdown", {}),
monthly_returns=o.get("monthly_returns", {}),
params=o.get("params", {}),
)
if r.get("passed") is True:
ok, issues = acceptance(rep, days, DEFAULT_TRADES_PER_DAY)
if ok:
return True, []
return acceptance(rep, days, DEFAULT_TRADES_PER_DAY)
def _lit_bool(v) -> str:
return "true" if v else "false"
def emit_darvas(params: dict, ok: bool) -> list[str]:
d = {**spec_defaults("darvas_xau"), **params}
return [
"static void SE_AuditDarvas(DarvasBoxConfig &c)",
"{",
f" c.box_period = {int(d['box_period'])};",
f" c.box_deviation = {float(d['box_deviation'])};",
f" c.ma_period = {int(d['ma_period'])};",
f" c.trend_threshold = {float(d['trend_threshold'])};",
f" c.stop_loss_pts = {float(d['stop_loss_pts'])};",
f" c.take_profit_pts = {float(d['take_profit_pts'])};",
" c.box_timeframe = PERIOD_M15;",
" c.trend_timeframe = PERIOD_M15;",
" c.use_close_breakout = true;",
" c.require_volume_ma = false;",
"}",
f"static bool SE_AuditDarvasEnabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def emit_ema_slope(fn: str, params: dict, ok: bool) -> list[str]:
d = params
lines = [f"static void SE_Audit{fn}(EmaSlopeConfig &c)", "{"]
for key, cast in [
("ema_period", int), ("price_threshold_pips", float), ("slope_threshold_pips", float),
("monitor_timeout_sec", int), ("trailing_stop_pips", float),
("max_trades_per_crossover", int), ("profit_check_bars", int),
("weekly_adx_period", int), ("weekly_adx_min", float), ("weekly_adx_bar_shift", int),
]:
if key in d:
lines.append(f" c.{key} = {cast(d[key])};")
if "use_trailing_stop" in d:
lines.append(f" c.use_trailing_stop = {_lit_bool(d['use_trailing_stop'])};")
lines += ["}", f"static bool SE_Audit{fn}Enabled() {{ return {_lit_bool(ok)}; }}", ""]
return lines
def emit_mean_rev(params: dict, ok: bool) -> list[str]:
d = {**spec_defaults("mean_rev_btc"), **params}
return [
"static void SE_AuditMeanRev(MeanReversionConfig &c)",
"{",
f" c.ema_period = {int(d.get('ema_period', 250))};",
f" c.min_ema_distance_pts = {float(d.get('min_ema_distance_pts', 3650))};",
f" c.rsi_period = {int(d.get('rsi_period', 28))};",
f" c.rsi_oversold = {float(d.get('rsi_oversold', 40))};",
f" c.rsi_overbought = {float(d.get('rsi_overbought', 83))};",
f" c.adx_period = {int(d.get('adx_period', 14))};",
f" c.adx_max_for_entry = {float(d.get('adx_max_for_entry', 17))};",
f" c.adx_escape = {float(d.get('adx_escape', 34))};",
f" c.use_rsi_cross = {_lit_bool(d.get('use_rsi_cross', True))};",
f" c.use_hard_sltp = {_lit_bool(d.get('use_hard_sltp', False))};",
f" c.sl_points = {float(d.get('sl_points', 1300))};",
f" c.tp_points = {float(d.get('tp_points', 13400))};",
"}",
f"static bool SE_AuditMeanRevEnabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def emit_rsi_cross(params: dict, ok: bool) -> list[str]:
d = {**spec_defaults("rsi_cross_xau"), **params}
return [
"static void SE_AuditRsiCross(RsiCrossOverConfig &c)",
"{",
f" c.rsi_period = {int(d.get('rsi_period', 19))};",
f" c.overbought_level = {float(d.get('overbought_level', 93))};",
f" c.oversold_level = {float(d.get('oversold_level', 22))};",
f" c.ema_period = {int(d.get('ema_period', 140))};",
f" c.ema_slope_threshold = {float(d.get('ema_slope_threshold', 105))};",
f" c.ema_distance_threshold = {float(d.get('ema_distance_threshold', 165))};",
f" c.exit_buy_rsi = {float(d.get('exit_buy_rsi', 86))};",
f" c.exit_sell_rsi = {float(d.get('exit_sell_rsi', 10))};",
f" c.trailing_stop_pts = {float(d.get('trailing_stop_pts', 295))};",
f" c.cooldown_seconds = {int(d.get('cooldown_seconds', 209))};",
"}",
f"static bool SE_AuditRsiCrossEnabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def emit_rsi_asian(fn: str, params: dict, ok: bool) -> list[str]:
d = params
return [
f"static void SE_Audit{fn}(RsiAsianConfig &c)",
"{",
f" c.rsi_period = {int(d.get('rsi_period', 28))};",
f" c.overbought_level = {float(d.get('overbought_level', 60))};",
f" c.oversold_level = {float(d.get('oversold_level', 8))};",
f" c.asian_session_start = {int(d.get('asian_session_start', 0))};",
f" c.asian_session_end = {int(d.get('asian_session_end', 8))};",
f" c.use_rsi_exit = {_lit_bool(d.get('use_rsi_exit', True))};",
f" c.rsi_exit_level = {float(d.get('rsi_exit_level', 55))};",
"}",
f"static bool SE_Audit{fn}Enabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def emit_rsi_secret(params: dict, ok: bool) -> list[str]:
d = {**spec_defaults("rsi_secret_xau"), **params}
return [
"static void SE_AuditRsiSecret(RsiSecretSauceConfig &c)",
"{",
f" c.rsi_period = {int(d.get('rsi_period', 16))};",
f" c.rsi_overbought = {float(d.get('rsi_overbought', 72.5))};",
f" c.rsi_oversold = {float(d.get('rsi_oversold', 32.5))};",
f" c.stop_loss_atr = {float(d.get('stop_loss_atr', 2.75))};",
f" c.take_profit_atr = {float(d.get('take_profit_atr', 5.0))};",
f" c.min_bars_between_trades = {int(d.get('min_bars_between_trades', 7))};",
"}",
f"static bool SE_AuditRsiSecretEnabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def emit_rsi_scalp(idx: int, sid: str, params: dict, ok: bool) -> list[str]:
d = {**spec_defaults(sid), **params}
return [
f"static void SE_AuditRsi{idx}(RsiScalpConfig &c)",
"{",
f" c.rsi_period = {int(d.get('rsi_period', 14))};",
f" c.rsi_overbought = {float(d.get('rsi_overbought', 70))};",
f" c.rsi_oversold = {float(d.get('rsi_oversold', 30))};",
f" c.rsi_target_buy = {float(d.get('rsi_target_buy', 80))};",
f" c.rsi_target_sell = {float(d.get('rsi_target_sell', 50))};",
f" c.bars_to_wait = {int(d.get('bars_to_wait', 5))};",
f" c.use_trailing = {_lit_bool(d.get('use_trailing', False))};",
f" c.trail_distance_pts = {float(d.get('trail_distance_pts', 0))};",
f" c.trail_activation_pts = {float(d.get('trail_activation_pts', 0))};",
"}",
f"static bool SE_AuditRsi{idx}Enabled() {{ return {_lit_bool(ok)}; }}",
"",
]
def stub_enabled(name: str, ok: bool = False) -> list[str]:
return [f"static bool SE_Audit{name}Enabled() {{ return {_lit_bool(ok)}; }}", ""]
def main() -> None:
start, end = PERIODS["2021-2026"]
days = period_days(start, end)
manifest: dict = {
"generated": datetime.now().isoformat(),
"period_days": days,
"trades_per_day_target": DEFAULT_TRADES_PER_DAY,
"strategies": {},
}
reports: dict[str, dict] = {}
status: dict[str, bool] = {}
params_map: dict[str, dict] = {}
for spec in STRATEGIES:
sid = spec["id"]
r = load_report(sid)
if not r:
manifest["strategies"][sid] = {"status": "no_report", "passed": False}
status[sid] = False
params_map[sid] = spec_defaults(sid)
continue
reports[sid] = r
params = r.get("optimized_params") or r.get("optimized", {}).get("params", spec_defaults(sid))
params_map[sid] = params
ok, issues = evaluate_report(r, days)
o = r.get("optimized", {})
tpd = trades_per_day(
type("R", (), {"total_trades": int(o.get("total_trades", 0))})(),
days,
)
status[sid] = ok
manifest["strategies"][sid] = {
"passed": ok,
"magic": MAGIC_MAP.get(sid),
"trades": o.get("total_trades"),
"trades_per_day": round(tpd, 3),
"net_profit": o.get("net_profit"),
"sharpe": o.get("sharpe"),
"profit_factor": o.get("profit_factor"),
"issues": issues,
"params": params,
}
lines = [
"//+------------------------------------------------------------------+",
"//| SuperEA_AuditParams.mqh - optimized params from cluster audit |",
f"//| Generated: {datetime.now().isoformat()}",
"//+------------------------------------------------------------------+",
"#ifndef SUPER_EA_AUDIT_PARAMS_MQH",
"#define SUPER_EA_AUDIT_PARAMS_MQH",
"",
]
lines += [f"// darvas_xau: {'PASS' if status.get('darvas_xau') else 'DISABLED'}"]
lines += emit_darvas(params_map.get("darvas_xau", {}), status.get("darvas_xau", False))
lines += [f"// ema_slope_unit: {'PASS' if status.get('ema_slope_unit') else 'DISABLED'}"]
lines += emit_ema_slope("EmaUnit", params_map.get("ema_slope_unit", {}), status.get("ema_slope_unit", False))
lines += [f"// ema_slope_trail: {'PASS' if status.get('ema_slope_trail') else 'DISABLED'}"]
lines += emit_ema_slope("EmaTrail", params_map.get("ema_slope_trail", {}), status.get("ema_slope_trail", False))
lines += [f"// mean_rev_btc: {'PASS' if status.get('mean_rev_btc') else 'DISABLED'}"]
lines += emit_mean_rev(params_map.get("mean_rev_btc", {}), status.get("mean_rev_btc", False))
lines += [f"// rsi_cross_xau: {'PASS' if status.get('rsi_cross_xau') else 'DISABLED'}"]
lines += emit_rsi_cross(params_map.get("rsi_cross_xau", {}), status.get("rsi_cross_xau", False))
for sid, fn in [
("rsi_asian_eur", "RsiAsianEur"),
("rsi_asian_aud", "RsiAsianAud"),
("rsi_asian_gbp", "RsiAsianGbp"),
]:
lines += [f"// {sid}: {'PASS' if status.get(sid) else 'DISABLED'}"]
lines += emit_rsi_asian(fn, params_map.get(sid, {}), status.get(sid, False))
lines += [f"// rsi_secret_xau: {'PASS' if status.get('rsi_secret_xau') else 'DISABLED'}"]
lines += emit_rsi_secret(params_map.get("rsi_secret_xau", {}), status.get("rsi_secret_xau", False))
for sid in RSI_SCALP_IDS:
idx = RSI_INDEX[sid]
lines += [f"// {sid}: {'PASS' if status.get(sid) else 'DISABLED'}"]
lines += emit_rsi_scalp(idx, sid, params_map.get(sid, {}), status.get(sid, False))
lines += ["#endif", ""]
OUT_MQH.parent.mkdir(parents=True, exist_ok=True)
OUT_MQH.write_text("\n".join(lines), encoding="utf-8")
OUT_JSON.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
passed = [k for k, v in status.items() if v]
print(f"Wrote {OUT_MQH}")
print(f"Wrote {OUT_JSON}")
print(f"Passed {len(passed)}/{len(STRATEGIES)}: {', '.join(passed) if passed else '(none)'}")
if __name__ == "__main__":
main()