Files
Apex_AI_MT5_EA_Optimizer/demo/run_demo.py
T
LEGSTECH Optimizer 6caafdb794 feat: open-source release — AI-driven autonomous optimization with live visibility
Major upgrade making the AI loop visible and the project ready for public release.

UI / UX
- Live AI Thinking Feed: streams reasoning, decisions, and outcomes per iteration
- Parameter Changes panel: prev → new + reason for every AI-driven edit
- Validation Activity panel: out-of-sample + sensitivity runs with live metrics
- Early Termination banner: surfaces why optimization stopped (targets met, no profit, budget, stuck, user stop)
- 3-phase tracker renamed Exploration / Iteration / Validation with live N/total
- Best Result modal exposes Evolution Path showing how the AI arrived at the winner
- Run-detail modal accessible from every recent run row
- Setup form validation (dates, walk-forward order, params selection, AI targets)
- Pause button removed; misleading sidebar nav consolidated to Dashboard / New Run / Reports / Source

Backend
- AIGuidedLoop streams ai_thinking, param_changes, ai_targets_met, ai_stuck
- Pipeline emits validation_start / validation_run_start / validation_run_complete / validation_done
- Pipeline emits early_termination on every early-stop path
- /api/best_result returns best run + full evolution chain
- /api/run/<id> + /api/runs sorted by ts
- AIReasoner falls back to ANTHROPIC_API_KEY env var when config is a placeholder
- Demo mode (APEX_DEMO_MODE=1) generates deterministic synthetic backtests so judges can run end-to-end without MT5

Open-source readiness
- README.md with pitch, demo flow, architecture diagram, quickstart, event reference
- LICENSE (MIT)
- config.example.yaml template (config.yaml now git-ignored)
- requirements.txt: added anthropic / requests / psutil / beautifulsoup4, capped majors
- .gitignore: secrets, *.set, scratch screenshots, ea_registry.yaml
- demo/run_demo.py: one-command offline demo runner
- 10 polished screenshots for README + judge review
2026-04-25 11:39:17 +00:00

143 lines
4.2 KiB
Python

"""
demo/run_demo.py
APEX offline demo runner.
Spins up the Flask + SocketIO app with APEX_DEMO_MODE=1 so the optimizer
generates synthetic backtest results instead of calling MT5. Lets judges
without a Windows + MT5 install see the full live AI loop, validation,
and verdict flow.
Usage:
python -m demo.run_demo
# or
python demo/run_demo.py
"""
from __future__ import annotations
import os
import sys
import textwrap
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parent.parent
DEMO_DIR = Path(__file__).resolve().parent
DEMO_SET = DEMO_DIR / "demo_ea.set"
REGISTRY = ROOT / "ea_registry.yaml"
CONFIG = ROOT / "config.yaml"
EXAMPLE_CONFIG = ROOT / "config.example.yaml"
DEMO_PROFILE = {
"name": "APEX_DEMO_EA",
"ex5_file": "APEX_DEMO_EA",
"set_template": str(DEMO_SET).replace("\\", "/"),
"symbol": "XAUUSD",
"timeframe": "H1",
"mode": "advanced",
"registered_at": "2026-01-01T00:00:00+00:00",
"optimize_params": {
"InpRiskPercent": True,
"InpMaxDailyLossPct": True,
"InpRRRatio": True,
"InpStopLossPips": True,
"InpTakeProfitPips": True,
"InpATRMultiplier": True,
"InpUseTrailing": True,
"InpTrailStartPips": True,
"InpUseBreakeven": True,
"InpBEPips": True,
"InpMinScore": True,
},
"automation_overrides": {},
}
def ensure_demo_registry() -> None:
"""Make sure the demo EA profile exists in ea_registry.yaml."""
if REGISTRY.exists():
try:
data = yaml.safe_load(REGISTRY.read_text()) or {"profiles": []}
except Exception:
data = {"profiles": []}
else:
data = {"profiles": []}
profiles = data.get("profiles") or []
if not any(p.get("name") == DEMO_PROFILE["name"] for p in profiles):
profiles.append(DEMO_PROFILE)
data["profiles"] = profiles
REGISTRY.write_text(yaml.safe_dump(data, sort_keys=False))
print(f" [ok] Registered demo EA in {REGISTRY.name}")
else:
print(f" [ok] Demo EA already in {REGISTRY.name}")
def ensure_config() -> None:
"""If config.yaml is missing, copy config.example.yaml as a starting point."""
if not CONFIG.exists():
if EXAMPLE_CONFIG.exists():
CONFIG.write_text(EXAMPLE_CONFIG.read_text())
print(f" [ok] Created {CONFIG.name} from template")
else:
print(f" [!] No config.yaml or config.example.yaml — app may fail to start")
def banner() -> None:
bar = "=" * 72
print(textwrap.dedent(f"""
{bar}
APEX -- DEMO MODE (offline / no MT5)
{bar}
* Backtests are synthetic (deterministic from params + jitter)
* The AI loop, validation, and verdict flow are 100% real
* Set ANTHROPIC_API_KEY to see live AI reasoning
Open http://localhost:5000 in your browser, hit "New Run", and
watch the AI think.
{bar}
"""))
def main() -> int:
banner()
print("Bootstrapping demo environment...")
ensure_config()
ensure_demo_registry()
# Set the demo flag — the pipeline checks this in _execute_run.
os.environ["APEX_DEMO_MODE"] = "1"
# Per-run latency tunable — keep small so demo feels snappy.
os.environ.setdefault("APEX_DEMO_RUN_SECONDS", "1.2")
if "ANTHROPIC_API_KEY" not in os.environ:
print(" [!] ANTHROPIC_API_KEY not set — AI reasoning will be skipped (synthetic metrics still flow).")
print()
print("Launching APEX server at http://localhost:5000 ...")
sys.path.insert(0, str(ROOT))
# Import after env vars are set so the pipeline picks them up.
import threading
import webbrowser
from app import app as flask_app, socketio
def _open_browser():
import time as _t
_t.sleep(1.5)
try:
webbrowser.open("http://localhost:5000")
except Exception:
pass
threading.Thread(target=_open_browser, daemon=True).start()
socketio.run(
flask_app, host="0.0.0.0", port=5000,
debug=False, use_reloader=False, allow_unsafe_werkzeug=True,
)
return 0
if __name__ == "__main__":
sys.exit(main())